diff -Nru fwupd-1.4.5/.circleci/config.yml fwupd-1.5.8/.circleci/config.yml --- fwupd-1.4.5/.circleci/config.yml 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/.circleci/config.yml 2021-03-31 20:08:32.000000000 +0000 @@ -1,17 +1,5 @@ version: 2 jobs: - check-abi: - machine: - image: circleci/classic:latest - steps: - - checkout - - run: - name: "Build container" - command: OS=debian-x86_64 ./contrib/ci/generate_docker.py - - run: - name: "Run build script" - command: docker run -t -v `pwd`:/build fwupd-debian-x86_64 ./contrib/ci/check-abi $(git describe --abbrev=0 --tags) $(git rev-parse HEAD) - build-ubuntu-x86_64: machine: image: circleci/classic:latest @@ -19,30 +7,18 @@ - checkout - run: name: "Build container" - command: OS=ubuntu-x86_64 ./contrib/ci/generate_docker.py + command: OS=ubuntu-x86_64 ./contrib/ci/generate_docker.py build - run: name: "Run build script" - command: docker run --privileged -e CI=true -t -v `pwd`/dist:/build/dist fwupd-ubuntu-x86_64 + command: docker run --privileged -e CI=true -t -v `pwd`:/github/workspace fwupd-ubuntu-x86_64 - persist_to_workspace: root: . paths: - "dist/docs" - build-chromeos-x86_64: - machine: - image: circleci/classic:latest - steps: - - checkout - - run: - name: "Build container" - command: OS=debian-x86_64 ./contrib/ci/generate_docker.py - - run: - name: "Run build script" - command: docker run --privileged -e CI=true -t -v `pwd`/dist:/build/dist fwupd-debian-x86_64 ./contrib/ci/trust.sh - build-windows: docker: - - image: fedora:31 + - image: fedora:latest steps: - run: name: "Install deps" @@ -56,14 +32,16 @@ gcc gcab mingw32-nsis + mingw64-brotli mingw64-gcc mingw64-pkg-config mingw64-glib2 + mingw64-gnutls mingw64-libgusb mingw64-sqlite mingw64-libarchive mingw64-json-glib - mingw64-libsoup + mingw64-curl wine - checkout - run: @@ -167,7 +145,7 @@ go get github.com/tcnksm/ghr VERSION=$(cat dist/VERSION) BODY=$(cat dist/news.txt) - ghr -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} -b ${BODY} ${VERSION} ./dist/setup/ + ghr -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} -b "${BODY}" ${VERSION} ./dist/setup/ workflows: version: 2 main: @@ -175,8 +153,6 @@ - build-windows - build-ubuntu-x86_64 - build-snap - - check-abi - - build-chromeos-x86_64 - publish-edge: requires: - build-snap diff -Nru fwupd-1.4.5/contrib/afl-fuzz.py fwupd-1.5.8/contrib/afl-fuzz.py --- fwupd-1.4.5/contrib/afl-fuzz.py 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/contrib/afl-fuzz.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,78 +0,0 @@ -#!/usr/bin/python3 -# SPDX-License-Identifier: LGPL-2.1+ - -import argparse -import sys -import subprocess -import os - - -def main(): - parser = argparse.ArgumentParser(description='Run afl-fuzz on all cores') - parser.add_argument('--input', '-i', help='fuzzing input directory') - parser.add_argument('--output', '-o', help='findings output directory') - parser.add_argument('--command', type=str, help='fuzzer tool command') - parser.add_argument('path', type=str, help='the fuzzer tool') - args = parser.parse_args() - if not args.input and not args.output: - print('-i and -o required') - return 1 - if not args.path: - print('tool name required') - return 1 - - # create if not already exists - if not os.path.exists(args.output): - os.makedirs(args.output) - - # run the main instance - envp = None - argv = [ - 'afl-fuzz', - '-m300', - '-i', - args.input, - '-o', - args.output, - '-M', - 'fuzzer00', - args.path, - ] - if args.command: - argv.append(args.command) - argv.append('@@') - print(argv) - p = subprocess.Popen(argv, env=envp) - - # run the secondary instances - cs = [] - for i in range(1, os.cpu_count()): - argv = [ - 'afl-fuzz', - '-m300', - '-i', - args.input, - '-o', - args.output, - '-S', - 'fuzzer%02i' % i, - args.path, - ] - if args.command: - argv.append(args.command) - argv.append('@@') - print(argv) - cs.append(subprocess.Popen(argv, env=envp, stdout=subprocess.DEVNULL)) - - # wait for the main instance - try: - p.wait() - except KeyboardInterrupt as _: - pass - for c in cs: - c.terminate() - return 0 - - -if __name__ == '__main__': - sys.exit(main()) diff -Nru fwupd-1.4.5/contrib/ci/abidiff.suppr fwupd-1.5.8/contrib/ci/abidiff.suppr --- fwupd-1.4.5/contrib/ci/abidiff.suppr 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/contrib/ci/abidiff.suppr 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,3 @@ [suppress_type] type_kind = enum - changed_enumerators = FWUPD_ERROR_LAST,FWUPD_GUID_FLAG_LAST,FWUPD_INSTALL_FLAG_LAST,FWUPD_KEYRING_KIND_LAST,FWUPD_REMOTE_KIND_LAST,FWUPD_SELF_SIGN_FLAG_LAST,FWUPD_STATUS_LAST,FWUPD_TRUST_FLAG_LAST,FWUPD_UPDATE_STATE_LAST,FWUPD_VERSION_FORMAT_LAST + changed_enumerators = FWUPD_ERROR_LAST,FWUPD_GUID_FLAG_LAST,FWUPD_INSTALL_FLAG_LAST,FWUPD_KEYRING_KIND_LAST,FWUPD_REMOTE_KIND_LAST,FWUPD_SELF_SIGN_FLAG_LAST,FWUPD_STATUS_LAST,FWUPD_TRUST_FLAG_LAST,FWUPD_UPDATE_STATE_LAST,FWUPD_VERSION_FORMAT_LAST,FWUPD_CLIENT_DOWNLOAD_FLAG_LAST diff -Nru fwupd-1.4.5/contrib/ci/arch.sh fwupd-1.5.8/contrib/ci/arch.sh --- fwupd-1.4.5/contrib/ci/arch.sh 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/contrib/ci/arch.sh 2021-03-31 20:08:32.000000000 +0000 @@ -3,6 +3,15 @@ set -x shopt -s extglob +#clone test firmware +if [ "$CI_NETWORK" = "true" ]; then + ./contrib/ci/get_test_firmware.sh + export G_TEST_SRCDIR=`pwd`/fwupd-test-firmware/installed-tests +fi + +#install anything missing from the container +./contrib/ci/generate_dependencies.py | xargs pacman -S --noconfirm --needed + # prepare the build tree rm -rf build mkdir build && pushd build @@ -12,9 +21,9 @@ popd chown nobody . -R -# install and run TPM simulator necessary for plugins/uefi/uefi-self-test -pacman -S --noconfirm ibm-sw-tpm2 tpm2-tools -tpm_server & +# install and run TPM simulator necessary for plugins/uefi-capsule/uefi-self-test +pacman -Syu --noconfirm swtpm tpm2-tools +swtpm socket --tpm2 --server port=2321 --ctrl type=tcp,port=2322 --flags not-need-init --tpmstate "dir=$PWD" & trap "kill $!" EXIT # extend a PCR0 value for test suite sleep 2 @@ -26,6 +35,15 @@ sudo -E -u nobody PKGEXT='.pkg.tar' makepkg -e --noconfirm pacman -U --noconfirm *.pkg.* +#run the CI tests for Qt5 +pacman -Syu --noconfirm qt5-base +meson qt5-thread-test ../contrib/ci/qt5-thread-test +ninja -C qt5-thread-test test + +#run the CI tests for making sure we can link fwupd/fwupdplugin +meson out-of-tree-link ../contrib/ci/out-of-tree-link +ninja -C out-of-tree-link test + # move the package to working dir mv *.pkg.* ../dist diff -Nru fwupd-1.4.5/contrib/ci/build_windows.sh fwupd-1.5.8/contrib/ci/build_windows.sh --- fwupd-1.4.5/contrib/ci/build_windows.sh 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/contrib/ci/build_windows.sh 2021-03-31 20:08:32.000000000 +0000 @@ -15,21 +15,24 @@ --libexecdir=$target \ --bindir=$target \ -Dbuild=standalone \ - -Dplugin_coreboot=false \ + -Dpolkit=false \ -Dplugin_flashrom=false \ - -Dplugin_uefi=false \ + -Dplugin_uefi_capsule=false \ -Dplugin_redfish=false \ -Dplugin_altos=false \ -Dplugin_dell=false \ -Dplugin_nvme=false \ + -Dplugin_platform_integrity=false \ -Dplugin_tpm=false \ -Dsystemd=false \ -Dplugin_emmc=false \ -Dplugin_amt=false \ -Dintrospection=false \ -Dplugin_thunderbolt=false \ - -Dplugin_synaptics=false \ + -Dplugin_synaptics_mst=false \ + -Dplugin_synaptics_rmi=false \ -Dman=false \ + -Dsoup_session_compat=false \ -Dgcab:introspection=false \ -Dgcab:docs=false \ -Dgcab:nls=false \ @@ -40,6 +43,11 @@ -Dlibjcat:man=false \ -Dlibjcat:gpg=false \ -Dlibjcat:introspection=false \ + -Dgusb:tests=false \ + -Dgusb:docs=false \ + -Dgusb:introspection=false \ + -Dgusb:vapi=false \ + -Dbluez=false \ -Dgudev=false $@ VERSION=$(meson introspect . --projectinfo | jq -r .version) ninja -v diff -Nru fwupd-1.4.5/contrib/ci/centos.sh fwupd-1.5.8/contrib/ci/centos.sh --- fwupd-1.4.5/contrib/ci/centos.sh 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/contrib/ci/centos.sh 2021-03-31 20:08:32.000000000 +0000 @@ -2,15 +2,22 @@ set -e set -x +#clone test firmware +if [ "$CI_NETWORK" = "true" ]; then + ./contrib/ci/get_test_firmware.sh + export G_TEST_SRCDIR=`pwd`/fwupd-test-firmware/installed-tests +fi + +#build rm -rf build mkdir -p build cd build meson .. \ --werror \ - -Dplugin_uefi=false \ + -Dplugin_uefi_capsule=false \ -Dplugin_dell=false \ -Dplugin_modem_manager=false \ - -Dplugin_synaptics=true \ + -Dplugin_synaptics_mst=true \ -Dplugin_flashrom=true \ -Dintrospection=true \ -Dgtkdoc=true \ diff -Nru fwupd-1.4.5/contrib/ci/check-null-false-returns.py fwupd-1.5.8/contrib/ci/check-null-false-returns.py --- fwupd-1.4.5/contrib/ci/check-null-false-returns.py 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/ci/check-null-false-returns.py 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,238 @@ +#!/usr/bin/python3 +# pylint: disable=invalid-name,missing-docstring,too-many-branches +# pylint: disable=too-many-statements,too-many-return-statements,too-few-public-methods +# +# Copyright (C) 2021 Richard Hughes +# +# SPDX-License-Identifier: LGPL-2.1+ + +import glob +import sys +from typing import List + + +def _tokenize(line: str) -> List[str]: + + # remove whitespace + line = line.strip() + line = line.replace("\t", "") + line = line.replace(";", "") + + # find value + line = line.replace(" ", "|") + line = line.replace(",", "|") + line = line.replace(")", "|") + line = line.replace("(", "|") + + # return empty tokens + tokens = [] + for token in line.rsplit("|"): + if token: + tokens.append(token) + return tokens + + +class ReturnValidator: + def __init__(self): + self.warnings: List[str] = [] + + # internal state + self._fn = None + self._line_num = None + self._value = None + self._nret = None + self._rvif = None + self._line = None + + @property + def _tokens(self) -> List[str]: + return _tokenize(self._line) + + @property + def _value_relaxed(self) -> str: + if self._value in ["0x0", "0x00", "0x0000"]: + return "0" + if self._value in ["0xffffffff"]: + return "G_MAXUINT32" + if self._value in ["0xffff"]: + return "G_MAXUINT16" + if self._value in ["0xff"]: + return "G_MAXUINT8" + if self._value in ["G_SOURCE_REMOVE"]: + return "FALSE" + if self._value in ["G_SOURCE_CONTINUE"]: + return "TRUE" + return self._value + + def _test_rvif(self) -> None: + + # parse "g_return_val_if_fail (SOMETHING (foo), NULL);" + self._value = self._tokens[-1] + + # enumerated enum, so ignore + if self._value.find("_") != -1: + return + + # is invalid + if self._rvif and self._value_relaxed not in self._rvif: + self.warnings.append( + "{} line {} got {}, expected {}".format( + self._fn, self._line_num, self._value, ", ".join(self._rvif) + ) + ) + + def _test_return(self) -> None: + + # parse "return 0x0;" + self._value = self._tokens[-1] + + # is invalid + if self._nret and self._value_relaxed in self._nret: + self.warnings.append( + "{} line {} got {}, which is not valid".format( + self._fn, self._line_num, self._value + ) + ) + + def parse(self, fn: str) -> None: + + self._fn = fn + with open(fn) as f: + self._rvif = None + self._nret = None + self._line_num = 0 + for line in f.readlines(): + self._line_num += 1 + line = line.rstrip() + if not line: + continue + if line.endswith("\\"): + continue + if line.endswith("&&"): + continue + self._line = line + idx = line.find("g_return_val_if_fail") + if idx != -1: + self._test_rvif() + continue + idx = line.find("return") + if idx != -1: + # continue + if len(self._tokens) == 2: + self._test_return() + continue + + # not a function header + if line[0] in ["#", " ", "\t", "{", "}", "/"]: + continue + + # label + if line.endswith(":"): + continue + + # remove prefixes + if line.startswith("static"): + line = line[7:] + if line.startswith("inline"): + line = line[7:] + + # a pointer + if line.endswith("*"): + self._rvif = ["NULL"] + self._nret = ["FALSE"] + continue + + # not a leading line + if line.find(" ") != -1: + continue + + # a type we know + if line in ["void"]: + self._rvif = [] + self._nret = [] + continue + if line in ["gpointer"]: + self._rvif = ["NULL"] + self._nret = ["FALSE"] + continue + if line in ["gboolean"]: + self._rvif = ["TRUE", "FALSE"] + self._nret = ["NULL", "0"] + continue + if line in ["guint32"]: + self._rvif = ["0", "G_MAXUINT32"] + self._nret = ["NULL", "TRUE", "FALSE"] + continue + if line in ["GQuark", "GType"]: + self._rvif = ["0"] + self._nret = ["NULL", "0", "TRUE", "FALSE"] + continue + if line in ["guint64"]: + self._rvif = ["0", "G_MAXUINT64"] + self._nret = ["NULL", "TRUE", "FALSE"] + continue + if line in ["guint16"]: + self._rvif = ["0", "G_MAXUINT16"] + self._nret = ["NULL", "TRUE", "FALSE"] + continue + if line in ["guint8"]: + self._rvif = ["0", "G_MAXUINT8"] + self._nret = ["NULL", "TRUE", "FALSE"] + continue + if line in ["gint64"]: + self._rvif = ["0", "-1", "G_MAXINT64"] + self._nret = ["NULL", "TRUE", "FALSE"] + continue + if line in ["gint32"]: + self._rvif = ["0", "-1", "G_MAXINT32"] + self._nret = ["NULL", "TRUE", "FALSE"] + continue + if line in ["gint16"]: + self._rvif = ["0", "-1", "G_MAXINT16"] + self._nret = ["NULL", "TRUE", "FALSE"] + continue + if line in ["gint8"]: + self._rvif = ["0", "-1", "G_MAXINT8"] + self._nret = ["NULL", "TRUE", "FALSE"] + continue + if line in ["gint", "int"]: + self._rvif = ["0", "-1", "G_MAXINT"] + self._nret = ["NULL", "TRUE", "FALSE"] + continue + if line in ["guint"]: + self._rvif = ["0", "G_MAXUINT"] + self._nret = ["NULL", "TRUE", "FALSE"] + continue + if line in ["gulong"]: + self._rvif = ["0", "G_MAXLONG"] + self._nret = ["NULL", "TRUE", "FALSE"] + continue + if line in ["gsize", "size_t"]: + self._rvif = ["0", "G_MAXSIZE"] + self._nret = ["NULL", "TRUE", "FALSE"] + continue + if line in ["gssize", "ssize_t"]: + self._rvif = ["0", "-1", "G_MAXSSIZE"] + self._nret = ["NULL", "TRUE", "FALSE"] + continue + # print('unknown return type {}'.format(line)) + self._rvif = None + self._nret = None + + +def test_files(): + + # test all C source files + validator = ReturnValidator() + for fn in glob.glob("**/*.c", recursive=True): + validator.parse(fn) + for warning in validator.warnings: + print(warning) + + return 1 if validator.warnings else 0 + + +if __name__ == "__main__": + + # all done! + sys.exit(test_files()) diff -Nru fwupd-1.4.5/contrib/ci/debian_s390x.sh fwupd-1.5.8/contrib/ci/debian_s390x.sh --- fwupd-1.4.5/contrib/ci/debian_s390x.sh 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/contrib/ci/debian_s390x.sh 2021-03-31 20:08:32.000000000 +0000 @@ -17,9 +17,10 @@ --cross-file s390x_cross.txt \ --werror \ -Dplugin_flashrom=false \ - -Dplugin_uefi=false \ + -Dplugin_uefi_capsule=false \ -Dplugin_dell=false \ -Dplugin_modem_manager=false \ + -Dplugin_msr=false \ -Dplugin_redfish=false \ -Dintrospection=false \ -Dgtkdoc=false \ diff -Nru fwupd-1.4.5/contrib/ci/debian.sh fwupd-1.5.8/contrib/ci/debian.sh --- fwupd-1.4.5/contrib/ci/debian.sh 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/contrib/ci/debian.sh 2021-03-31 20:08:32.000000000 +0000 @@ -2,12 +2,22 @@ set -e set -x +export QUBES_OPTION= + +# remove when tpm2-tss is fixed +mkdir -p /usr/include/tss + #although it's debian, we don't build packages if [ "$OS" = "debian-s390x" ]; then ./contrib/ci/debian_s390x.sh exit 0 fi +# Set Qubes Os vars if -Dqubes=true is parameter +if [ "$QUBES" = "true" ]; then + export QUBES_OPTION='-Dqubes=true' +fi + #prepare export DEBFULLNAME="CI Builder" export DEBEMAIL="ci@travis-ci.org" @@ -23,13 +33,29 @@ #generate control file ./contrib/ci/generate_debian.py +#check if we have all deps available +#if some are missing, we're going to use subproject instead and +#packaging CI will fail +./contrib/ci/generate_dependencies.py | xargs apt install -y || true +if ! dpkg-checkbuilddeps; then + ./contrib/ci/ubuntu.sh + exit 0 +fi + +#clone test firmware +if [ "$CI_NETWORK" = "true" ]; then + ./contrib/ci/get_test_firmware.sh + export G_TEST_SRCDIR=`pwd`/fwupd-test-firmware/installed-tests +fi + #disable unit tests if fwupd is already installed (may cause problems) if [ -x /usr/lib/fwupd/fwupd ]; then export DEB_BUILD_OPTIONS=nocheck fi #build the package EDITOR=/bin/true dch --create --package fwupd -v $VERSION "CI Build" -debuild --no-lintian --preserve-envvar CI --preserve-envvar CC +debuild --no-lintian --preserve-envvar CI --preserve-envvar CC \ + --preserve-envvar QUBES_OPTION #check lintian output #suppress tags that are side effects of building in docker this way diff -Nru fwupd-1.4.5/contrib/ci/dependencies.xml fwupd-1.5.8/contrib/ci/dependencies.xml --- fwupd-1.4.5/contrib/ci/dependencies.xml 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/contrib/ci/dependencies.xml 2021-03-31 20:08:32.000000000 +0000 @@ -6,7 +6,7 @@ - + @@ -66,12 +66,12 @@ - + - + @@ -766,7 +766,7 @@ - (>= 0.2.9) + (>= 0.3.5) libgusb-dev:s390x @@ -774,7 +774,7 @@ - (>= 0.2.9) + (>= 0.3.3) @@ -818,19 +818,25 @@ + + + + + + - libsoup + curl - libsoup-devel + libcurl-devel - libsoup-devel + libcurl-devel - libsoup2.4-dev:s390x + libcurl4-gnutls-dev:s390x @@ -1179,6 +1185,24 @@ + + + systemd-devel + + + systemd-devel + + + + + libsystemd-dev:s390x + + + + + + + diff -Nru fwupd-1.4.5/contrib/ci/Dockerfile-arch.in fwupd-1.5.8/contrib/ci/Dockerfile-arch.in --- fwupd-1.4.5/contrib/ci/Dockerfile-arch.in 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/contrib/ci/Dockerfile-arch.in 2021-03-31 20:08:32.000000000 +0000 @@ -2,12 +2,11 @@ %%%OS%%% ENV LANG en_US.UTF-8 ENV LC_ALL en_US.UTF-8 +ENV CI_NETWORK true RUN echo fubar > /etc/machine-id RUN rm /usr/share/libalpm/hooks/package-cleanup.hook RUN echo fubar > /etc/machine-id RUN pacman -Syu --noconfirm archlinux-keyring %%%INSTALL_DEPENDENCIES_COMMAND%%% -RUN mkdir /build -WORKDIR /build -COPY . . +WORKDIR /github/workspace CMD ["./contrib/ci/arch.sh"] diff -Nru fwupd-1.4.5/contrib/ci/Dockerfile-centos.in fwupd-1.5.8/contrib/ci/Dockerfile-centos.in --- fwupd-1.4.5/contrib/ci/Dockerfile-centos.in 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/contrib/ci/Dockerfile-centos.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -FROM centos:7 -%%%OS%%% -ENV LANG en_US.UTF-8 -ENV LANGUAGE en_US:en -ENV LC_ALL en_US.UTF-8 -RUN echo fubar > /etc/machine-id -RUN yum install epel-release -y -RUN echo fubar > /etc/machine-id -%%%INSTALL_DEPENDENCIES_COMMAND%%% -RUN pip3 install pillow pygobject -RUN wget https://copr.fedorainfracloud.org/coprs/jsynacek/systemd-backports-for-centos-7/repo/epel-7/jsynacek-systemd-backports-for-centos-7-epel-7.repo -O /etc/yum.repos.d/jsynacek-systemd-centos-7.repo -RUN yum --enablerepo=epel-testing -y update -RUN mkdir /build -WORKDIR /build -COPY . . -CMD ["./contrib/ci/centos.sh"] diff -Nru fwupd-1.4.5/contrib/ci/Dockerfile-debian.in fwupd-1.5.8/contrib/ci/Dockerfile-debian.in --- fwupd-1.4.5/contrib/ci/Dockerfile-debian.in 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/contrib/ci/Dockerfile-debian.in 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,6 @@ FROM %%%ARCH_PREFIX%%%debian:testing %%%OS%%% +ENV CI_NETWORK true RUN echo "deb http://ftp.us.debian.org/debian unstable main contrib non-free" >> /etc/apt/sources.list RUN echo 'Package: *\n\ Pin: release a=testing\n\ @@ -21,7 +22,5 @@ RUN echo fubar > /etc/machine-id %%%ARCH_SPECIFIC_COMMAND%%% %%%INSTALL_DEPENDENCIES_COMMAND%%% -RUN mkdir /build -WORKDIR /build -COPY . . +WORKDIR /github/workspace CMD ["./contrib/ci/debian.sh"] diff -Nru fwupd-1.4.5/contrib/ci/Dockerfile-fedora.in fwupd-1.5.8/contrib/ci/Dockerfile-fedora.in --- fwupd-1.4.5/contrib/ci/Dockerfile-fedora.in 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/contrib/ci/Dockerfile-fedora.in 2021-03-31 20:08:32.000000000 +0000 @@ -1,4 +1,4 @@ -FROM fedora:31 +FROM fedora:32 %%%OS%%% ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en @@ -7,8 +7,5 @@ RUN dnf -y update RUN echo fubar > /etc/machine-id %%%INSTALL_DEPENDENCIES_COMMAND%%% -RUN dnf -y update glib2 glib2-devel --releasever=32 -RUN mkdir /build -WORKDIR /build -COPY . . +WORKDIR /github/workspace CMD ["./contrib/ci/fedora.sh"] diff -Nru fwupd-1.4.5/contrib/ci/Dockerfile-flatpak.in fwupd-1.5.8/contrib/ci/Dockerfile-flatpak.in --- fwupd-1.4.5/contrib/ci/Dockerfile-flatpak.in 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/contrib/ci/Dockerfile-flatpak.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -FROM fedora:29 -%%%OS%%% -ENV LANG en_US.UTF-8 -ENV LANGUAGE en_US:en -ENV LC_ALL en_US.UTF-8 -RUN echo fubar > /etc/machine-id -%%%INSTALL_DEPENDENCIES_COMMAND%%% -RUN dnf --enablerepo=updates-testing -y update -RUN mkdir /build -WORKDIR /build -COPY . . -CMD ["./contrib/ci/flatpak.py"] diff -Nru fwupd-1.4.5/contrib/ci/Dockerfile-ubuntu.in fwupd-1.5.8/contrib/ci/Dockerfile-ubuntu.in --- fwupd-1.4.5/contrib/ci/Dockerfile-ubuntu.in 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/contrib/ci/Dockerfile-ubuntu.in 2021-03-31 20:08:32.000000000 +0000 @@ -1,10 +1,9 @@ FROM ubuntu:devel %%%OS%%% -ENV CC clang-6.0 +ENV CI_NETWORK true +ENV CC clang RUN echo fubar > /etc/machine-id %%%ARCH_SPECIFIC_COMMAND%%% %%%INSTALL_DEPENDENCIES_COMMAND%%% -RUN mkdir /build -WORKDIR /build -COPY . . +WORKDIR /github/workspace CMD ["./contrib/ci/ubuntu.sh"] diff -Nru fwupd-1.4.5/contrib/ci/fedora.sh fwupd-1.5.8/contrib/ci/fedora.sh --- fwupd-1.4.5/contrib/ci/fedora.sh 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/contrib/ci/fedora.sh 2021-03-31 20:08:32.000000000 +0000 @@ -2,21 +2,54 @@ set -e set -x +# check for g_return_val_if_fail sanity +if ! ./contrib/ci/check-null-false-returns.py; then + exit 1 +fi + +# these are deprecated in favor of INTERNAL flags +deprecated="FWUPD_DEVICE_FLAG_NO_AUTO_INSTANCE_IDS + FWUPD_DEVICE_FLAG_ONLY_SUPPORTED + FWUPD_DEVICE_FLAG_MD_SET_NAME + FWUPD_DEVICE_FLAG_MD_SET_VERFMT + FWUPD_DEVICE_FLAG_NO_GUID_MATCHING + FWUPD_DEVICE_FLAG_MD_SET_ICON" +for val in $deprecated; do + if grep -- $val plugins/*/*.c ; then + exit 1 + fi +done + +# check shell scripts +dnf install -y ShellCheck +if ! find . -name '*.sh' | xargs shellcheck --severity=error -e SC2068; then + exit 1 +fi + +#get any missing deps from the container +./contrib/ci/generate_dependencies.py | xargs dnf install -y + #generate a tarball git config tar.tar.xz.command "xz -c" mkdir -p build && pushd build rm -rf * + +if [ "$QUBES" = "true" ]; then + QUBES_MACRO=(--define "qubes_packages 1") +fi + meson .. \ -Dgtkdoc=true \ -Dman=true \ -Dtests=true \ + -Dgusb:tests=false \ -Dplugin_dummy=true \ -Dplugin_flashrom=true \ -Dplugin_modem_manager=false \ -Dplugin_thunderbolt=true \ - -Dplugin_uefi=true \ + -Dplugin_uefi_capsule=true \ -Dplugin_dell=true \ - -Dplugin_synaptics=true $@ + -Dplugin_synaptics_mst=true $@ ninja-build dist popd VERSION=`meson introspect build --projectinfo | jq -r .version` @@ -38,7 +71,7 @@ fi #build RPM packages -rpmbuild -ba build/fwupd.spec +rpmbuild -ba "${QUBES_MACRO[@]}" build/fwupd.spec #if invoked outside of CI if [ ! -f /.dockerenv ]; then @@ -53,7 +86,7 @@ cp $HOME/rpmbuild/RPMS/*/*.rpm dist if [ "$CI" = "true" ]; then - sed "s,^BlacklistPlugins=test;invalid,BlacklistPlugins=," -i /etc/fwupd/daemon.conf + sed "s,^DisabledPlugins=.*,DisabledPlugins=," -i /etc/fwupd/daemon.conf # set up enough PolicyKit and D-Bus to run the daemon mkdir -p /run/dbus diff -Nru fwupd-1.4.5/contrib/ci/generate_debian.py fwupd-1.5.8/contrib/ci/generate_debian.py --- fwupd-1.4.5/contrib/ci/generate_debian.py 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/contrib/ci/generate_debian.py 2021-03-31 20:08:32.000000000 +0000 @@ -11,6 +11,7 @@ def parse_control_dependencies(requested_type): TARGET = os.getenv('OS') + QUBES = os.getenv('QUBES') deps = [] dep = '' @@ -81,7 +82,7 @@ suffix = "]" dep = "%s%s%s%s" % (dep, prefix, exclusions[i].text, suffix) deps.append(dep) - return deps + return deps, QUBES def update_debian_control(target): @@ -95,14 +96,23 @@ with open(control_in, 'r') as rfd: lines = rfd.readlines() - deps = parse_control_dependencies("build") + deps, QUBES = parse_control_dependencies("build") deps.sort() + + if QUBES: + lines += '\n' + control_qubes_in = os.path.join(target, 'control.qubes.in') + with open(control_qubes_in, 'r') as rfd: + lines += rfd.readlines() + with open(control_out, 'w') as wfd: for line in lines: if line.startswith("Build-Depends: %%%DYNAMIC%%%"): wfd.write("Build-Depends:\n") for i in range(0, len(deps)): wfd.write("\t%s,\n" % deps[i]) + elif "fwupd-qubes-vm-whonix" in line and not QUBES: + break else: wfd.write(line) diff -Nru fwupd-1.4.5/contrib/ci/generate_dependencies.py fwupd-1.5.8/contrib/ci/generate_dependencies.py --- fwupd-1.4.5/contrib/ci/generate_dependencies.py 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/contrib/ci/generate_dependencies.py 2021-03-31 20:08:32.000000000 +0000 @@ -1,6 +1,6 @@ #!/usr/bin/python3 # -# Copyright (C) 2017-2018 Dell, Inc. +# Copyright (C) 2017 Dell, Inc. # Copyright (C) 2020 Intel, Inc. # # SPDX-License-Identifier: LGPL-2.1+ diff -Nru fwupd-1.4.5/contrib/ci/generate_docker.py fwupd-1.5.8/contrib/ci/generate_docker.py --- fwupd-1.4.5/contrib/ci/generate_docker.py 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/contrib/ci/generate_docker.py 2021-03-31 20:08:32.000000000 +0000 @@ -1,13 +1,12 @@ #!/usr/bin/python3 # -# Copyright (C) 2017-2018 Dell, Inc. +# Copyright (C) 2017 Dell, Inc. # # SPDX-License-Identifier: LGPL-2.1+ # import os import subprocess import sys -import tempfile import shutil from generate_dependencies import parse_dependencies @@ -44,8 +43,7 @@ with open(input, 'r') as rfd: lines = rfd.readlines() -out = tempfile.NamedTemporaryFile(dir='.', delete=True) -with open(out.name, 'w') as wfd: +with open('Dockerfile', 'w') as wfd: for line in lines: if line.startswith("FROM %%%ARCH_PREFIX%%%"): if (OS == "debian" or OS == "ubuntu") and SUBOS == "i386": @@ -83,11 +81,13 @@ else: wfd.write(line) wfd.flush() + +if len(sys.argv) == 2 and sys.argv[1] == 'build': cmd = get_container_cmd() args = [cmd, "build", "-t", "fwupd-%s" % TARGET] if 'http_proxy' in os.environ: args += ['--build-arg=http_proxy=%s' % os.environ['http_proxy']] if 'https_proxy' in os.environ: args += ['--build-arg=https_proxy=%s' % os.environ['https_proxy']] - args += ["-f", "./%s" % os.path.basename(out.name), "."] + args += ["-f", "./Dockerfile", "."] subprocess.check_call(args) diff -Nru fwupd-1.4.5/contrib/ci/get_test_firmware.sh fwupd-1.5.8/contrib/ci/get_test_firmware.sh --- fwupd-1.4.5/contrib/ci/get_test_firmware.sh 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/ci/get_test_firmware.sh 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,8 @@ +#!/bin/sh + +#clone fwupd-test-firmware +rm -rf fwupd-test-firmware +git clone https://github.com/fwupd/fwupd-test-firmware +#set up build tests to work +cp fwupd-test-firmware/ci-tests/* . -R +export G_TEST_SRCDIR=`pwd`/fwupd-test-firmware/installed-tests diff -Nru fwupd-1.4.5/contrib/ci/oss-fuzz.py fwupd-1.5.8/contrib/ci/oss-fuzz.py --- fwupd-1.4.5/contrib/ci/oss-fuzz.py 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/ci/oss-fuzz.py 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,336 @@ +#!/usr/bin/python3 +# pylint: disable=invalid-name,missing-docstring +# +# Copyright (C) 2021 Richard Hughes +# +# SPDX-License-Identifier: LGPL-2.1+ +# +# pylint: disable=too-many-instance-attributes,no-self-use + +import os +import sys +import subprocess +import glob +from typing import Dict, Optional, List, Union + +DEFAULT_BUILDDIR = ".ossfuzz" + + +class Builder: + def __init__(self) -> None: + + self.cc = self._ensure_environ("CC", "gcc") + self.cxx = self._ensure_environ("CXX", "g++") + self.builddir = self._ensure_environ("WORK", os.path.realpath(DEFAULT_BUILDDIR)) + self.installdir = self._ensure_environ( + "OUT", os.path.realpath(os.path.join(DEFAULT_BUILDDIR, "out")) + ) + self.srcdir = self._ensure_environ("SRC", os.path.realpath("..")) + self.ldflags = ["-lpthread", "-lresolv", "-ldl", "-lffi", "-lz"] + + # defined in env + self.cflags = ["-Wno-deprecated-declarations"] + if "CFLAGS" in os.environ: + self.cflags += os.environ["CFLAGS"].split(" ") + self.cxxflags = [] + if "CXXFLAGS" in os.environ: + self.cxxflags += os.environ["CXXFLAGS"].split(" ") + + # set up shared / static + os.environ["PKG_CONFIG"] = "pkg-config --static" + if "PATH" in os.environ: + os.environ["PATH"] = "{}:{}".format( + os.environ["PATH"], os.path.join(self.builddir, "bin") + ) + else: + os.environ["PATH"] = os.path.join(self.builddir, "bin") + os.environ["PKG_CONFIG_PATH"] = os.path.join(self.builddir, "lib", "pkgconfig") + + # writable + os.makedirs(self.builddir, exist_ok=True) + os.makedirs(self.installdir, exist_ok=True) + + def _ensure_environ(self, key: str, value: str) -> str: + """ set the environment unless already set """ + if key not in os.environ: + os.environ[key] = value + return os.environ[key] + + def checkout_source(self, name: str, url: str, commit: Optional[str] = None) -> str: + """ checkout source tree, optionally to a specific commit """ + srcdir_name = os.path.join(self.srcdir, name) + if os.path.exists(srcdir_name): + return srcdir_name + subprocess.run(["git", "clone", url], cwd=self.srcdir, check=True) + if commit: + subprocess.run(["git", "checkout", commit], cwd=srcdir_name, check=True) + return srcdir_name + + def build_meson_project(self, srcdir: str, argv) -> None: + """ configure and build the meson project """ + srcdir_build = os.path.join(srcdir, DEFAULT_BUILDDIR) + if not os.path.exists(srcdir_build): + subprocess.run( + [ + "meson", + "--prefix", + self.builddir, + "--libdir", + "lib", + "--default-library", + "static", + ] + + argv + + [DEFAULT_BUILDDIR], + cwd=srcdir, + check=True, + ) + subprocess.run(["ninja", "install"], cwd=srcdir_build, check=True) + + def add_work_includedir(self, value: str) -> None: + """ add a CFLAG """ + self.cflags.append("-I{}/{}".format(self.builddir, value)) + + def add_src_includedir(self, value: str) -> None: + """ add a CFLAG """ + self.cflags.append("-I{}/{}".format(self.srcdir, value)) + + def add_build_ldflag(self, value: str) -> None: + """ add a LDFLAG """ + self.ldflags.append(os.path.join(self.builddir, value)) + + def substitute(self, src: str, replacements: Dict[str, str]) -> str: + """ map changes """ + + dst = os.path.basename(src).replace(".in", "") + with open(os.path.join(self.srcdir, src), "r") as f: + blob = f.read() + for key in replacements: + blob = blob.replace(key, replacements[key]) + with open(os.path.join(self.builddir, dst), "w") as out: + out.write(blob) + return dst + + def compile(self, src: str) -> str: + """ compile a specific source file """ + argv = [self.cc] + argv.extend(self.cflags) + fullsrc = os.path.join(self.srcdir, src) + if not os.path.exists(fullsrc): + fullsrc = os.path.join(self.builddir, src) + dst = os.path.basename(src).replace(".c", ".o") + argv.extend( + [ + "-c", + fullsrc, + "-o", + os.path.join(self.builddir, dst), + ] + ) + print("building {} into {}".format(src, dst)) + try: + subprocess.run(argv, cwd=self.srcdir, check=True) + except subprocess.CalledProcessError as e: + print(e) + sys.exit(1) + return os.path.join(self.builddir, "{}".format(dst)) + + def link(self, objs: List[str], dst: str) -> None: + """ link multiple obects into a binary """ + argv = [self.cxx] + self.cxxflags + for obj in objs: + if obj.startswith("-"): + argv.append(obj) + else: + argv.append(os.path.join(self.builddir, obj)) + argv += ["-o", os.path.join(self.installdir, dst)] + argv += self.ldflags + print("building {} into {}".format(",".join(objs), dst)) + subprocess.run(argv, cwd=self.srcdir, check=True) + + def write_header( + self, dst: str, defines: Dict[str, Optional[Union[str, int]]] + ) -> None: + """ write a header file """ + dstdir = os.path.join(self.builddir, os.path.dirname(dst)) + os.makedirs(dstdir, exist_ok=True) + print("writing {}".format(dst)) + with open(os.path.join(dstdir, os.path.basename(dst)), "w") as f: + for key in defines: + value = defines[key] + if value is not None: + if isinstance(value, int): + f.write("#define {} {}\n".format(key, value)) + else: + f.write('#define {} "{}"\n'.format(key, value)) + else: + f.write("#define {}\n".format(key)) + self.add_work_includedir(os.path.dirname(dst)) + + def makezip(self, dst: str, globstr: str) -> None: + """ create a zip file archive from a glob """ + argv = [ + "zip", + "--junk-paths", + os.path.join(self.installdir, dst), + ] + glob.glob(os.path.join(self.srcdir, globstr)) + print("assembling {}".format(dst)) + subprocess.run(argv, cwd=self.srcdir, check=True) + + def grep_meson(self, src: str, token: str = "fuzzing") -> List[str]: + """ find source files tagged with a specific comment """ + srcs = [] + with open(os.path.join(self.srcdir, src, "meson.build"), "r") as f: + for line in f.read().split("\n"): + if line.find(token) == -1: + continue + srcs.append( + os.path.join( + src, + line.strip() + .replace("'", "") + .replace(",", "") + .replace(" ", "") + .split("#")[0], + ) + ) + return srcs + + +def _build(bld: Builder) -> None: + + # GLib + src = bld.checkout_source("glib", url="https://gitlab.gnome.org/GNOME/glib.git") + bld.build_meson_project( + src, + [ + "-Dlibmount=disabled", + "-Dselinux=disabled", + "-Dnls=disabled", + "-Dlibelf=disabled", + "-Dbsymbolic_functions=false", + "-Dtests=false", + "-Dinternal_pcre=true", + ], + ) + bld.add_work_includedir("include/glib-2.0") + bld.add_work_includedir("lib/glib-2.0/include") + bld.add_build_ldflag("lib/libgio-2.0.a") + bld.add_build_ldflag("lib/libgmodule-2.0.a") + bld.add_build_ldflag("lib/libgobject-2.0.a") + bld.add_build_ldflag("lib/libglib-2.0.a") + bld.add_build_ldflag("lib/libgthread-2.0.a") + + # JSON-GLib + src = bld.checkout_source( + "json-glib", + url="https://gitlab.gnome.org/GNOME/json-glib.git", + ) + bld.build_meson_project( + src, + [ + "-Dgtk_doc=disabled", + "-Dtests=false", + "-Dintrospection=disabled", + ], + ) + bld.add_work_includedir("include/json-glib-1.0/json-glib") + bld.add_work_includedir("include/json-glib-1.0") + bld.add_build_ldflag("lib/libjson-glib-1.0.a") + + # libxmlb + src = bld.checkout_source("libxmlb", url="https://github.com/hughsie/libxmlb.git") + bld.build_meson_project( + src, + [ + "-Dgtkdoc=false", + "-Dintrospection=false", + "-Dtests=false", + ], + ) + bld.add_work_includedir("include/libxmlb-2") + bld.add_work_includedir("include/libxmlb-2/libxmlb") + bld.add_build_ldflag("lib/libxmlb.a") + + # write required headers + bld.write_header("libfwupd/fwupd-version.h", {}) + bld.write_header( + "config.h", + { + "FWUPD_DATADIR": "/tmp", + "FWUPD_LOCALSTATEDIR": "/tmp", + "FWUPD_PLUGINDIR": "/tmp", + "FWUPD_SYSCONFDIR": "/tmp", + "HAVE_REALPATH": None, + "PACKAGE_NAME": "fwupd", + "PACKAGE_VERSION": "0.0.0", + }, + ) + + # libfwupd + libfwupdplugin + built_objs: List[str] = [] + bld.add_src_includedir("fwupd") + for path in ["fwupd/libfwupd", "fwupd/libfwupdplugin"]: + bld.add_src_includedir(path) + for src in bld.grep_meson(path): + built_objs.append(bld.compile(src)) + + # dummy binary entrypoint + if "LIB_FUZZING_ENGINE" in os.environ: + built_objs.append(os.environ["LIB_FUZZING_ENGINE"]) + else: + built_objs.append(bld.compile("fwupd/libfwupdplugin/fu-fuzzer-main.c")) + + # built in formats + for fuzzer in ["dfuse", "fmap", "ihex", "srec"]: + src = bld.substitute( + "fwupd/libfwupdplugin/fu-fuzzer-firmware.c.in", + { + "@FIRMWARENEW@": "fu_{}_firmware_new".format(fuzzer), + "@INCLUDE@": "libfwupdplugin/fu-{}-firmware.h".format(fuzzer), + }, + ) + bld.link([bld.compile(src)] + built_objs, "{}_fuzzer".format(fuzzer)) + bld.makezip( + "{}_fuzzer_seed_corpus.zip".format(fuzzer), + "fwupd/src/fuzzing/firmware/{}*".format(fuzzer), + ) + + # plugins + for srcdir, fuzzer, globstr in [ + ("bcm57xx", "bcm57xx", "bcm57xx*"), + ("ccgx", "ccgx", "ccgx*.cyacd"), + ("ccgx", "ccgx-dmc", "ccgx-dmc*.bin"), + ("cros-ec", "cros-ec", "cros-ec*"), + ("ebitdo", "ebitdo", "ebitdo*"), + ("elantp", "elantp", "elantp*"), + ("hailuck", "hailuck-kbd", "ihex*"), + ("pixart-rf", "pxi", "pixart*"), + ("solokey", "solokey", "solokey*"), + ("synaptics-prometheus", "synaprom", "synaprom*"), + ("synaptics-rmi", "synaptics-rmi", "synaptics-rmi*"), + ("synaptics-mst", "synaptics-mst", "synaptics-mst*"), + ("wacom-usb", "wac", "wacom*"), + ]: + fuzz_objs = [] + for obj in bld.grep_meson("fwupd/plugins/{}".format(srcdir)): + fuzz_objs.append(bld.compile(obj)) + src = bld.substitute( + "fwupd/libfwupdplugin/fu-fuzzer-firmware.c.in", + { + "@FIRMWARENEW@": "fu_{}_firmware_new".format(fuzzer.replace("-", "_")), + "@INCLUDE@": "plugins/{}/fu-{}-firmware.h".format(srcdir, fuzzer), + }, + ) + fuzz_objs.append(bld.compile(src)) + bld.link(fuzz_objs + built_objs, "{}_fuzzer".format(fuzzer)) + bld.makezip( + "{}_fuzzer_seed_corpus.zip".format(fuzzer), + "fwupd/src/fuzzing/firmware/{}".format(globstr), + ) + + +if __name__ == "__main__": + _builder = Builder() + _build(_builder) + sys.exit(0) diff -Nru fwupd-1.4.5/contrib/ci/out-of-tree-link/fwupd.c fwupd-1.5.8/contrib/ci/out-of-tree-link/fwupd.c --- fwupd-1.4.5/contrib/ci/out-of-tree-link/fwupd.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/ci/out-of-tree-link/fwupd.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,10 @@ +#undef NDEBUG +#include + +#include + +int main (void) +{ + assert (fwupd_error_to_string (FWUPD_ERROR_NOTHING_TO_DO) != NULL); + return 0; +} diff -Nru fwupd-1.4.5/contrib/ci/out-of-tree-link/fwupdplugin.c fwupd-1.5.8/contrib/ci/out-of-tree-link/fwupdplugin.c --- fwupd-1.4.5/contrib/ci/out-of-tree-link/fwupdplugin.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/ci/out-of-tree-link/fwupdplugin.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,10 @@ +#undef NDEBUG +#include + +#include + +int main (void) +{ + assert (fu_common_vercmp_full ("1.0", "2.1", FWUPD_VERSION_FORMAT_NUMBER) < 0); + return 0; +} diff -Nru fwupd-1.4.5/contrib/ci/out-of-tree-link/.gitignore fwupd-1.5.8/contrib/ci/out-of-tree-link/.gitignore --- fwupd-1.4.5/contrib/ci/out-of-tree-link/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/ci/out-of-tree-link/.gitignore 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +build diff -Nru fwupd-1.4.5/contrib/ci/out-of-tree-link/meson.build fwupd-1.5.8/contrib/ci/out-of-tree-link/meson.build --- fwupd-1.4.5/contrib/ci/out-of-tree-link/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/ci/out-of-tree-link/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,27 @@ + project('out-of-tree-link', 'c', + license : 'LGPL-2.1+', +) +fwupd = dependency('fwupd') +fwupdplugin = dependency('fwupdplugin') +env = environment() +env.set('G_DEBUG', 'fatal-criticals') +e = executable( + 'fwupd', + sources : [ + 'fwupd.c' + ], + dependencies : [ + fwupd + ], + ) +test('fwupd', e, timeout: 60, env: env) +e = executable( + 'fwupdplugin', + sources : [ + 'fwupdplugin.c' + ], + dependencies : [ + fwupdplugin + ], + ) +test('fwupdplugin', e, timeout: 60, env: env) diff -Nru fwupd-1.4.5/contrib/ci/qt5-thread-test/meson.build fwupd-1.5.8/contrib/ci/qt5-thread-test/meson.build --- fwupd-1.4.5/contrib/ci/qt5-thread-test/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/ci/qt5-thread-test/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,25 @@ +project('qt5-thread-test', 'cpp', + license : 'LGPL-2.1+', +) +add_project_arguments('-fPIC', language : 'cpp') +qt5core = dependency('Qt5Core') +qt5concurrent = dependency('Qt5Concurrent') +glib2 = dependency('glib-2.0') +gio2 = dependency('gio-2.0') +fwupd = dependency('fwupd') +env = environment() +env.set('G_DEBUG', 'fatal-criticals') +e = executable( + 'qt-thread-test', + sources : [ + 'qt-thread-test.cpp' + ], + dependencies : [ + qt5core, + qt5concurrent, + glib2, + gio2, + fwupd, + ], +) +test('qt-thread-test', e, timeout: 60, env: env) diff -Nru fwupd-1.4.5/contrib/ci/qt5-thread-test/qt-thread-test.cpp fwupd-1.5.8/contrib/ci/qt5-thread-test/qt-thread-test.cpp --- fwupd-1.4.5/contrib/ci/qt5-thread-test/qt-thread-test.cpp 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/ci/qt5-thread-test/qt-thread-test.cpp 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2020 Aleix Pol + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include + +#include +#include +#include + +int main(int argc, char** argv) +{ + QCoreApplication app(argc, argv); + + auto client = fwupd_client_new(); + auto cancellable = g_cancellable_new(); + g_autoptr(GError) error = nullptr; + + auto fw = new QFutureWatcher(&app); + QObject::connect(fw, &QFutureWatcher::finished, [fw]() { + QCoreApplication::exit(0); + }); + fw->setFuture(QtConcurrent::run([&] { + return fwupd_client_get_devices(client, cancellable, &error); + })); + + return app.exec(); +} diff -Nru fwupd-1.4.5/contrib/ci/trust.sh fwupd-1.5.8/contrib/ci/trust.sh --- fwupd-1.4.5/contrib/ci/trust.sh 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/contrib/ci/trust.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -#!/bin/sh -set -e -set -x - -# Builds using GPG and PKCS7 turned off to make -# sure no assumptions of a trust backend -rm -rf build -meson build \ - -Dman=false \ - -Ddaemon=false \ - -Dplugin_tpm=false \ - -Dplugin_modem_manager=false \ - -Dplugin_flashrom=false \ - -Dplugin_uefi=false \ - -Dplugin_dell=false \ - -Dplugin_redfish=false \ - -Dsystemd=false \ - -Dlvfs=false \ - -Dlibxmlb:gtkdoc=false \ - -Dlibxmlb:introspection=false \ - -Dlibjcat:introspection=false \ - -Dlibjcat:gtkdoc=false \ - -Dlibjcat:gpg=false \ - -Dlibjcat:pkcs7=false -ninja -C build test -v diff -Nru fwupd-1.4.5/contrib/ci/ubuntu.sh fwupd-1.5.8/contrib/ci/ubuntu.sh --- fwupd-1.4.5/contrib/ci/ubuntu.sh 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/contrib/ci/ubuntu.sh 2021-03-31 20:08:32.000000000 +0000 @@ -2,13 +2,23 @@ set -e set -x +#clone test firmware +if [ "$CI_NETWORK" = "true" ]; then + ./contrib/ci/get_test_firmware.sh + export G_TEST_SRCDIR=`pwd`/fwupd-test-firmware/installed-tests +fi + +#check for and install missing dependencies +./contrib/ci/generate_dependencies.py | xargs apt install -y + #evaluate using Ubuntu's buildflags +#evaluate using Debian/Ubuntu's buildflags eval "$(dpkg-buildflags --export=sh)" #filter out -Bsymbolic-functions export LDFLAGS=$(dpkg-buildflags --get LDFLAGS | sed "s/-Wl,-Bsymbolic-functions\s//") rm -rf build -meson build -Dman=false -Dgtkdoc=true +meson build -Dman=false -Dgtkdoc=true -Dgusb:tests=false -Dplugin_platform_integrity=true #build with clang ninja -C build test -v @@ -16,6 +26,3 @@ ninja -C build install -v mkdir -p dist/docs cp build/docs/* dist/docs -R - -#run static analysis (these mostly won't be critical) -ninja -C build scan-build -v diff -Nru fwupd-1.4.5/contrib/debian/clean fwupd-1.5.8/contrib/debian/clean --- fwupd-1.4.5/contrib/debian/clean 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/clean 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,2 @@ +gtk-doc.make +m4/gtk-doc.m4 diff -Nru fwupd-1.4.5/contrib/debian/compat fwupd-1.5.8/contrib/debian/compat --- fwupd-1.4.5/contrib/debian/compat 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/compat 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +12 diff -Nru fwupd-1.4.5/contrib/debian/control.in fwupd-1.5.8/contrib/debian/control.in --- fwupd-1.4.5/contrib/debian/control.in 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/control.in 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,217 @@ +Source: fwupd +Priority: optional +Maintainer: Debian EFI +Uploaders: Steve McIntyre <93sam@debian.org>, + Matthias Klumpp , + Mario Limonciello +Build-Depends: %%%DYNAMIC%%% +Build-Depends-Indep: libglib2.0-doc +Standards-Version: 4.5.0 +Section: admin +Homepage: https://github.com/fwupd/fwupd +Vcs-Git: https://salsa.debian.org/efi-team/fwupd.git +Vcs-Browser: https://salsa.debian.org/efi-team/fwupd + +Package: libfwupdplugin1 +Section: libs +Architecture: linux-any +Depends: ${misc:Depends}, + ${shlibs:Depends} +Multi-Arch: same +Description: Firmware update daemon plugin library + fwupd is a daemon to allow session software to update device firmware. + You can either use a GUI software manager like GNOME Software to view and + apply updates, the command-line tool or the system D-Bus interface directly. + Firmware updates are supported for a variety of technologies. + See for details + . + This package provides the library for the interface between daemon and plugins. + +Package: libfwupd2 +Section: libs +Architecture: linux-any +Depends: ${misc:Depends}, + ${shlibs:Depends} +Multi-Arch: same +Description: Firmware update daemon library + fwupd is a daemon to allow session software to update device firmware. + You can either use a GUI software manager like GNOME Software to view and + apply updates, the command-line tool or the system D-Bus interface directly. + Firmware updates are supported for a variety of technologies. + See for details + . + This package provides the library used by the daemon. + +Package: fwupd +Architecture: linux-any +Depends: ${misc:Depends}, + ${shlibs:Depends}, + shared-mime-info +Recommends: python3, + bolt, + dbus, + secureboot-db, + udisks2, + fwupd-signed +Suggests: gir1.2-fwupd-2.0 +Provides: fwupdate +Conflicts: fwupdate-amd64-signed, + fwupdate-i386-signed, + fwupdate-arm64-signed, + fwupdate-armhf-signed +Breaks: gir1.2-dfu-1.0 (<< 0.9.7-1), + libdfu1 (<< 0.9.7-1), + fwupdate (<< 12-7), + libdfu-dev (<< 0.9.7-1) +Replaces: gir1.2-dfu-1.0 (<< 0.9.7-1), + libdfu1 (<< 0.9.7-1), + libdfu-dev (<< 0.9.7-1), + fwupdate (<< 12-7) +Multi-Arch: foreign +Description: Firmware update daemon + fwupd is a daemon to allow session software to update device firmware. + You can either use a GUI software manager like GNOME Software to view and + apply updates, the command-line tool or the system D-Bus interface directly. + Firmware updates are supported for a variety of technologies. + See for details + +Package: fwupd-tests +Architecture: linux-any +Depends: ${misc:Depends}, + ${shlibs:Depends}, + ca-certificates, + dbus-x11, + fwupd, + gnome-desktop-testing, + policykit-1, + python3, + python3-gi, + python3-requests, +Breaks: fwupd (<< 0.9.4-1) +Replaces: fwupd (<< 0.9.4-1) +Multi-Arch: foreign +Description: Test suite for firmware update daemon + fwupd is a daemon to allow session software to update device firmware. + You can either use a GUI software manager like GNOME Software to view and + apply updates, the command-line tool or the system D-Bus interface directly. + Firmware updates are supported for a variety of technologies. + See for details + . + This package provides a set of installed tests that can be run to validate + the daemon in a continuous integration system. + +Package: fwupd-doc +Section: doc +Architecture: all +Multi-Arch: foreign +Depends: ${misc:Depends}, +Description: Firmware update daemon documentation (HTML format) + fwupd is a daemon to allow session software to update device firmware. + You can either use a GUI software manager like GNOME Software to view and + apply updates, the command-line tool or the system D-Bus interface directly. + Firmware updates are supported for a variety of technologies. + See for details + . + This package provides development documentation for creating a package that + uses fwupd. + +Package: libfwupd-dev +Architecture: linux-any +Multi-Arch: same +Depends: libfwupd2 (= ${binary:Version}), + gir1.2-fwupd-2.0 (= ${binary:Version}), + libcurl4-gnutls-dev, + libglib2.0-dev (>= 2.45.8), + libjcat-dev, + libjson-glib-dev (>= 1.1.1), + ${misc:Depends} +Breaks: fwupd-dev (<< 0.5.4-2~) +Replaces: fwupd-dev (<< 0.5.4-2~) +Section: libdevel +Description: development files for libfwupd + fwupd is a daemon to allow session software to update device firmware. + You can either use a GUI software manager like GNOME Software to view and + apply updates, the command-line tool or the system D-Bus interface directly. + Firmware updates are supported for a variety of technologies. + See for details + . + This package provides the development files for libfwupd + +Package: gir1.2-fwupd-2.0 +Architecture: linux-any +Multi-Arch: same +Depends: ${misc:Depends}, + ${gir:Depends} +Section: introspection +Description: GObject introspection data for libfwupd + This package provides the introspection data for libfwupd. + . + It can be used by packages using the GIRepository format to generate + dynamic bindings. + +Package: libfwupdplugin-dev +Architecture: linux-any +Multi-Arch: same +Depends: libfwupdplugin1 (= ${binary:Version}), + gir1.2-fwupdplugin-1.0 (= ${binary:Version}), + libarchive-dev, + libcurl4-gnutls-dev, + libfwupd-dev (= ${binary:Version}), + libgcab-dev, + libglib2.0-dev (>= 2.45.8), + libgudev-1.0-dev, + libgusb-dev (>= 0.3.5), + libjcat-dev, + libjson-glib-dev (>= 1.1.1), + libxmlb-dev (>= 0.1.13), + valgrind [!ia64 !riscv64 !x32 !mips !sparc64 !sh4 !ppc64 !powerpcspe !hppa !alpha !mips64el !armhf !armel !mipsel !m68k], + ${misc:Depends} +Section: libdevel +Description: development files for libfwupdplugin + fwupd is a daemon to allow session software to update device firmware. + You can either use a GUI software manager like GNOME Software to view and + apply updates, the command-line tool or the system D-Bus interface directly. + Firmware updates are supported for a variety of technologies. + See for details + . + This package provides the development files for libfwupdplugin + +Package: gir1.2-fwupdplugin-1.0 +Architecture: linux-any +Multi-Arch: same +Depends: ${misc:Depends}, + ${gir:Depends} +Section: introspection +Description: GObject introspection data for libfwupdplugin + This package provides the introspection data for libfwupdplugin. + . + It can be used by packages using the GIRepository format to generate + dynamic bindings. + +Package: fwupd-amd64-signed-template +Architecture: amd64 +Depends: ${shlibs:Depends}, ${misc:Depends}, make | build-essential | dpkg-dev +Description: Template for signed fwupd package + This package is used to control code signing by the Debian signing + service. + +Package: fwupd-i386-signed-template +Architecture: i386 +Depends: ${shlibs:Depends}, ${misc:Depends}, make | build-essential | dpkg-dev +Description: Template for signed fwupd package + This package is used to control code signing by the Debian signing + service. + +Package: fwupd-armhf-signed-template +Architecture: armhf +Depends: ${shlibs:Depends}, ${misc:Depends}, make | build-essential | dpkg-dev +Description: Template for signed fwupd package + This package is used to control code signing by the Debian signing + service. + +Package: fwupd-arm64-signed-template +Architecture: arm64 +Depends: ${shlibs:Depends}, ${misc:Depends}, make | build-essential | dpkg-dev +Description: Template for signed fwupd package + This package is used to control code signing by the Debian signing + service. diff -Nru fwupd-1.4.5/contrib/debian/control.qubes.in fwupd-1.5.8/contrib/debian/control.qubes.in --- fwupd-1.4.5/contrib/debian/control.qubes.in 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/control.qubes.in 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,4 @@ +Package: fwupd-qubes-vm-whonix +Architecture: amd64 +Description: Whonix support for Qubes OS + This package is used to download firmware updates and metadata via TOR. diff -Nru fwupd-1.4.5/contrib/debian/copyright.in fwupd-1.5.8/contrib/debian/copyright.in --- fwupd-1.4.5/contrib/debian/copyright.in 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/copyright.in 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,140 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: fwupd +Source: https://github.com/fwupd/fwupd + +%%%DYNAMIC%%% +Files: *.metainfo.xml +Copyright: Richard Hughes +License: CC0-1.0 + +Files: debian/* +Copyright: 2015 Daniel Jared Dominguez + 2015 Mario Limonciello +License: LGPL-2.1+ + +License: LGPL-2.1+ + This package is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + . + This package is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + . + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see + . + On Debian systems, the complete text of the GNU Lesser General + Public License version 2.1 can be found in "/usr/share/common-licenses/LGPL-2.1". + + +License: CC0-1.0 + Creative Commons CC0 1.0 Universal + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL + SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT + RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. + CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE + INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES + RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + . + Statement of Purpose + . + The laws of most jurisdictions throughout the world automatically confer + exclusive Copyright and Related Rights (defined below) upon the creator and + subsequent owner(s) (each and all, an "owner") of an original work of + authorship and/or a database (each, a "Work"). Certain owners wish to + permanently relinquish those rights to a Work for the purpose of contributing + to a commons of creative, cultural and scientific works ("Commons") that the + public can reliably and without fear of later claims of infringement build + upon, modify, incorporate in other works, reuse and redistribute as freely as + possible in any form whatsoever and for any purposes, including without + limitation commercial purposes. These owners may contribute to the Commons to + promote the ideal of a free culture and the further production of creative, + cultural and scientific works, or to gain reputation or greater distribution + for their Work in part through the use and efforts of others. For these and/or + other purposes and motivations, and without any expectation of additional + consideration or compensation, the person associating CC0 with a Work (the + "Affirmer"), to the extent that he or she is an owner of Copyright and Related + Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly + distribute the Work under its terms, with knowledge of his or her Copyright and + Related Rights in the Work and the meaning and intended legal effect of CC0 on + those rights. + . + 1. Copyright and Related Rights. A Work made available under CC0 may be + protected by copyright and related or neighboring rights ("Copyright and + Related Rights"). Copyright and Related Rights include, but are not limited to, + the following: + i. the right to reproduce, adapt, distribute, perform, display, communicate, + and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); + iii. publicity and privacy rights pertaining to a person's image or likeness + depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, subject + to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data in a + Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal protection + of databases, and under any national implementation thereof, including any + amended or successor version of such directive); and + vii. other similar, equivalent or corresponding rights throughout the world + based on applicable law or treaty, and any national implementations thereof. + . + 2. Waiver. To the greatest extent permitted by, but not in contravention of, + applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and + unconditionally waives, abandons, and surrenders all of Affirmer's Copyright + and Related Rights and associated claims and causes of action, whether now + known or unknown (including existing as well as future claims and causes of + action), in the Work (i) in all territories worldwide, (ii) for the maximum + duration provided by applicable law or treaty (including future time + extensions), (iii) in any current or future medium and for any number of + copies, and (iv) for any purpose whatsoever, including without limitation + commercial, advertising or promotional purposes (the "Waiver"). + Affirmer makes the Waiver for the benefit of each member of the public at large + and to the detriment of Affirmer's heirs and successors, fully intending that + such Waiver shall not be subject to revocation, rescission, cancellation, + termination, or any other legal or equitable action to disrupt the quiet + enjoyment of the Work by the public as contemplated by Affirmer's express + Statement of Purpose. + . + 3. Public License Fallback. Should any part of the Waiver for any reason be + judged legally invalid or ineffective under applicable law, then the Waiver + shall be preserved to the maximum extent permitted taking into account + Affirmer's express Statement of Purpose. In addition, to the extent the Waiver + is so judged Affirmer hereby grants to each affected person a royalty-free, non + transferable, non sublicensable, non exclusive, irrevocable and unconditional + license to exercise Affirmer's Copyright and Related Rights in the Work (i) in + all territories worldwide, (ii) for the maximum duration provided by + applicable law or treaty (including future time extensions), (iii) in any + current or future medium and for any number of copies, and (iv) for any + purpose whatsoever, including without limitation commercial, advertising or + promotional purposes (the "License"). The License shall be deemed effective + as of the date CC0 was applied by Affirmer to the Work. Should any part of + the License for any reason be judged legally invalid or ineffective under + applicable law, such partial invalidity or ineffectiveness shall not + invalidate the remainder of the License, and in such case Affirmer hereby + affirms that he or she will not (i) exercise any of his or her remaining + Copyright and Related Rights in the Work or (ii) assert any associated claims + and causes of action with respect to the Work, in either case contrary to + Affirmer's express Statement of Purpose. + . + 4. Limitations and Disclaimers. + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or warranties of + any kind concerning the Work, express, implied, statutory or otherwise, + including without limitation warranties of title, merchantability, fitness for + a particular purpose, non infringement, or the absence of latent or other + defects, accuracy, or the present or absence of errors, whether or not + discoverable, all to the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons that + may apply to the Work or any use thereof, including without limitation any + person's Copyright and Related Rights in the Work. Further, Affirmer disclaims + responsibility for obtaining any necessary consents, permissions or other + rights required for any use of the Work. + d. Affirmer understands and acknowledges that Creative Commons is not a party + to this document and has no duty or obligation with respect to this CC0 or use + of the Work. diff -Nru fwupd-1.4.5/contrib/debian/docs fwupd-1.5.8/contrib/debian/docs --- fwupd-1.4.5/contrib/debian/docs 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/docs 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ + diff -Nru fwupd-1.4.5/contrib/debian/fwupd.dirs fwupd-1.5.8/contrib/debian/fwupd.dirs --- fwupd-1.4.5/contrib/debian/fwupd.dirs 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/fwupd.dirs 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +var/cache/app-info/xmls diff -Nru fwupd-1.4.5/contrib/debian/fwupd-doc.install fwupd-1.5.8/contrib/debian/fwupd-doc.install --- fwupd-1.4.5/contrib/debian/fwupd-doc.install 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/fwupd-doc.install 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +usr/share/gtk-doc diff -Nru fwupd-1.4.5/contrib/debian/fwupd.install fwupd-1.5.8/contrib/debian/fwupd.install --- fwupd-1.4.5/contrib/debian/fwupd.install 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/fwupd.install 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,22 @@ +usr/bin/* +etc/* +usr/share/bash-completion +usr/share/fish/vendor_completions.d +usr/share/fwupd/* +usr/share/dbus-1/* +usr/share/icons/* +usr/share/polkit-1/* +usr/share/locale +usr/share/metainfo/* +usr/libexec/fwupd/* +usr/share/man/man1/* +lib/systemd/system/* +lib/systemd/system-preset/* +lib/systemd/system-shutdown/* +var/lib/fwupd +lib/udev/rules.d/* +data/daemon.conf etc/fwupd +debian/fwupd.pkla /var/lib/polkit-1/localauthority/10-vendor.d +usr/lib/*/fwupd-plugins-*/*.so +debian/lintian/fwupd usr/share/lintian/overrides +obj*/data/motd/85-fwupd /etc/update-motd.d diff -Nru fwupd-1.4.5/contrib/debian/fwupd.maintscript fwupd-1.5.8/contrib/debian/fwupd.maintscript --- fwupd-1.4.5/contrib/debian/fwupd.maintscript 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/fwupd.maintscript 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,6 @@ + +rm_conffile /etc/fwupd.conf 1.0.0~ +rm_conffile /etc/fwupd/remotes.d/fwupd.conf 1.2.7~ +rm_conffile /etc/dbus-1/system.d/org.freedesktop.fwupd.conf 1.3.2~ +rm_conffile /etc/modules-load.d/fwupd-msr.conf 1.5.3~ +rm_conffile /etc/modules-load.d/fwupd-platform-integrity.conf 1.5.3~ diff -Nru fwupd-1.4.5/contrib/debian/fwupd.pkla fwupd-1.5.8/contrib/debian/fwupd.pkla --- fwupd-1.4.5/contrib/debian/fwupd.pkla 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/fwupd.pkla 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,5 @@ +[Call internal fwupd actions] +Identity=unix-group:admin;unix-group:sudo +Action=org.freedesktop.fwupd.update-internal +ResultActive=yes + diff -Nru fwupd-1.4.5/contrib/debian/fwupd.postinst fwupd-1.5.8/contrib/debian/fwupd.postinst --- fwupd-1.4.5/contrib/debian/fwupd.postinst 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/fwupd.postinst 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,50 @@ +#!/bin/sh +set -e + +#DEBHELPER# + +if dpkg-maintscript-helper supports rm_conffile 2>/dev/null; then + dpkg-maintscript-helper rm_conffile \ + /etc/fwupd.conf 1.0.0~ -- "$@" + dpkg-maintscript-helper rm_conffile \ + /etc/fwupd/remotes.d/fwupd.conf 1.2.7~ -- "$@" + dpkg-maintscript-helper rm_conffile \ + /etc/dbus-1/system.d/org.freedesktop.fwupd.conf 1.3.2~ -- "$@" + dpkg-maintscript-helper rm_conffile \ + /etc/fwupd/ata.conf 1.5.5~ -- "$@" +fi + +#Perform transition from /etc/fwupd/uefi.conf to /etc/fwupd/uefi_capsule.conf +if dpkg-maintscript-helper supports mv_conffile 2>/dev/null; then + ORIGINAL=/etc/fwupd/uefi.conf + NEW=/etc/fwupd/uefi_capsule.conf + #If already upgraded this file won't exist + #If in the middle of an upgrade: + # -> If unmodified then preinst would have renamed to /etc/fwupd/uefi.conf.dpkg-remove + # -> If modified, we need to do an in-place upgrade with sed + if [ -f $ORIGINAL ]; then + sed "s,\[uefi\],\[uefi_capsule\]," -i $ORIGINAL + fi + dpkg-maintscript-helper mv_conffile $ORIGINAL $NEW 1.5.5~ -- "$@" +fi + +# Clean up from fwupdate->fwupd transition +# This can be removed after bullseye and focal are released +EFIDIR=$(awk '/^ID=/ {gsub(/"/,""); split($$0,a,"="); print tolower(a[2])}' /etc/os-release) +if [ "${DPKG_MAINTSCRIPT_ARCH}" = "amd64" ]; then + EFI_NAME=x64 +elif [ "${DPKG_MAINTSCRIPT_ARCH}" = "i386" ]; then + EFI_NAME=ia32 +elif [ "${DPKG_MAINTSCRIPT_ARCH}" = "arm64" ]; then + EFI_NAME=aa64 +elif [ "${DPKG_MAINTSCRIPT_ARCH}" = "armhf" ]; then + EFI_NAME=arm +fi +rm -f /boot/efi/EFI/$EFIDIR/fwup$EFI_NAME.efi +rm -f /var/lib/fwupdate/done +rm -f /var/cache/fwupdate/done +for dir in /var/cache/fwupdate /var/lib/fwupdate; do + if [ -d $dir ]; then + rmdir --ignore-fail-on-non-empty $dir || true + fi +done diff -Nru fwupd-1.4.5/contrib/debian/fwupd.postrm fwupd-1.5.8/contrib/debian/fwupd.postrm --- fwupd-1.4.5/contrib/debian/fwupd.postrm 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/fwupd.postrm 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,27 @@ +#!/bin/sh +set -e + +#DEBHELPER# + +if [ "$1" = purge ]; then + rm -rf /var/lib/fwupd/gnupg + rm -f /var/cache/app-info/xmls/fwupd.xml +fi + +if dpkg-maintscript-helper supports rm_conffile 2>/dev/null; then + dpkg-maintscript-helper rm_conffile \ + /etc/fwupd.conf 1.0.0~ -- "$@" + dpkg-maintscript-helper rm_conffile \ + /etc/fwupd/remotes.d/fwupd.conf 1.2.7~ -- "$@" + dpkg-maintscript-helper rm_conffile \ + /etc/dbus-1/system.d/org.freedesktop.fwupd.conf 1.3.2~ -- "$@" + dpkg-maintscript-helper rm_conffile \ + /etc/fwupd/ata.conf 1.5.5~ -- "$@" +fi + +#Perform transition from /etc/fwupd/uefi.conf to /etc/fwupd/uefi_capsule.conf +if dpkg-maintscript-helper supports mv_conffile 2>/dev/null; then + ORIGINAL=/etc/fwupd/uefi.conf + NEW=/etc/fwupd/uefi_capsule.conf + dpkg-maintscript-helper mv_conffile $ORIGINAL $NEW 1.5.5~ -- "$@" +fi diff -Nru fwupd-1.4.5/contrib/debian/fwupd.preinst fwupd-1.5.8/contrib/debian/fwupd.preinst --- fwupd-1.4.5/contrib/debian/fwupd.preinst 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/fwupd.preinst 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,29 @@ +#!/bin/sh +set -e + +#DEBHELPER# + +if dpkg-maintscript-helper supports rm_conffile 2>/dev/null; then + dpkg-maintscript-helper rm_conffile \ + /etc/fwupd.conf 1.0.0~ -- "$@" + dpkg-maintscript-helper rm_conffile \ + /etc/fwupd/remotes.d/fwupd.conf 1.2.7~ -- "$@" + dpkg-maintscript-helper rm_conffile \ + /etc/dbus-1/system.d/org.freedesktop.fwupd.conf 1.3.2~ -- "$@" + dpkg-maintscript-helper rm_conffile \ + /etc/fwupd/ata.conf 1.5.5~ -- "$@" +fi + +#Perform transition from /etc/fwupd/uefi.conf to /etc/fwupd/uefi_capsule.conf +if dpkg-maintscript-helper supports mv_conffile 2>/dev/null; then + ORIGINAL=/etc/fwupd/uefi.conf + NEW=/etc/fwupd/uefi_capsule.conf + dpkg-maintscript-helper mv_conffile $ORIGINAL $NEW 1.5.5~ -- "$@" +fi + +# 1.3.2 had fwupd-refresh.service and fwupd.service both claiming +# this directory, but fwupd-refresh.service used DynamicUser directive +# meaning no other unit could access it. +if [ -L /var/cache/fwupd ]; then + rm -f /var/cache/fwupd +fi diff -Nru fwupd-1.4.5/contrib/debian/fwupd-qubes-vm-whonix.install fwupd-1.5.8/contrib/debian/fwupd-qubes-vm-whonix.install --- fwupd-1.4.5/contrib/debian/fwupd-qubes-vm-whonix.install 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/fwupd-qubes-vm-whonix.install 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,2 @@ +usr/libexec/qubes-fwupd/fwupd_download_updates.py +usr/libexec/qubes-fwupd/fwupd_common_vm.py diff -Nru fwupd-1.4.5/contrib/debian/fwupd-qubes-vm-whonix.postinst fwupd-1.5.8/contrib/debian/fwupd-qubes-vm-whonix.postinst --- fwupd-1.4.5/contrib/debian/fwupd-qubes-vm-whonix.postinst 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/fwupd-qubes-vm-whonix.postinst 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,11 @@ +#!/bin/bash + +HOME_DIR=`getent passwd user | awk '{ split($$0,a,":"); print a[6]}'` + +if [ -z "$HOME_DIR" ]; then + echo "Default user does not exist!!" >&2 + echo "Package does not create fwupd directories" >&2 +else + mkdir -p $HOME_DIR/.cache/fwupd_download_updates + chown -R user:user $HOME_DIR/.cache/fwupd_download_updates +fi diff -Nru fwupd-1.4.5/contrib/debian/fwupd-qubes-vm-whonix.postrm fwupd-1.5.8/contrib/debian/fwupd-qubes-vm-whonix.postrm --- fwupd-1.4.5/contrib/debian/fwupd-qubes-vm-whonix.postrm 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/fwupd-qubes-vm-whonix.postrm 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,7 @@ +#!/bin/bash + +HOME_DIR=`getent passwd user | awk '{ split($$0,a,":"); print a[6]}'` + +if [ -z "$HOME_DIR" ] && [ "$1" = "purge" ]; then + rm -rf $HOME_DIR/.cache/fwupd +fi diff -Nru fwupd-1.4.5/contrib/debian/fwupd-tests.install fwupd-1.5.8/contrib/debian/fwupd-tests.install --- fwupd-1.4.5/contrib/debian/fwupd-tests.install 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/fwupd-tests.install 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,11 @@ +#These are in a generic looking directory because +#that is where gnome-desktop-testing expects to +#find them. for more information see: +#https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=872458 +usr/share/installed-tests/* +usr/libexec/installed-tests/fwupd/fwupd.sh +usr/libexec/installed-tests/fwupd/*-self-test +usr/lib/*/fwupd-plugins-3/libfu_plugin_test.so +usr/lib/*/fwupd-plugins-3/libfu_plugin_invalid.so +debian/lintian/fwupd-tests usr/share/lintian/overrides +etc/fwupd/remotes.d/fwupd-tests.conf diff -Nru fwupd-1.4.5/contrib/debian/fwupd-tests.postinst fwupd-1.5.8/contrib/debian/fwupd-tests.postinst --- fwupd-1.4.5/contrib/debian/fwupd-tests.postinst 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/fwupd-tests.postinst 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,23 @@ +#!/bin/sh +set -e + +#DEBHELPER# + +#only enable on installation not upgrade +if [ "$1" = configure ] && [ -z "$2" ]; then + if [ -f /etc/fwupd/daemon.conf ]; then + if [ "$CI" = "true" ]; then + sed "s,^DisabledPlugins=.*,DisabledPlugins=," -i /etc/fwupd/daemon.conf + else + echo "To enable test suite, modify /etc/fwupd/daemon.conf" + fi + fi + if [ -f /etc/fwupd/remotes.d/fwupd-tests.conf ]; then + if [ "$CI" = "true" ]; then + sed "s,^Enabled=false,Enabled=true," -i /etc/fwupd/remotes.d/fwupd-tests.conf + else + echo "To enable test suite, enable fwupd-tests remote" + fi + + fi +fi diff -Nru fwupd-1.4.5/contrib/debian/fwupd-tests.postrm fwupd-1.5.8/contrib/debian/fwupd-tests.postrm --- fwupd-1.4.5/contrib/debian/fwupd-tests.postrm 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/fwupd-tests.postrm 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,14 @@ +#!/bin/sh +set -e + +#DEBHELPER# + +if [ "$1" = remove -o "$1" = purge ]; then + if [ -f /etc/fwupd/daemon.conf ]; then + if [ "$CI" = "true" ]; then + sed "s,^DisabledPlugins=,DisabledPlugins=test;invalid," -i /etc/fwupd/daemon.conf + else + echo "To disable test suite, modify /etc/fwupd/daemon.conf" + fi + fi +fi diff -Nru fwupd-1.4.5/contrib/debian/gbp.conf fwupd-1.5.8/contrib/debian/gbp.conf --- fwupd-1.4.5/contrib/debian/gbp.conf 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/gbp.conf 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,7 @@ +[DEFAULT] +debian-branch = debian +upstream-tag = %(version)s + +[buildpackage] +sign-tags = True +dist = experimental diff -Nru fwupd-1.4.5/contrib/debian/gen_signing_changelog fwupd-1.5.8/contrib/debian/gen_signing_changelog --- fwupd-1.4.5/contrib/debian/gen_signing_changelog 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/gen_signing_changelog 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,32 @@ +#!/bin/sh +# +# Generate a changelog file for the signed fwupdate package, based on +# a changelog.in file and other state + +DIR=$1 +SOURCE=$2 +ARCH=$3 +IN="${DIR}/changelog.in" +OUT="${DIR}/changelog" + +# Parse out fields from our changelg entry - want the signing-template +# one to match all the important details where we can +DISTRIBUTION="$(dpkg-parsechangelog | sed -ne 's/^Distribution: \(.*\)/\1/p')" +URGENCY="$(dpkg-parsechangelog | sed -ne 's/^Urgency: \(.*\)/\1/p')" +MAINT="$(dpkg-parsechangelog | sed -ne 's/^Maintainer: \(.*\)/\1/p')" +DATE="$(dpkg-parsechangelog | sed -ne 's/^Date: \(.*\)/\1/p')" + +# If the version ends in "+bXXX", this is a binNMU. We don't want a new +# source package to look like that, so change it to ".bXXX" instead +VERSION="$(dpkg-parsechangelog | sed -ne 's/^Version: \(.*\)/\1/p')" +MANGLED_VERSION="$(echo $VERSION | sed -r 's/-/\+/;s/\+(b[[:digit:]]+)$/.\1/')" + +printf "%s-%s-signed (%s) %s; urgency=%s\n" "${SOURCE}" "${ARCH}" "${MANGLED_VERSION}" "${DISTRIBUTION}" "${URGENCY}" > $OUT +printf "\n" >> $OUT +printf " * Update to %s version %s\n" "${SOURCE}" "${VERSION}" >> $OUT +printf "\n" >> $OUT +printf " -- %s %s\n" "${MAINT}" "${DATE}" >> $OUT +printf "\n" >> $OUT + +cat $IN >> $OUT +rm -f $IN diff -Nru fwupd-1.4.5/contrib/debian/gen_signing_json fwupd-1.5.8/contrib/debian/gen_signing_json --- fwupd-1.4.5/contrib/debian/gen_signing_json 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/gen_signing_json 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,29 @@ +#!/bin/sh +# +# Generate a json file to go in the the fwupd-signed template +# package. Describes exactly what needs to be signed, and how. + +DIR=$1 +SOURCE=$2 +ARCH=$3 +OUT="$DIR/files.json" + +# What file are we looking to sign? +BINARY=$(find debian/tmp -name '*.efi' | xargs basename) + +# Actually needs full path within the binary deb +BINARY="usr/libexec/${SOURCE}/efi/${BINARY}" + +rm -f $OUT + +printf '{\n' >> $OUT +printf ' "packages": {\n' >> $OUT +printf ' "%s": {\n' "${SOURCE}" >> $OUT +printf ' "trusted_certs": [],\n' >> $OUT +printf ' "files": [ \n' >> $OUT +printf ' {"sig_type": "efi", "file": "%s"}\n' "${BINARY}" >> $OUT +printf ' ]\n' >> $OUT +printf ' }\n' >> $OUT +printf ' }\n' >> $OUT +printf '}\n' >> $OUT + diff -Nru fwupd-1.4.5/contrib/debian/gir1.2-fwupd-2.0.install fwupd-1.5.8/contrib/debian/gir1.2-fwupd-2.0.install --- fwupd-1.4.5/contrib/debian/gir1.2-fwupd-2.0.install 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/gir1.2-fwupd-2.0.install 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +usr/lib/*/girepository-1.0/Fwupd-*.typelib diff -Nru fwupd-1.4.5/contrib/debian/gir1.2-fwupdplugin-1.0.install fwupd-1.5.8/contrib/debian/gir1.2-fwupdplugin-1.0.install --- fwupd-1.4.5/contrib/debian/gir1.2-fwupdplugin-1.0.install 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/gir1.2-fwupdplugin-1.0.install 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +usr/lib/*/girepository-1.0/FwupdPlugin-*.typelib diff -Nru fwupd-1.4.5/contrib/debian/libfwupd2.install fwupd-1.5.8/contrib/debian/libfwupd2.install --- fwupd-1.4.5/contrib/debian/libfwupd2.install 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/libfwupd2.install 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +usr/lib/*/libfwupd.so.* diff -Nru fwupd-1.4.5/contrib/debian/libfwupd-dev.install fwupd-1.5.8/contrib/debian/libfwupd-dev.install --- fwupd-1.4.5/contrib/debian/libfwupd-dev.install 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/libfwupd-dev.install 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,7 @@ +usr/include/fwupd-1/fwupd.h +usr/include/fwupd-1/libfwupd +usr/lib/*/libfwupd.so +usr/lib/*/pkgconfig/fwupd.pc +usr/share/gir-1.0/Fwupd-*.gir +usr/share/vala/vapi/fwupd.deps +usr/share/vala/vapi/fwupd.vapi diff -Nru fwupd-1.4.5/contrib/debian/libfwupdplugin1.install fwupd-1.5.8/contrib/debian/libfwupdplugin1.install --- fwupd-1.4.5/contrib/debian/libfwupdplugin1.install 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/libfwupdplugin1.install 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +usr/lib/*/libfwupdplugin.so.* diff -Nru fwupd-1.4.5/contrib/debian/libfwupdplugin-dev.install fwupd-1.5.8/contrib/debian/libfwupdplugin-dev.install --- fwupd-1.4.5/contrib/debian/libfwupdplugin-dev.install 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/libfwupdplugin-dev.install 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,7 @@ +usr/include/fwupd-1/fwupdplugin.h +usr/include/fwupd-1/libfwupdplugin +usr/lib/*/libfwupdplugin.so +usr/lib/*/pkgconfig/fwupdplugin.pc +usr/share/gir-1.0/FwupdPlugin-*.gir +usr/share/vala/vapi/fwupdplugin.deps +usr/share/vala/vapi/fwupdplugin.vapi diff -Nru fwupd-1.4.5/contrib/debian/lintian/fwupd fwupd-1.5.8/contrib/debian/lintian/fwupd --- fwupd-1.4.5/contrib/debian/lintian/fwupd 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/lintian/fwupd 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,15 @@ +#these are intended to be d-bus activated +fwupd binary: systemd-service-file-missing-install-key lib/systemd/system/fwupd-offline-update.service +fwupd binary: systemd-service-file-missing-install-key lib/systemd/system/fwupd.service +fwupd binary: systemd-service-file-missing-install-key lib/systemd/system/system-update.target.wants/fwupd-offline-update.service +#see debian bug 896012 +fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_upower.so +fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_uefi_recovery.so +#EFI applications are PE executables +fwupd: executable-not-elf-or-script usr/libexec/fwupd/efi/*.efi +fwupd: portable-executable-missing-security-features usr/libexec/fwupd/efi/*.efi SafeSEH +fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_modem_manager.so +fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_pci_bcr.so +fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_pci_mei.so +fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_iommu.so +fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_msr.so diff -Nru fwupd-1.4.5/contrib/debian/lintian/fwupd-tests fwupd-1.5.8/contrib/debian/lintian/fwupd-tests --- fwupd-1.4.5/contrib/debian/lintian/fwupd-tests 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/lintian/fwupd-tests 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,3 @@ +#see debian bug 896012 +fwupd-tests: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_test.so +fwupd-tests: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_invalid.so diff -Nru fwupd-1.4.5/contrib/debian/not-installed fwupd-1.5.8/contrib/debian/not-installed --- fwupd-1.4.5/contrib/debian/not-installed 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/not-installed 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,4 @@ +usr/libexec/qubes-fwupd/fwupd_usbvm_validate.py +usr/sbin/qubes-fwupdmgr +usr/share/qubes-fwupd/src/* +usr/share/qubes-fwupd/test/* diff -Nru fwupd-1.4.5/contrib/debian/README.Debian fwupd-1.5.8/contrib/debian/README.Debian --- fwupd-1.4.5/contrib/debian/README.Debian 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/README.Debian 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,18 @@ +signed vs unsigned fwupd programs +------------------------------------ + +fwupd 1.1.0 is configured to understand when to use a signed version +of the EFI binary. If the signed version isn't installed but secure +boot is turned on, it will avoid copying to the EFI system partition. + +This allows supporting secure boot even if not turned on at install, or +changed later after install. + +In Ubuntu, both fwupd-signed and fwupd are seeded in the default +installation. Nothing is installed to the ESP until it's needed. + +In Debian, the package name for the signed version is slightly +different due to different infrastructure. fwupd-signed-$ARCH and +fwupd should both be installed and then things will work similarly +to what's described above. + diff -Nru fwupd-1.4.5/contrib/debian/README.source fwupd-1.5.8/contrib/debian/README.source --- fwupd-1.4.5/contrib/debian/README.source 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/README.source 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,9 @@ +fwupd for Debian +---------------- + +To build from the git tree, run: + git-buildpackage -us -uc -S +Then, if using sbuild, you can use something like: + sbuild -s -c sid-amd64 -d unstable + + -- Daniel Jared Dominguez Thu, 21 May 2015 13:44:16 -0500 diff -Nru fwupd-1.4.5/contrib/debian/rules fwupd-1.5.8/contrib/debian/rules --- fwupd-1.4.5/contrib/debian/rules 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/rules 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,133 @@ +#!/usr/bin/make -f +# -*- makefile -*- + +export LC_ALL := C.UTF-8 +export DEB_BUILD_MAINT_OPTIONS = hardening=+all +export DEB_LDFLAGS_MAINT_STRIP=-Wl,-Bsymbolic-functions + +#GPGME needs this for proper building on 32 bit archs +ifeq ($(DEB_HOST_ARCH_BITS),32) + export DEB_CFLAGS_MAINT_APPEND = -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE +endif + +CONFARGS = + +ifneq ($(CI),) + CONFARGS += --werror --wrap-mode=default +endif + +SB_STYLE := debian +deb_version := $(shell dpkg-parsechangelog --show-field Version) +ifeq (yes,$(shell dpkg-vendor --derives-from Ubuntu && echo yes)) + SB_STYLE := ubuntu + tar_name := fwupd_$(deb_version)_$(DEB_HOST_ARCH).tar.gz + CONFARGS += -Dplugin_flashrom=false + CONFARGS += -Defi_sbat_distro_id=ubuntu + CONFARGS += -Defi_sbat_distro_summary=Ubuntu + CONFARGS += -Defi_sbat_distro_pkgname=fwupd + CONFARGS += -Defi_sbat_distro_version=$(deb_version) + CONFARGS += -Defi_sbat_distro_url="https://launchpad.net/ubuntu/+source/fwupd" +else + TMPLDIR := debian/fwupd-$(DEB_HOST_ARCH)-signed-template/usr/share/code-signing/fwupd-$(DEB_HOST_ARCH)-signed-template + ifneq ($(DEB_HOST_ARCH_CPU),ia64) + CONFARGS += -Dplugin_flashrom=true + else + CONFARGS += -Dplugin_flashrom=false + endif + CONFARGS += -Defi_sbat_distro_id=debian + CONFARGS += -Defi_sbat_distro_summary=Debian + CONFARGS += -Defi_sbat_distro_pkgname=fwupd + CONFARGS += -Defi_sbat_distro_version=$(deb_version) + CONFARGS += -Defi_sbat_distro_url="https://tracker.debian.org/pkg/fwupd" +endif + +ifeq (yes,$(shell pkg-config --exists libsmbios_c && echo yes)) + CONFARGS += -Dplugin_dell=true +else + CONFARGS += -Dplugin_dell=false +endif + +ifeq (yes,$(shell pkg-config --exists efivar && echo yes)) + CONFARGS += -Dplugin_uefi_capsule=true +else + CONFARGS += -Dplugin_uefi_capsule=false +endif + +ifneq ($(filter $(DEB_HOST_ARCH_CPU),i386 amd64),) + CONFARGS += -Dplugin_msr=true +else + CONFARGS += -Dplugin_msr=false +endif + +ifneq ($(QUBES_OPTION),) + CONFARGS += -Dqubes=true +endif + +CONFARGS += -Dplugin_dummy=true -Dgtkdoc=true -Dsupported_build=true + +%: + dh $@ --with gir + +override_dh_auto_clean: + rm -fr obj-* + rm -fr debian/build +ifeq (ubuntu,$(SB_STYLE)) + rm -rf debian/fwupd-images +endif + +override_dh_auto_configure: + dh_auto_configure -- $(CONFARGS) + +override_dh_install: + find debian/tmp/usr -type f -name "*a" -print | xargs rm -f + sed -i 's,wheel,sudo,' debian/tmp/usr/share/polkit-1/rules.d/org.freedesktop.fwupd.rules + dh_install + #install the EFI binaries if needed + [ ! -d debian/tmp/usr/libexec/fwupd/efi/ ] || dh_install -pfwupd usr/libexec/fwupd/efi + #install MSR conf if needed (depending on distro) + [ ! -d debian/tmp/usr/lib/modules-load.d ] || dh_install -pfwupd usr/lib/modules-load.d + [ ! -d debian/tmp/lib/modules-load.d ] || dh_install -pfwupd lib/modules-load.d + dh_missing -a --fail-missing + + #this is placed in fwupd-tests + rm -f debian/fwupd/usr/lib/*/fwupd-plugins-3/libfu_plugin_test.so + rm -f debian/fwupd/usr/lib/*/fwupd-plugins-3/libfu_plugin_test_ble.so + rm -f debian/fwupd/usr/lib/*/fwupd-plugins-3/libfu_plugin_invalid.so + rm -f debian/fwupd/etc/fwupd/remotes.d/fwupd-tests.conf + +ifeq (debian,$(SB_STYLE)) + # Generate the template source for the Debian signing service to use + mkdir -p $(TMPLDIR)/source-template/debian + cp -a debian/signing-template/* $(TMPLDIR)/source-template/debian + cp debian/README.Debian $(TMPLDIR)/source-template/debian + find $(TMPLDIR)/source-template/debian -type f | xargs sed -i "s,SIGNARCH,$(DEB_HOST_ARCH)," + find $(TMPLDIR)/source-template/debian -type f | xargs sed -i "s,SIGNVERSION,$(deb_version)," + set -e; for file in $$(find $(TMPLDIR)/source-template/debian -type f -name '*SIGNARCH*'); do \ + file1=$$(echo $$file | sed "s,SIGNARCH,$(DEB_HOST_ARCH),"); \ + mv -v $$file $$file1; \ + done + install -m 0755 debian/fwupd.postinst $(TMPLDIR)/source-template/debian/fwupd-$(DEB_HOST_ARCH)-signed.postinst + install -m 0755 debian/fwupd.postrm $(TMPLDIR)/source-template/debian/fwupd-$(DEB_HOST_ARCH)-signed.postrm + debian/gen_signing_changelog $(TMPLDIR)/source-template/debian fwupd $(DEB_HOST_ARCH) + debian/gen_signing_json $(TMPLDIR) fwupd ${DEB_HOST_ARCH} +endif + +override_dh_strip_nondeterminism: + dh_strip_nondeterminism -Xfirmware-example.xml.gz + +ifneq (yes,$(shell command -v valgrind >/dev/null 2>&1 && echo yes)) +override_dh_auto_test: + : +endif + +override_dh_builddeb: + dh_builddeb +ifeq (ubuntu,$(SB_STYLE)) + set -e; if [ -d debian/tmp/usr/libexec/fwupd/efi/ ]; then \ + mkdir -p debian/fwupd-images/$(deb_version); \ + cp debian/tmp/usr/libexec/fwupd/efi/fwupd*.efi debian/fwupd-images/$(deb_version); \ + echo $(deb_version) > debian/fwupd-images/$(deb_version)/version; \ + tar -C debian/fwupd-images -czvf ../$(tar_name) .; \ + dpkg-distaddfile $(tar_name) raw-uefi -; \ + fi +endif diff -Nru fwupd-1.4.5/contrib/debian/signing-template/changelog.in fwupd-1.5.8/contrib/debian/signing-template/changelog.in --- fwupd-1.4.5/contrib/debian/signing-template/changelog.in 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/signing-template/changelog.in 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,5 @@ +fwupd-SIGNARCH-signed (1) unstable; urgency=medium + + * Add template source package for signing + + -- Steve McIntyre <93sam@debian.org> Sat, 07 Apr 2018 12:44:55 +0100 diff -Nru fwupd-1.4.5/contrib/debian/signing-template/compat fwupd-1.5.8/contrib/debian/signing-template/compat --- fwupd-1.4.5/contrib/debian/signing-template/compat 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/signing-template/compat 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +9 diff -Nru fwupd-1.4.5/contrib/debian/signing-template/control fwupd-1.5.8/contrib/debian/signing-template/control --- fwupd-1.4.5/contrib/debian/signing-template/control 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/signing-template/control 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,27 @@ +Source: fwupd-SIGNARCH-signed +Priority: optional +Maintainer: Debian EFI +Uploaders: Steve McIntyre <93sam@debian.org>, + Matthias Klumpp , + Mario Limonciello +Build-Depends: debhelper (>= 9.0.0), sbsigntool [amd64 arm64 armhf i386], fwupd (= SIGNVERSION) [SIGNARCH] +Standards-Version: 4.1.3 +Section: libs +Homepage: https://github.com/fwupd/fwupd +Vcs-Git: https://salsa.debian.org/efi-team/fwupd.git +Vcs-Browser: https://salsa.debian.org/efi-team/fwupd + +Package: fwupd-SIGNARCH-signed +Section: admin +Architecture: SIGNARCH +Provides: fwupd-signed +Depends: ${shlibs:Depends}, ${misc:Depends}, fwupd (= SIGNVERSION) +Built-Using: fwupd (= SIGNVERSION) +Description: Tools to manage UEFI firmware updates (signed) + fwupd provides functionality to update system firmware. It has been + initially designed to update firmware using UEFI capsule updates, but + it is designed to be extensible to other firmware update standards. + . + This package contains just the signed version of the fwupd binary, + needed if your system has UEFI Secure Boot enabled. It depends on the + normal fwupd package for everything else. diff -Nru fwupd-1.4.5/contrib/debian/signing-template/copyright fwupd-1.5.8/contrib/debian/signing-template/copyright --- fwupd-1.4.5/contrib/debian/signing-template/copyright 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/signing-template/copyright 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,33 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: fwupd +Source: https://github.com/fwupd/fwupd + +Files: * +Copyright: 2015 Richard Hughes +License: LGPL-2.1+ + +Files: data/tests/colorhug/firmware.metainfo.xml +Copyright: 2015 Richard Hughes +License: CC0-1.0 + +Files: debian/* +Copyright: 2015 Daniel Jared Dominguez + 2015 Mario Limonciello +License: LGPL-2.1+ + +License: LGPL-2.1+ + This package is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + . + This package is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + . + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see + . + On Debian systems, the complete text of the GNU Lesser General + Public License version 2.1 can be found in "/usr/share/common-licenses/LGPL-2.1". diff -Nru fwupd-1.4.5/contrib/debian/signing-template/fwupd-SIGNARCH-signed.install fwupd-1.5.8/contrib/debian/signing-template/fwupd-SIGNARCH-signed.install --- fwupd-1.4.5/contrib/debian/signing-template/fwupd-SIGNARCH-signed.install 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/signing-template/fwupd-SIGNARCH-signed.install 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +*.efi.signed /usr/libexec/fwupd/efi diff -Nru fwupd-1.4.5/contrib/debian/signing-template/README.source fwupd-1.5.8/contrib/debian/signing-template/README.source --- fwupd-1.4.5/contrib/debian/signing-template/README.source 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/signing-template/README.source 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,4 @@ +This source package is generated by the Debian signing service from a +template built by the fwupd package. It should never be updated directly. + + -- Steve McIntyre <93sam@debian.org> Sat, 07 Apr 2018 12:44:55 +0100 diff -Nru fwupd-1.4.5/contrib/debian/signing-template/rules fwupd-1.5.8/contrib/debian/signing-template/rules --- fwupd-1.4.5/contrib/debian/signing-template/rules 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/signing-template/rules 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,15 @@ +#!/usr/bin/make -f +# -*- makefile -*- + +PACKAGE_NAME := fwupd +SIG_PKG_NAME := fwupd-SIGNARCH-signed +SIGNATURE_DIR := debian/signatures/$(PACKAGE_NAME) +BINARY := $(shell find /usr/libexec/fwupd/efi -name '*.efi' | xargs basename) + +%: + dh $@ + +override_dh_auto_build: + cp /usr/libexec/fwupd/efi/$(BINARY) . + sbattach --attach $(SIGNATURE_DIR)/usr/libexec/fwupd/efi/$(BINARY).sig $(BINARY) + mv $(BINARY) $(BINARY).signed diff -Nru fwupd-1.4.5/contrib/debian/signing-template/source/format fwupd-1.5.8/contrib/debian/signing-template/source/format --- fwupd-1.4.5/contrib/debian/signing-template/source/format 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/signing-template/source/format 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +3.0 (native) diff -Nru fwupd-1.4.5/contrib/debian/source/format fwupd-1.5.8/contrib/debian/source/format --- fwupd-1.4.5/contrib/debian/source/format 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/source/format 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +3.0 (quilt) diff -Nru fwupd-1.4.5/contrib/debian/source/include-binaries fwupd-1.5.8/contrib/debian/source/include-binaries --- fwupd-1.4.5/contrib/debian/source/include-binaries 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/source/include-binaries 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +debian/binary-patches/example.elf diff -Nru fwupd-1.4.5/contrib/debian/source/lintian-overrides fwupd-1.5.8/contrib/debian/source/lintian-overrides --- fwupd-1.4.5/contrib/debian/source/lintian-overrides 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/source/lintian-overrides 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,2 @@ +#github doesn't have these +fwupd source: debian-watch-does-not-check-gpg-signature diff -Nru fwupd-1.4.5/contrib/debian/source/options fwupd-1.5.8/contrib/debian/source/options --- fwupd-1.4.5/contrib/debian/source/options 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/source/options 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +extend-diff-ignore=".vscode" diff -Nru fwupd-1.4.5/contrib/debian/tests/ci fwupd-1.5.8/contrib/debian/tests/ci --- fwupd-1.4.5/contrib/debian/tests/ci 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/tests/ci 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,5 @@ +#!/bin/sh +set -e +sed "s,^DisabledPlugins=.*,DisabledPlugins=," -i /etc/fwupd/daemon.conf +sed "s,^VerboseDomains=.*,VerboseDomains=*," -i /etc/fwupd/daemon.conf +gnome-desktop-testing-runner fwupd diff -Nru fwupd-1.4.5/contrib/debian/tests/control fwupd-1.5.8/contrib/debian/tests/control --- fwupd-1.4.5/contrib/debian/tests/control 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/tests/control 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,6 @@ +Tests: ci +Restrictions: needs-root + +Tests: libfwupd-dev +Depends: build-essential, libfwupd-dev, pkg-config +Restrictions: allow-stderr, superficial diff -Nru fwupd-1.4.5/contrib/debian/tests/libfwupd-dev fwupd-1.5.8/contrib/debian/tests/libfwupd-dev --- fwupd-1.4.5/contrib/debian/tests/libfwupd-dev 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/tests/libfwupd-dev 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,38 @@ +#!/bin/sh +# Copyright 2020 Collabora Ltd. +# Copyright 2021 Simon McVittie +# SPDX-License-Identifier: LGPL-2.1-or-later + +set -eux + +WORKDIR="$(mktemp -d)" +trap 'cd /; rm -fr "$WORKDIR"' 0 INT QUIT ABRT PIPE TERM + +if [ -n "${DEB_HOST_GNU_TYPE:-}" ]; then + CROSS_COMPILE="$DEB_HOST_GNU_TYPE-" +else + CROSS_COMPILE= +fi + +CC="${CROSS_COMPILE}gcc" +PKG_CONFIG="${CROSS_COMPILE}pkg-config" + +cd "$WORKDIR" + +cat > trivial.c <<'EOF' +#undef NDEBUG +#include + +#include + +int main (void) +{ + assert (fwupd_error_to_string (FWUPD_ERROR_NOTHING_TO_DO) != NULL); + return 0; +} +EOF + +# Deliberately word-splitting pkg-config's output: +# shellcheck disable=SC2046 +"${CC}" -otrivial trivial.c $("${PKG_CONFIG}" --cflags --libs fwupd) +./trivial diff -Nru fwupd-1.4.5/contrib/debian/watch fwupd-1.5.8/contrib/debian/watch --- fwupd-1.4.5/contrib/debian/watch 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/debian/watch 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,6 @@ +# You can run the "uscan" command to check for upstream updates and more. +# See uscan(1) for format + +version=3 +opts=filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/fwupd-$1\.tar\.gz/ \ +https://github.com/fwupd/fwupd/tags .*/v?(\d\S*)\.tar\.gz diff -Nru fwupd-1.4.5/contrib/firmware_packager/firmware_packager.py fwupd-1.5.8/contrib/firmware_packager/firmware_packager.py --- fwupd-1.4.5/contrib/firmware_packager/firmware_packager.py 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/contrib/firmware_packager/firmware_packager.py 2021-03-31 20:08:32.000000000 +0000 @@ -1,6 +1,6 @@ #!/usr/bin/python3 # -# Copyright (C) 2017 Max Ehrlich max.ehr@gmail.com +# Copyright (C) 2017 Max Ehrlich maxehr@gmail.com # # SPDX-License-Identifier: LGPL-2.1+ # @@ -107,7 +107,7 @@ print('Creating metainfo') make_firmware_metainfo(args, dir) - print('Cabbing firmware files') + print('Creating cabinet file') create_firmware_cab(args, dir) print('Done') diff -Nru fwupd-1.4.5/contrib/firmware_packager/install_dell_bios_exe.py fwupd-1.5.8/contrib/firmware_packager/install_dell_bios_exe.py --- fwupd-1.4.5/contrib/firmware_packager/install_dell_bios_exe.py 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/contrib/firmware_packager/install_dell_bios_exe.py 2021-03-31 20:08:32.000000000 +0000 @@ -10,7 +10,11 @@ import tempfile import gi -gi.require_version('Fwupd', '2.0') +try: + gi.require_version('Fwupd', '2.0') +except ValueError: + print("Missing gobject-introspection packages. Try to install gir1.2-fwupd-2.0.") + sys.exit(1) from gi.repository import Fwupd # pylint: disable=wrong-import-position from simple_client import install, check_exists from add_capsule_header import add_header @@ -68,7 +72,7 @@ if not item.has_flag(1 << 8): continue # return the first hit for UEFI plugin - if item.get_plugin() == 'uefi': + if item.get_plugin() == 'uefi' or item.get_plugin() == 'uefi_capsule': print("Installing to %s" % item.get_name()) return item.get_guid_default(), item.get_id(), item.get_version() print("Couldn't find any UEFI devices") diff -Nru fwupd-1.4.5/contrib/firmware_packager/meson.build fwupd-1.5.8/contrib/firmware_packager/meson.build --- fwupd-1.4.5/contrib/firmware_packager/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/contrib/firmware_packager/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,10 +1,17 @@ if get_option('firmware-packager') install_data('firmware_packager.py', install_dir : 'share/fwupd') - install_data('simple_client.py', - install_dir : 'share/fwupd') install_data('add_capsule_header.py', install_dir : 'share/fwupd') install_data('install_dell_bios_exe.py', install_dir : 'share/fwupd') + con2 = configuration_data() + con2.set('FWUPD_VERSION', fwupd_version) + configure_file( + input : 'simple_client.py', + output : 'simple_client.py', + configuration : con2, + install: true, + install_dir: 'share/fwupd', + ) endif diff -Nru fwupd-1.4.5/contrib/firmware_packager/simple_client.py fwupd-1.5.8/contrib/firmware_packager/simple_client.py --- fwupd-1.4.5/contrib/firmware_packager/simple_client.py 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/contrib/firmware_packager/simple_client.py 2021-03-31 20:08:32.000000000 +0000 @@ -62,7 +62,9 @@ help="Reinstall payloads(default False)", ) parser.add_argument( - "command", choices=["get-devices", "get-details", "install"], help="What to do" + "command", + choices=["get-devices", "get-details", "install", "refresh"], + help="What to do", ) parser.add_argument('cab', nargs='?', help='CAB file') parser.add_argument('deviceid', nargs='?', help='DeviceID to operate on(optional)') @@ -70,6 +72,18 @@ return args +def refresh(client): + """Uses fwupd client to refresh metadata""" + remotes = client.get_remotes() + client.set_user_agent_for_package("simple_client", "@FWUPD_VERSION@") + for remote in remotes: + if not remote.get_enabled(): + continue + if remote.get_kind() != Fwupd.RemoteKind.DOWNLOAD: + continue + client.refresh_remote(remote) + + def get_devices(client): """Use fwupd client to fetch devices""" devices = client.get_devices() @@ -140,6 +154,8 @@ elif ARGS.command == "get-details": check_exists(ARGS.cab) get_details(CLIENT, ARGS.cab) + elif ARGS.command == "refresh": + refresh(CLIENT) elif ARGS.command == "install": check_exists(ARGS.cab) install(CLIENT, ARGS.cab, ARGS.deviceid, ARGS.allow_older, ARGS.allow_reinstall) diff -Nru fwupd-1.4.5/contrib/fwupd.spec.in fwupd-1.5.8/contrib/fwupd.spec.in --- fwupd-1.4.5/contrib/fwupd.spec.in 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/contrib/fwupd.spec.in 2021-03-31 20:08:32.000000000 +0000 @@ -1,7 +1,7 @@ %global glib2_version 2.45.8 %global libxmlb_version 0.1.3 -%global libgusb_version 0.2.11 -%global libsoup_version 2.51.92 +%global libgusb_version 0.3.5 +%global libcurl_version 7.61.0 %global libjcat_version 0.1.0 %global systemd_version 231 %global json_glib_version 1.1.1 @@ -22,9 +22,13 @@ %global have_uefi 1 %endif -# redfish is only available on this arch -%ifarch x86_64 -%global have_redfish 1 +# flashrom is only available on these arches +%ifarch i686 x86_64 armv7hl aarch64 ppc64le +%global have_flashrom 1 +%endif + +%ifarch i686 x86_64 +%global have_msr 1 %endif # libsmbios is only available on x86 @@ -51,11 +55,12 @@ BuildRequires: libgcab1-devel BuildRequires: libgudev1-devel BuildRequires: libgusb-devel >= %{libgusb_version} -BuildRequires: libsoup-devel >= %{libsoup_version} +BuildRequires: libcurl-devel >= %{libcurl_version} BuildRequires: libjcat-devel >= %{libjcat_version} BuildRequires: polkit-devel >= 0.103 BuildRequires: sqlite-devel BuildRequires: systemd >= %{systemd_version} +BuildRequires: systemd-devel BuildRequires: libarchive-devel BuildRequires: gobject-introspection-devel BuildRequires: gcab @@ -73,17 +78,15 @@ BuildRequires: vala BuildRequires: bash-completion BuildRequires: git-core +%if 0%{?have_flashrom} BuildRequires: flashrom-devel >= 1.2-2 +%endif %if 0%{?have_modem_manager} BuildRequires: ModemManager-glib-devel >= 1.10.0 BuildRequires: libqmi-devel >= 1.22.0 %endif -%if 0%{?have_redfish} -BuildRequires: efivar-devel >= 33 -%endif - %if 0%{?have_uefi} BuildRequires: efivar-devel >= 33 BuildRequires: python3 python3-cairo python3-gobject python3-pillow @@ -109,7 +112,6 @@ Requires: glib2%{?_isa} >= %{glib2_version} Requires: libxmlb%{?_isa} >= %{libxmlb_version} Requires: libgusb%{?_isa} >= %{libgusb_version} -Requires: libsoup%{?_isa} >= %{libsoup_version} Requires: bubblewrap Requires: shared-mime-info @@ -122,6 +124,9 @@ Obsoletes: libdfu < 1.0.0 Obsoletes: fwupd-labels < 1.1.0-1 +Obsoletes: dbxtool < 9 +Provides: dbxtool + %if 0%{?rhel} > 7 Obsoletes: fwupdate < 11-4 Obsoletes: fwupdate-efi < 11-4 @@ -130,6 +135,20 @@ Provides: fwupdate-efi %endif +# optional, but a really good idea +Recommends: udisks2 +Recommends: bluez + +%if 0%{?have_modem_manager} +Recommends: %{name}-plugin-modem-manager +%endif +%if 0%{?have_flashrom} +Recommends: %{name}-plugin-flashrom +%endif +%if 0%{?have_uefi} +Recommends: %{name}-plugin-uefi-capsule-data +%endif + %description fwupd is a daemon to allow session software to update device firmware. @@ -144,11 +163,59 @@ %package tests Summary: Data files for installed tests -BuildArch: noarch %description tests Data files for installed tests. +%if 0%{?have_modem_manager} +%package plugin-modem-manager +Summary: fwupd plugin using ModemManger + +%description plugin-modem-manager +This provides the optional package which is only required on hardware that +might have mobile broadband hardware. It is probably not required on servers. +%endif + +%if 0%{?have_flashrom} +%package plugin-flashrom +Summary: fwupd plugin using flashrom + +%description plugin-flashrom +This provides the optional package which is only required on hardware that +can be flashed using flashrom. It is probably not required on servers. +%endif + +%if 0%{?have_uefi} +%package plugin-uefi-capsule-data +Summary: Localized data for the UEFI UX capsule + +%description plugin-uefi-capsule-data +This provides the pregenerated BMP artwork for the UX capsule, which allows the +"Installing firmware update…" localized text to be shown during a UEFI firmware +update operation. This subpackage is probably not required on embedded hardware +or server machines. +%endif + +%if 0%{?qubes_packages} +%package qubes-dom0 +Summary: fwupd wrapper for Qubes OS - dom0 scripts +Requires: gcab +Requires: fwupd >= 1.5.7 +Requires: libjcat >= 0.1.6 + +%description qubes-dom0 +fwupd wrapper for Qubes OS + +%package qubes-vm +Summary: fwupd wrapper for Qubes OS - VM scripts +Requires: gcab +Requires: fwupd >= 1.5.7 +Requires: libjcat >= 0.1.6 + +%description qubes-vm +fwupd wrapper for Qubes OS +%endif + %prep %autosetup -p1 @@ -169,39 +236,56 @@ %else -Dplugin_dummy=false \ %endif +%if 0%{?have_flashrom} -Dplugin_flashrom=true \ - -Dplugin_thunderbolt=true \ -%if 0%{?have_redfish} - -Dplugin_redfish=true \ %else - -Dplugin_redfish=false \ + -Dplugin_flashrom=false \ +%endif +%if 0%{?have_msr} + -Dplugin_msr=true \ +%else + -Dplugin_msr=false \ %endif + -Dplugin_thunderbolt=true \ %if 0%{?have_uefi} - -Dplugin_uefi=true \ - -Dplugin_nvme=true \ + -Dplugin_uefi_capsule=true \ + -Dplugin_uefi_pk=true \ + -Defi_sbat_distro_id="fedora" \ + -Defi_sbat_distro_summary="The Fedora Project" \ + -Defi_sbat_distro_pkgname="%{name}" \ + -Defi_sbat_distro_version="%{version}" \ + -Defi_sbat_distro_url="https://src.fedoraproject.org/rpms/%{name}" \ -Dplugin_tpm=true \ %else - -Dplugin_uefi=false \ - -Dplugin_nvme=false \ + -Dplugin_uefi_capsule=false \ + -Dplugin_uefi_pk=false \ -Dplugin_tpm=false \ %endif %if 0%{?have_dell} -Dplugin_dell=true \ - -Dplugin_synaptics=true \ + -Dplugin_synaptics_mst=true \ %else -Dplugin_dell=false \ - -Dplugin_synaptics=false \ + -Dplugin_synaptics_mst=false \ %endif %if 0%{?have_modem_manager} -Dplugin_modem_manager=true \ %else -Dplugin_modem_manager=false \ %endif - -Dman=true +%if 0%{?qubes_packages} + -Dqubes=true \ +%endif + -Dman=true \ + -Dbluez=true \ + -Dsupported_build=true %meson_build %if 0%{?enable_tests} +%if 0%{?enable_ci} + ./contrib/ci/get_test_firmware.sh +%endif %check %meson_test %endif @@ -218,16 +302,29 @@ %global efiarch aa64 %endif %global fwup_efi_fn $RPM_BUILD_ROOT%{_libexecdir}/fwupd/efi/fwupd%{efiarch}.efi -%pesign -s -i %{fwup_efi_fn} -o %{fwup_efi_fn}.signed +%pesign -s -i %{fwup_efi_fn} -o %{fwup_efi_fn}.tmp +%define __pesign_client_cert fwupd-signer +%pesign -s -i %{fwup_efi_fn}.tmp -o %{fwup_efi_fn}.signed +rm -vf %{fwup_efi_fn}.tmp %endif mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg +# workaround for https://bugzilla.redhat.com/show_bug.cgi?id=1757948 +mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/cache/fwupd + %find_lang %{name} %post %systemd_post fwupd.service +# change vendor-installed remotes to use the default keyring type +for fn in /etc/fwupd/remotes.d/*.conf; do + if grep -q "Keyring=gpg" "$fn"; then + sed -i 's/Keyring=gpg/#Keyring=pkcs/g' "$fn"; + fi +done + %preun %systemd_preun fwupd.service @@ -238,18 +335,18 @@ %files -f %{name}.lang %doc README.md AUTHORS %license COPYING -%config(noreplace)%{_sysconfdir}/fwupd/ata.conf %config(noreplace)%{_sysconfdir}/fwupd/daemon.conf %config(noreplace)%{_sysconfdir}/fwupd/upower.conf %if 0%{?have_uefi} -%config(noreplace)%{_sysconfdir}/fwupd/uefi.conf +%config(noreplace)%{_sysconfdir}/fwupd/uefi_capsule.conf %endif -%if 0%{?have_redfish} %config(noreplace)%{_sysconfdir}/fwupd/redfish.conf -%endif %config(noreplace)%{_sysconfdir}/fwupd/thunderbolt.conf %dir %{_libexecdir}/fwupd %{_libexecdir}/fwupd/fwupd +%ifarch i686 x86_64 +%{_libexecdir}/fwupd/fwupd-detect-cet +%endif %{_libexecdir}/fwupd/fwupdoffline %if 0%{?have_uefi} %{_libexecdir}/fwupd/efi/*.efi @@ -258,6 +355,9 @@ %{_bindir}/fwupdtpmevlog %endif %{_bindir}/dfu-tool +%if 0%{?have_uefi} +%{_bindir}/dbxtool +%endif %{_bindir}/fwupdmgr %{_bindir}/fwupdtool %{_bindir}/fwupdagent @@ -272,6 +372,9 @@ %config(noreplace)%{_sysconfdir}/fwupd/remotes.d/vendor-directory.conf %config(noreplace)%{_sysconfdir}/pki/fwupd %{_sysconfdir}/pki/fwupd-metadata +%if 0%{?have_msr} +/usr/lib/modules-load.d/fwupd-msr.conf +%endif %{_datadir}/dbus-1/system.d/org.freedesktop.fwupd.conf %{_datadir}/bash-completion/completions/fwupdmgr %{_datadir}/bash-completion/completions/fwupdtool @@ -286,13 +389,16 @@ %{_datadir}/polkit-1/actions/org.freedesktop.fwupd.policy %{_datadir}/polkit-1/rules.d/org.freedesktop.fwupd.rules %{_datadir}/dbus-1/system-services/org.freedesktop.fwupd.service -%{_datadir}/man/man1/fwupdtool.1.gz -%{_datadir}/man/man1/fwupdagent.1.gz -%{_datadir}/man/man1/dfu-tool.1.gz -%{_datadir}/man/man1/fwupdmgr.1.gz +%{_mandir}/man1/fwupdtool.1* +%{_mandir}/man1/fwupdagent.1* +%{_mandir}/man1/dfu-tool.1* %if 0%{?have_uefi} -%{_datadir}/man/man1/fwupdate.1.gz -%{_datadir}/man/man1/fwupdtpmevlog.1.gz +%{_mandir}/man1/dbxtool.* +%endif +%{_mandir}/man1/fwupdmgr.1* +%if 0%{?have_uefi} +%{_mandir}/man1/fwupdate.1* +%{_mandir}/man1/fwupdtpmevlog.1* %endif %{_datadir}/metainfo/org.freedesktop.fwupd.metainfo.xml %{_datadir}/icons/hicolor/scalable/apps/org.freedesktop.fwupd.svg @@ -307,6 +413,7 @@ %{_presetdir}/fwupd-refresh.preset %{_unitdir}/system-update.target.wants/ %dir %{_localstatedir}/lib/fwupd +%dir %{_localstatedir}/cache/fwupd %dir %{_datadir}/fwupd/quirks.d %{_datadir}/fwupd/quirks.d/*.quirk %{_localstatedir}/lib/fwupd/builder/README.md @@ -316,13 +423,15 @@ /usr/lib/udev/rules.d/*.rules /usr/lib/systemd/system-shutdown/fwupd.shutdown %dir %{_libdir}/fwupd-plugins-3 +%{_libdir}/fwupd-plugins-3/libfu_plugin_acpi_dmar.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_acpi_facp.so %{_libdir}/fwupd-plugins-3/libfu_plugin_altos.so %{_libdir}/fwupd-plugins-3/libfu_plugin_amt.so %{_libdir}/fwupd-plugins-3/libfu_plugin_ata.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_bcm57xx.so %{_libdir}/fwupd-plugins-3/libfu_plugin_ccgx.so %{_libdir}/fwupd-plugins-3/libfu_plugin_colorhug.so -%{_libdir}/fwupd-plugins-3/libfu_plugin_coreboot.so -%{_libdir}/fwupd-plugins-3/libfu_plugin_csr.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_cros_ec.so %{_libdir}/fwupd-plugins-3/libfu_plugin_cpu.so %if 0%{?have_dell} %{_libdir}/fwupd-plugins-3/libfu_plugin_dell.so @@ -330,24 +439,30 @@ %endif %{_libdir}/fwupd-plugins-3/libfu_plugin_dell_dock.so %{_libdir}/fwupd-plugins-3/libfu_plugin_dfu.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_dfu_csr.so %{_libdir}/fwupd-plugins-3/libfu_plugin_ebitdo.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_elantp.so %{_libdir}/fwupd-plugins-3/libfu_plugin_emmc.so %{_libdir}/fwupd-plugins-3/libfu_plugin_ep963x.so %{_libdir}/fwupd-plugins-3/libfu_plugin_fastboot.so -%{_libdir}/fwupd-plugins-3/libfu_plugin_flashrom.so %{_libdir}/fwupd-plugins-3/libfu_plugin_fresco_pd.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_hailuck.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_iommu.so %{_libdir}/fwupd-plugins-3/libfu_plugin_jabra.so -%if 0%{?have_modem_manager} -%{_libdir}/fwupd-plugins-3/libfu_plugin_modem_manager.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_linux_lockdown.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_linux_sleep.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_linux_swap.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_linux_tainted.so +%if 0%{?have_msr} +%{_libdir}/fwupd-plugins-3/libfu_plugin_msr.so %endif %{_libdir}/fwupd-plugins-3/libfu_plugin_nitrokey.so -%if 0%{?have_uefi} %{_libdir}/fwupd-plugins-3/libfu_plugin_nvme.so -%endif %{_libdir}/fwupd-plugins-3/libfu_plugin_optionrom.so -%if 0%{?have_redfish} +%{_libdir}/fwupd-plugins-3/libfu_plugin_pci_bcr.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_pci_mei.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_pixart_rf.so %{_libdir}/fwupd-plugins-3/libfu_plugin_redfish.so -%endif %{_libdir}/fwupd-plugins-3/libfu_plugin_rts54hid.so %{_libdir}/fwupd-plugins-3/libfu_plugin_rts54hub.so %{_libdir}/fwupd-plugins-3/libfu_plugin_solokey.so @@ -362,6 +477,7 @@ %{_libdir}/fwupd-plugins-3/libfu_plugin_system76_launch.so %if 0%{?enable_dummy} %{_libdir}/fwupd-plugins-3/libfu_plugin_test.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_test_ble.so %{_libdir}/fwupd-plugins-3/libfu_plugin_invalid.so %endif %{_libdir}/fwupd-plugins-3/libfu_plugin_thelio_io.so @@ -369,7 +485,10 @@ %if 0%{?have_uefi} %{_libdir}/fwupd-plugins-3/libfu_plugin_tpm.so %{_libdir}/fwupd-plugins-3/libfu_plugin_tpm_eventlog.so -%{_libdir}/fwupd-plugins-3/libfu_plugin_uefi.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_bios.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_uefi_capsule.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_uefi_dbx.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_uefi_pk.so %{_libdir}/fwupd-plugins-3/libfu_plugin_uefi_recovery.so %endif %{_libdir}/fwupd-plugins-3/libfu_plugin_logind.so @@ -378,9 +497,20 @@ %{_libdir}/fwupd-plugins-3/libfu_plugin_vli.so %{_libdir}/fwupd-plugins-3/libfu_plugin_wacom_raw.so %{_libdir}/fwupd-plugins-3/libfu_plugin_wacom_usb.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_goodixmoc.so %ghost %{_localstatedir}/lib/fwupd/gnupg + +%if 0%{?have_modem_manager} +%files plugin-modem-manager +%{_libdir}/fwupd-plugins-3/libfu_plugin_modem_manager.so +%endif +%if 0%{?have_flashrom} +%files plugin-flashrom +%{_libdir}/fwupd-plugins-3/libfu_plugin_flashrom.so +%endif %if 0%{?have_uefi} -%{_datadir}/locale/*/LC_IMAGES/fwupd* +%files plugin-uefi-capsule-data +%{_datadir}/fwupd/uefi-capsule-ux.tar.xz %endif %files devel @@ -394,13 +524,40 @@ %{_libdir}/pkgconfig/fwupdplugin.pc %files tests +%if 0%{?enable_tests} %dir %{_datadir}/installed-tests/fwupd %{_datadir}/installed-tests/fwupd/fwupd-tests.xml %{_datadir}/installed-tests/fwupd/*.test %{_datadir}/installed-tests/fwupd/*.cab %{_datadir}/installed-tests/fwupd/*.sh +%{_libexecdir}/installed-tests/fwupd/* %dir %{_sysconfdir}/fwupd/remotes.d %config(noreplace)%{_sysconfdir}/fwupd/remotes.d/fwupd-tests.conf +%endif + +%if 0%{?qubes_packages} +%files qubes-vm +%{_libexecdir}/qubes-fwupd/fwupd_common_vm.py +%{_libexecdir}/qubes-fwupd/fwupd_download_updates.py +%{_libexecdir}/qubes-fwupd/fwupd_usbvm_validate.py + +%files qubes-dom0 +%{_datadir}/qubes-fwupd/src/fwupd_receive_updates.py +/usr/sbin/qubes-fwupdmgr +%{_datadir}/qubes-fwupd/src/qubes_fwupd_heads.py +%{_datadir}/qubes-fwupd/src/qubes_fwupd_update.py +%{_datadir}/qubes-fwupd/src/__init__.py +%{_datadir}/qubes-fwupd/test/fwupd_logs.py +%{_datadir}/qubes-fwupd/test/test_qubes_fwupdmgr.py +%{_datadir}/qubes-fwupd/test/test_qubes_fwupd_heads.py +%{_datadir}/qubes-fwupd/test/__init__.py +%{_datadir}/qubes-fwupd/test/logs/get_devices.log +%{_datadir}/qubes-fwupd/test/logs/get_updates.log +%{_datadir}/qubes-fwupd/test/logs/help.log +%{_datadir}/qubes-fwupd/test/logs/firmware.metainfo.xml +%{_datadir}/qubes-fwupd/test/logs/metainfo_name/firmware.metainfo.xml +%{_datadir}/qubes-fwupd/test/logs/metainfo_version/firmware.metainfo.xml +%endif %changelog * #LONGDATE# Richard Hughes #VERSION#-0.#BUILD##ALPHATAG# diff -Nru fwupd-1.4.5/contrib/generate-version-script.py fwupd-1.5.8/contrib/generate-version-script.py --- fwupd-1.4.5/contrib/generate-version-script.py 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/contrib/generate-version-script.py 2021-03-31 20:08:32.000000000 +0000 @@ -6,6 +6,7 @@ # SPDX-License-Identifier: LGPL-2.1+ import sys +import argparse import xml.etree.ElementTree as ET from pkg_resources import parse_version @@ -30,6 +31,7 @@ def __init__(self, library_name): self.library_name = library_name self.releases = {} + self.overrides = {} def _add_node(self, node): identifier = node.attrib[XMLNS_C + 'identifier'] @@ -56,9 +58,6 @@ # choose the lowest version method for the _get_type symbol version_lowest = None - if '{http://www.gtk.org/introspection/glib/1.0}get-type' not in cls.attrib: - return - type_name = cls.attrib['{http://www.gtk.org/introspection/glib/1.0}get-type'] # add all class methods for node in cls.findall(XMLNS + 'method'): @@ -78,9 +77,14 @@ ): version_lowest = version_tmp + if '{http://www.gtk.org/introspection/glib/1.0}get-type' not in cls.attrib: + return + type_name = cls.attrib['{http://www.gtk.org/introspection/glib/1.0}get-type'] + # finally add the get_type symbol - if version_lowest: - self.releases[version_lowest].append(type_name) + version = self.overrides.get(type_name, version_lowest) + if version: + self.releases[version].append(type_name) def import_gir(self, filename): tree = ET.parse(filename) @@ -119,11 +123,22 @@ if __name__ == '__main__': - if {'-?', '--help', '--usage'}.intersection(set(sys.argv)): - usage(0) - if len(sys.argv) != 4: + + parser = argparse.ArgumentParser() + parser.add_argument( + '-r', + '--override', + action='append', + nargs=2, + metavar=('symbol', 'version'), + ) + args, argv = parser.parse_known_args() + if len(argv) != 3: usage(1) - ld = LdVersionScript(library_name=sys.argv[1]) - ld.import_gir(sys.argv[2]) - open(sys.argv[3], 'w').write(ld.render()) + ld = LdVersionScript(library_name=argv[0]) + if args.override: + for override_symbol, override_version in args.override: + ld.overrides[override_symbol] = override_version + ld.import_gir(argv[1]) + open(argv[2], 'w').write(ld.render()) diff -Nru fwupd-1.4.5/contrib/meson.build fwupd-1.5.8/contrib/meson.build --- fwupd-1.4.5/contrib/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/contrib/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,4 +1,7 @@ subdir('firmware_packager') +if get_option('qubes') + subdir('qubes') +endif if host_machine.system() == 'windows' con2 = configuration_data() diff -Nru fwupd-1.4.5/contrib/nvme-parse.py fwupd-1.5.8/contrib/nvme-parse.py --- fwupd-1.4.5/contrib/nvme-parse.py 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/contrib/nvme-parse.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,153 +0,0 @@ -#!/usr/bin/python3 -# SPDX-License-Identifier: LGPL-2.1+ - -import csv -import binascii -import os -import struct -import glob -from collections import namedtuple - - -class Record(object): - def __init__(self, filename, cns): - self.filename = filename - self.cns = cns - - -def load_pci_ids(): - pci_vendors = {} - pci_vendors[0x1987] = 'Freescale' - for ln in open('/usr/share/hwdata/pci.ids').read().split('\n'): - if ln.startswith('#'): - continue - if ln.startswith('\t'): - continue - data = ln.split(' ') - if len(data) != 2: - continue - pci_vendors[int(data[0], 16)] = data[1].split(' ')[0] - if data[0] == 'ffff': - break - return pci_vendors - - -def _data_to_utf8(s): - return s.decode('utf-8', 'replace').replace('\0', ' ') - - -def main(): - - # open files - records = [] - for fn in glob.glob('tests/nvme/*'): - blob = open(fn, 'rb').read() - if len(blob) != 4096: - print('WARNING: ignoring %s of size %i' % (fn, len(blob))) - continue - Cns = namedtuple( - 'Cns', - 'vid ssvid sn mn fr rab ieee cmic mdts cntlid ver ' - 'rtd3r rtd3e oaes ctratt rrls rsvd102 oacs acl aerl ' - 'frmw lpa elpe npss avscc apsta wctemp cctemp mtfa ' - 'hmpre hmmin tnvmcap unvmcap rpmbs edstt dsto fwug ' - 'kas hctma mntmt mxtmt sanicap hmminds hmmaxd ' - 'nsetidmax rsvd340 anatt anacap anagrpmax nanagrpid ' - 'rsvd352 sqes cqes maxcmd nn oncs fuses fna vwc awun ' - 'awupf nvscc nwpc acwu rsvd534 sgls mnan rsvd544 ' - 'subnqn rsvd1024 ioccsz iorcsz icdoff ctrattr msdbd ' - 'rsvd1804 psd vs', - ) - try: - cns = Cns._make( - struct.unpack( - ' 0: - s1ro_cnt += 1 - if (r.cns.frmw & 0x10) >> 4: - fawr_cnt += 1 - nfws = (r.cns.frmw & 0x0E) >> 1 - if nfws in nfws_map: - nfws_map[nfws] += 1 - continue - nfws_map[nfws] = 1 - print('s1ro=%i/%i' % (s1ro_cnt, len(records))) - print('fawr=%i/%i' % (fawr_cnt, len(records))) - nfws = sorted(nfws_map.items(), key=lambda k: k[0], reverse=True) - for nfws, cnt in nfws: - print('nfws[%i]=%i' % (nfws, cnt)) - - # vendor popularity - vids = {} - for r in records: - if r.cns.vid not in vids: - vids[r.cns.vid] = 1 - continue - vids[r.cns.vid] += 1 - vids = sorted(vids.items(), key=lambda k: k[1], reverse=True) - pci_vendors = load_pci_ids() - for vid, cnt in vids: - name = '0x%04x' % vid - if vid in pci_vendors: - name = pci_vendors[vid] - print('%s,%i' % (name, cnt)) - - # vendor records - vs_records = [] - for r in records: - if r.cns.vs: - vs_records.append(r) - print('nr_vs=%i' % len(vs_records)) - - -main() diff -Nru fwupd-1.4.5/contrib/PKGBUILD fwupd-1.5.8/contrib/PKGBUILD --- fwupd-1.4.5/contrib/PKGBUILD 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/contrib/PKGBUILD 2021-03-31 20:08:32.000000000 +0000 @@ -11,7 +11,7 @@ depends=('libgusb' 'modemmanager' 'tpm2-tss') makedepends=('meson' 'valgrind' 'gobject-introspection' 'gtk-doc' 'python-pillow' 'git' 'python-cairo' 'noto-fonts' 'noto-fonts-cjk' 'python-gobject' 'vala' - 'libsoup' 'polkit' 'gcab') + 'curl' 'polkit' 'gcab') pkgver() { cd ${pkgname} @@ -27,7 +27,13 @@ if [ -n "$CI" ]; then export CI="--wrap-mode=default" fi - arch-meson -D b_lto=false $CI ../build + arch-meson -D b_lto=false $CI ../build \ + -Defi_sbat_distro_id="arch" \ + -Defi_sbat_distro_summary="Arch Linux" \ + -Defi_sbat_distro_pkgname="${pkgname}" \ + -Defi_sbat_distro_version="${pkgver}" \ + -Defi_sbat_distro_url="https://archlinux.org/packages/community/x86_64/${pkgname}/" \ + -Dsupported_build=true ninja -v -C ../build } diff -Nru fwupd-1.4.5/contrib/qubes/doc/heads_update.md fwupd-1.5.8/contrib/qubes/doc/heads_update.md --- fwupd-1.4.5/contrib/qubes/doc/heads_update.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/qubes/doc/heads_update.md 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,65 @@ +# Heads update + +The Heads update was tested on the `Lenovo ThinkPad x230`. + +## Requirements + +You need to build and flash Heads ROM from the +[3mdeb fork](https://github.com/3mdeb/heads/tree/qubes-fwupd). +You will find there Heads ROMs for ThinkPad x230. + +## Update process + +ThinkPad x230 is now the only laptop that has Heads ROM in the custom LVFS +storage. Nevertheless, qubes-fwupd has already implemented a `device` flag, that +will allow updates for other hardware. + +At first run the qubes-fwupd Heads update. + +``` +sudo qubes-fwupdmgr update-heads --device=x230 +``` + +Press Y to reboot the device. + +In the main menu, choose `options` and then go to `Flash/Update the BIOS` + +![img](img/heads_options.jpg) + +Decide to retain or erase the settings. + +![img](img/heads_firmware_managment_menu.jpg) + +The tool will inform you that heads update has been detected in `/boot` +directory. If you will decide not to update, you will be asked to attach the +USB drive. + +![img](img/heads_detected.jpg) + +Select a ROM file. + +![img](img/heads_selecting_rom.jpg) + +Press yes to confirm the choice. The Heads update will begin. + + +![img](img/heads_flash_rom.jpg) + +Wait until the end of the update process. + +![img](img/heads_update_process.jpg) + +Press OK to reboot the system. + +![img](img/heads_success.jpg) + +## Test + +Change directory to `/usr/share/qubes-fwupd` and run test case with sudo +privileges. + +### Qubes OS R4.1 + +``` +# python3 -m unittest -v test.test_qubes_fwupd_heads +``` Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/contrib/qubes/doc/img/heads_detected.jpg and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/contrib/qubes/doc/img/heads_detected.jpg differ Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/contrib/qubes/doc/img/heads_firmware_managment_menu.jpg and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/contrib/qubes/doc/img/heads_firmware_managment_menu.jpg differ Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/contrib/qubes/doc/img/heads_flash_rom.jpg and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/contrib/qubes/doc/img/heads_flash_rom.jpg differ Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/contrib/qubes/doc/img/heads_options.jpg and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/contrib/qubes/doc/img/heads_options.jpg differ Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/contrib/qubes/doc/img/heads_selecting_rom.jpg and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/contrib/qubes/doc/img/heads_selecting_rom.jpg differ Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/contrib/qubes/doc/img/heads_success.jpg and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/contrib/qubes/doc/img/heads_success.jpg differ Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/contrib/qubes/doc/img/heads_update_process.jpg and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/contrib/qubes/doc/img/heads_update_process.jpg differ Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/contrib/qubes/doc/img/qubes_manager.png and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/contrib/qubes/doc/img/qubes_manager.png differ Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/contrib/qubes/doc/img/uefi_capsule_found.jpg and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/contrib/qubes/doc/img/uefi_capsule_found.jpg differ Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/contrib/qubes/doc/img/uefi_ME.jpg and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/contrib/qubes/doc/img/uefi_ME.jpg differ Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/contrib/qubes/doc/img/uefi_success.jpg and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/contrib/qubes/doc/img/uefi_success.jpg differ diff -Nru fwupd-1.4.5/contrib/qubes/doc/uefi_capsule_update.md fwupd-1.5.8/contrib/qubes/doc/uefi_capsule_update.md --- fwupd-1.4.5/contrib/qubes/doc/uefi_capsule_update.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/qubes/doc/uefi_capsule_update.md 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,47 @@ +# UEFI capsule update + +The qubes-fwupd handle the UEFI capsule update under several conditions. +The fwupd uses ESRT tables to read GUID, and that causes trouble when the OS +is running under a hypervisor. The Xen does not pass the ESRT tables to +paravirtualized dom0, so the Qubes is not able to provide sysfs information. +More information you can find it this thread: + +https://patchwork.kernel.org/patch/11715901/ + +## Requirements + +### Qubes OS + +You need Qubes R4.1 to use the UEFI capsule update. + +### Hardware + +Make sure that your hardware has available firmware updates in the [LVFS](https://fwupd.org/) + +## UEFI capsule update - downgrade + +UEFI capsule updates and downgrades were tested on DELL XPS 15 9560. + +``` +$ sudo qubes-fwupdmgr downgrade +``` + +## UEFI capsule update - update + +``` +$ sudo qubes-fwupdmgr update +``` + +## Update process + +### Capsule found + +![img](img/uefi_capsule_found.jpg) + +### ME updated + +![img](img/uefi_ME.jpg) + +### Success + +![img](img/uefi_success.jpg) diff -Nru fwupd-1.4.5/contrib/qubes/doc/whonix.md fwupd-1.5.8/contrib/qubes/doc/whonix.md --- fwupd-1.4.5/contrib/qubes/doc/whonix.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/qubes/doc/whonix.md 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,24 @@ +# Whonix support + +The qubes-fwupd uses the sys-whonix VM as the update VM to handle downloading +updates and metadata via Tor. The tests detect if sys-whonix is running, but +do not check if you are connected with Tor. So before running the test make sure +that sys-whonix has access to the network. + +## Refresh + +``` +$ sudo qubes-fwupdmgr refresh --whonix +``` + +## Update + +``` +$ sudo qubes-fwupdmgr update --whonix +``` + +## Downgrade + +``` +$ sudo qubes-fwupdmgr downgrade --whonix +``` diff -Nru fwupd-1.4.5/contrib/qubes/meson.build fwupd-1.5.8/contrib/qubes/meson.build --- fwupd-1.4.5/contrib/qubes/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/qubes/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,53 @@ +install_data([ + 'src/__init__.py', + 'src/fwupd_receive_updates.py', + 'src/qubes_fwupd_heads.py', + 'src/qubes_fwupd_update.py', + ], + install_dir : 'share/qubes-fwupd/src', +) + +install_data([ + 'test/__init__.py', + 'test/fwupd_logs.py', + 'test/test_qubes_fwupd_heads.py', + 'test/test_qubes_fwupdmgr.py', + ], + install_dir : 'share/qubes-fwupd/test', +) + +install_data([ + 'test/logs/firmware.metainfo.xml', + 'test/logs/get_devices.log', + 'test/logs/get_updates.log', + 'test/logs/help.log', + ], + install_dir : 'share/qubes-fwupd/test/logs', +) + +install_data([ + 'src/vms/fwupd_common_vm.py', + 'src/vms/fwupd_download_updates.py', + 'src/vms/fwupd_usbvm_validate.py', + ], + install_dir : 'libexec/qubes-fwupd', + install_mode : 'rwxrwxr-x', +) + +install_data([ + 'test/logs/metainfo_name/firmware.metainfo.xml', + ], + install_dir : 'share/qubes-fwupd/test/logs/metainfo_name', +) + +install_data( + 'test/logs/metainfo_version/firmware.metainfo.xml', + install_dir : 'share/qubes-fwupd/test/logs/metainfo_version', +) + +install_data( + 'src/qubes_fwupdmgr.py', + install_dir : 'sbin', + rename : 'qubes-fwupdmgr', + install_mode : 'rwxrwxr-x', +) diff -Nru fwupd-1.4.5/contrib/qubes/README.md fwupd-1.5.8/contrib/qubes/README.md --- fwupd-1.4.5/contrib/qubes/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/qubes/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,222 @@ +# qubes-fwupd + +fwupd wrapper for QubesOS + +## Table of Contents + +* [Requirements](#Requirements) +* [Usage](#Usage) +* [Installation](#Installation) +* [Testing](#Testing) +* [Whonix support](doc/whonix.md) +* [UEFI capsule update](doc/uefi_capsule_update.md) +* [Heads update](doc/heads_update.md) + +## OS Requirements + +**Operating System:** Qubes OS R4.1 + +**Admin VM (dom0):** Fedora 32 + +**Template VM:** Fedora 32 + +**Whonix VM:** whonix-gw-15 + +## Usage + +``` +========================================================================================== +Usage: +========================================================================================== + Command: qubes-fwupdmgr [OPTION…][FLAG..] + Example: qubes-fwupdmgr refresh --whonix --url= + +Options: +========================================================================================== + get-devices: Get all devices that support firmware updates + get-updates: Get the list of updates for connected hardware + refresh: Refresh metadata from remote server + update: Update chosen device to latest firmware version + update-heads: Updates heads firmware to the latest version + downgrade: Downgrade chosen device to chosen firmware version + clean: Delete all cached update files + +Flags: +========================================================================================== + --whonix: Download firmware updates via Tor + --device: Specify device for heads update (default - x230) + --url: Address of the custom metadata remote server + +Help: +========================================================================================== + -h --help: Show help options +``` + +## Installation + +For development purpose: + +1. Build the package for fedora and debian as it is shown in the contrib +[README](../README.md). +2. The build artifacts are placed in `dist` directory: + -- dom0 package - `dist/fwupd-qubes-dom0--0.1alpha.fc32.x86_64.rpm` + -- vm package - `dist/fwupd-qubes-vm--0.1alpha.fc32.x86_64.rpm` + -- whonix package - `dist/fwupd-qubes-vm-whonix-_amd64.deb` + +3. Copy packages to the Qubes OS. +4. Move the `fwupd-qubes-vm--0.1alpha.fc32.x86_64.rpm` to the Fedora 32 +template VM (replace `` with the current version) + +``` +$ qvm-copy fwupd-qubes-vm--0.1alpha.fc32.x86_64.rpm +``` + +5. Install package dependencies + +``` +# dnf install gcab fwupd +``` + +6. Run terminal in the template VM and go to +`~/QubesIncoming/`. Compare SHA sums of the package in +TemplateVM and qubes-builder VM. If they match, install the package: + +``` +# rpm -U fwupd-qubes-vm--0.1alpha.fc32.x86_64.rpm +``` + +7. Shutdown TemplateVM + +8. Run whonix-gw-15 and copy whonix a package from qubes builder VM + +``` +$ qvm-copy fwupd-qubes-vm-whonix-_amd64.deb +``` + +9. Install dependencies + +``` +# apt install gcab fwupd +``` + +10. Run terminal in the whonix-gw-15 and go to `~/QubesIncoming/qubes-builder`. +Compare SHA sums of the package in TemplateVM and qubes-builder VM. If they +match, install the package: + +``` +# dpkg -i fwupd-qubes-vm-whonix-_amd64.deb +``` + +11. Shutdown whonix-gw-15 + +12. Run dom0 terminal in the dom0 and copy package + +``` +$ qvm-run --pass-io \ +'cat /qubes-src/fwupd/pkgs/dom0-fc32/x86_64/fwupd-qubes-dom0--0.1alpha.fc32.x86_64.rpm' > \ +fwupd-qubes-dom0--0.1alpha.fc32.x86_64.rpm +``` + +13. Install package dependencies + +``` +# qubes-dom0-update gcab fwupd python36 +``` + +14. Make sure that sys-firewall, sys-whonix, and sys-usb (if exists) are running. + +15. Compare the SHA sums of the package in dom0 and qubes-builder VM. +If they match, install the package: + +``` +# rpm -U qubes-fwupd-dom0-0.2.0-1.fc32.x86_64.rpm +``` + +16. Reboot system (or reboot sys-firewall, sys-whonix, and sys-usb) + +17. Run the tests to verify the installation process + +## Testing + +### Outside the Qubes OS + +A test case covers the whole qubes_fwupdmgr script. It could be run outside the +Qubes OS. If the requirements of a single test are not met, it will be omitted. +To run the tests, move to the repo directory and type the following: + +``` +$ python3 -m unittest -v test.test_qubes_fwupdmgr + +test_clean_cache (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... ok +test_downgrade_firmware (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... skipped 'Required device not connected' +test_download_firmware_updates (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... skipped 'requires Qubes OS' +test_download_metadata (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... skipped 'requires Qubes OS' +test_get_devices (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... skipped 'requires Qubes OS' +test_get_devices_qubes (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... skipped 'requires Qubes OS' +test_get_updates (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... skipped 'requires Qubes OS' +test_get_updates_qubes (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... skipped 'requires Qubes OS' +test_help (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... ok +test_output_crawler (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... ok +test_parse_downgrades (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... ok +test_parse_parameters (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... ok +test_parse_updates_info (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... ok +test_refresh_metadata (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... skipped 'requires Qubes OS' +test_user_input_choice (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... ok +test_user_input_downgrade (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... ok +test_user_input_empty_list (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... ok +test_user_input_n (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... ok +test_verify_dmi (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... ok +test_verify_dmi_argument_version (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... ok +test_verify_dmi_version (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... ok +test_verify_dmi_wrong_vendor (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... ok + +---------------------------------------------------------------------- +Ran 22 tests in 0.003s + +OK (skipped=8) +``` + +### In the Qubes OS + +In the dom0, move to: + +``` +$ cd /usr/share/qubes-fwupd/ +``` + +#### Qubes OS 4.1 + +Run the tests with sudo privileges: + +``` +# python3 -m unittest -v test.test_qubes_fwupdmgr +``` + +Note: If the whonix tests failed, make sure that you are connected to the Tor + +## Whonix support + +``` +# qubes-fwupdmgr [refresh/update/downgrade] --whonix [FLAG] +``` + +More specified information you will find in the +[whonix documentation](doc/whonix.md). + +## UEFI capsule update + +``` +# qubes-fwupdmgr [update/downgrade] +``` + +Requirements and more specified information you will find in the +[UEFI capsule update documentation](doc/uefi_capsule_update.md). + +## Heads update + +``` +# qubes-fwupdmgr update-heads --device=x230 --url= +``` + +Requirements and more specified information you will find in the +[heads update documentation](doc/heads_update.md). diff -Nru fwupd-1.4.5/contrib/qubes/src/fwupd_receive_updates.py fwupd-1.5.8/contrib/qubes/src/fwupd_receive_updates.py --- fwupd-1.4.5/contrib/qubes/src/fwupd_receive_updates.py 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/qubes/src/fwupd_receive_updates.py 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,318 @@ +#!/usr/bin/python3 +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2010 Rafal Wojtczuk +# 2020 Norbert Kamiński +# +# SPDX-License-Identifier: LGPL-2.1+ +# + +import glob +import grp +import hashlib +import os +import re +import shutil +import subprocess + +FWUPD_DOM0_DIR = "/root/.cache/fwupd" +FWUPD_DOM0_UPDATES_DIR = os.path.join(FWUPD_DOM0_DIR, "updates") +FWUPD_DOM0_UNTRUSTED_DIR = os.path.join(FWUPD_DOM0_UPDATES_DIR, "untrusted") +FWUPD_DOM0_METADATA_DIR = os.path.join(FWUPD_DOM0_DIR, "metadata") +FWUPD_DOM0_METADATA_FILE = os.path.join( + FWUPD_DOM0_METADATA_DIR, + "firmware.xml.gz" +) +FWUPD_DOM0_METADATA_JCAT = os.path.join( + FWUPD_DOM0_METADATA_DIR, + "firmware.xml.gz.jcat" +) + +FWUPD_VM_DIR = "/home/user/.cache/fwupd" +FWUPD_VM_UPDATES_DIR = os.path.join(FWUPD_VM_DIR, "updates") +FWUPD_VM_METADATA_DIR = os.path.join(FWUPD_VM_DIR, "metadata") +FWUPD_VM_METADATA_FILE = os.path.join( + FWUPD_VM_METADATA_DIR, + "firmware.xml.gz" +) +FWUPD_VM_METADATA_JCAT = os.path.join( + FWUPD_VM_METADATA_DIR, + "firmware.xml.gz.jcat" +) +FWUPD_PKI = "/etc/pki/fwupd" +FWUPD_DOWNLOAD_PREFIX = "https://fwupd.org/downloads/" +FWUPD_METADATA_FLAG_REGEX = re.compile(r"^metaflag") +FWUPD_METADATA_FILES_REGEX = re.compile( + r"^firmware[a-z0-9\[\]\@\<\>\.\"\-]{0,128}.xml.gz.?[aj]?[sc]?[ca]?t?$" +) +HEADS_UPDATES_DIR = "/boot/updates" +WARNING_COLOR = '\033[93m' + + +class FwupdReceiveUpdates: + def _check_shasum(self, file_path, sha): + """Compares computed SHA256 checksum with `sha` parameter. + + Keyword arguments: + file_path -- absolute path to the file + sha -- SHA256 checksum of the file + """ + with open(file_path, 'rb') as f: + c_sha = hashlib.sha256(f.read()).hexdigest() + if c_sha != sha: + self.clean_cache() + raise ValueError(f"Computed checksum {c_sha} did NOT match {sha}.") + + def _check_domain(self, updatevm): + """Checks if domain given as `updatevm` is allowed to send update + files. + + Keyword argument: + updatevm - domain to be checked + """ + cmd = ['qubes-prefs', '--force-root', 'updatevm'] + p = subprocess.check_output(cmd) + source = p.decode('ascii').rstrip() + if source != updatevm and "sys-whonix" != updatevm: + raise Exception( + f'Domain {updatevm} not allowed to send dom0 updates' + ) + + def _verify_received(self, files_path, regex_pattern, updatevm): + """Checks if sent files match regex filename pattern. + + Keyword arguments: + + files_path -- absolute path to inspected directory + regex_pattern -- pattern of the expected files + updatevm - domain to be checked + """ + for untrusted_f in os.listdir(files_path): + if not regex_pattern.match(untrusted_f): + raise Exception(f'Domain {updatevm} sent unexpected file') + f = untrusted_f + assert '/' not in f + assert '\0' not in f + assert '\x1b' not in f + path_f = os.path.join(files_path, f) + if os.path.islink(path_f) or not os.path.isfile(path_f): + raise Exception(f'Domain {updatevm} sent not regular file') + + def _create_dirs(self, *args): + """Method creates directories. + + Keyword arguments: + *args -- paths to be created + """ + qubes_gid = grp.getgrnam('qubes').gr_gid + self.old_umask = os.umask(0o002) + if args is None: + raise Exception("Creating directories failed, no paths given.") + for file_path in args: + if not os.path.exists(file_path): + os.mkdir(file_path) + os.chown(file_path, -1, qubes_gid) + os.chmod(file_path, 0o0775) + elif os.stat(file_path).st_gid != qubes_gid: + print( + f"{WARNING_COLOR}Warning: You should move a personal files" + f" from {file_path}. Cleaning cache will cause lose of " + f"the personal data!!{WARNING_COLOR}" + ) + + def _extract_archive(self, archive_path, output_path): + """Extracts archive file to the specified directory. + + Keyword arguments: + archive_path -- absolute path to archive file + output_path -- absolute path to the output directory + """ + cmd_extract = [ + "gcab", + "-x", + f"--directory={output_path}", + f"{archive_path}" + ] + shutil.copy(archive_path, FWUPD_DOM0_UPDATES_DIR) + p = subprocess.Popen(cmd_extract, stdout=subprocess.PIPE) + p.communicate()[0].decode('ascii') + if p.returncode != 0: + raise Exception( + f'gcab: Error while extracting {archive_path}.' + ) + + def _jcat_verification(self, file_path, file_directory): + """Verifies sha1 and sha256 checksum, GPG signature, + and PKCS#7 signature. + + Keyword argument: + file_path -- absolute path to jcat file + file_directory -- absolute path to the directory to jcat file location + """ + cmd_jcat = [ + "jcat-tool", + "verify", + f"{file_path}", + "--public-keys", + FWUPD_PKI + ] + p = subprocess.Popen( + cmd_jcat, + cwd=file_directory, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE + ) + stdout, __ = p.communicate() + verification = stdout.decode('utf-8') + print(verification) + if p.returncode != 0: + self.clean_cache() + raise Exception('jcat-tool: Verification failed') + + def handle_fw_update(self, updatevm, sha, filename): + """Copies firmware update archives from the updateVM. + + Keyword arguments: + updatevm -- update VM name + sha -- SHA256 checksum of the firmware update archive + filename -- name of the firmware update archive + """ + fwupd_firmware_file_regex = re.compile(filename) + dom0_firmware_untrusted_path = os.path.join( + FWUPD_DOM0_UNTRUSTED_DIR, + filename + ) + updatevm_firmware_file_path = os.path.join( + FWUPD_VM_UPDATES_DIR, + filename + ) + + self._check_domain(updatevm) + if os.path.exists(FWUPD_DOM0_UNTRUSTED_DIR): + shutil.rmtree(FWUPD_DOM0_UNTRUSTED_DIR) + self._create_dirs(FWUPD_DOM0_UPDATES_DIR, FWUPD_DOM0_UNTRUSTED_DIR) + + cmd_copy = 'qvm-run --pass-io %s %s > %s' % ( + updatevm, + "'cat %s'" % updatevm_firmware_file_path, + dom0_firmware_untrusted_path + ) + p = subprocess.Popen(cmd_copy, shell=True) + p.wait() + if p.returncode != 0: + raise Exception('qvm-run: Copying firmware file failed!!') + + self._verify_received( + FWUPD_DOM0_UNTRUSTED_DIR, + fwupd_firmware_file_regex, + updatevm + ) + self._check_shasum(dom0_firmware_untrusted_path, sha) + untrusted_dir_name = filename.replace(".cab", "") + self._extract_archive( + dom0_firmware_untrusted_path, + FWUPD_DOM0_UNTRUSTED_DIR + ) + signature_name = os.path.join( + FWUPD_DOM0_UNTRUSTED_DIR, + "firmware*.jcat" + ) + file_path = glob.glob(signature_name) + if not file_path: + raise FileNotFoundError("jcat file not found!") + self._jcat_verification(file_path[0], FWUPD_DOM0_UNTRUSTED_DIR) + os.umask(self.old_umask) + if untrusted_dir_name == "untrusted": + untrusted_dir_name = "trusted" + verified_file = os.path.join(FWUPD_DOM0_UPDATES_DIR, filename) + self.arch_name = "trusted.cab" + self.arch_path = os.path.join( + FWUPD_DOM0_UPDATES_DIR, + self.arch_name + ) + shutil.move(verified_file, self.arch_path) + else: + self.arch_path = os.path.join(FWUPD_DOM0_UPDATES_DIR, filename) + dir_name = os.path.join(FWUPD_DOM0_UPDATES_DIR, untrusted_dir_name) + os.remove(dom0_firmware_untrusted_path) + shutil.move(FWUPD_DOM0_UNTRUSTED_DIR, dir_name) + + def handle_metadata_update(self, updatevm, metadata_url=None): + """Copies metadata files from the updateVM. + + Keyword argument: + updatevm -- update VM name + """ + if metadata_url: + metadata_name = metadata_url.replace( + FWUPD_DOWNLOAD_PREFIX, + "" + ) + self.metadata_file = os.path.join( + FWUPD_DOM0_METADATA_DIR, + metadata_name + ) + self.metadata_file_jcat = self.metadata_file + '.jcat' + else: + self.metadata_file = FWUPD_DOM0_METADATA_FILE + self.metadata_file_jcat = FWUPD_DOM0_METADATA_JCAT + self.metadata_file_updatevm = self.metadata_file.replace( + FWUPD_DOM0_METADATA_DIR, + FWUPD_VM_METADATA_DIR + ) + self.metadata_file_jcat_updatevm = self.metadata_file_jcat.replace( + FWUPD_DOM0_METADATA_DIR, + FWUPD_VM_METADATA_DIR + ) + self._check_domain(updatevm) + self._create_dirs(FWUPD_DOM0_METADATA_DIR) + cmd_file = "'cat %s'" % self.metadata_file_updatevm + cmd_jcat = "'cat %s'" % self.metadata_file_jcat_updatevm + cmd_copy_metadata_file = 'qvm-run --pass-io %s %s > %s' % ( + updatevm, + cmd_file, + self.metadata_file + ) + cmd_copy_metadata_jcat = 'qvm-run --pass-io %s %s > %s' % ( + updatevm, + cmd_jcat, + self.metadata_file_jcat + ) + + p = subprocess.Popen(cmd_copy_metadata_file, shell=True) + p.wait() + if p.returncode != 0: + raise Exception('qvm-run: Copying metadata file failed!!') + p = subprocess.Popen(cmd_copy_metadata_jcat, shell=True) + p.wait() + if p.returncode != 0: + raise Exception('qvm-run": Copying metadata jcat failed!!') + + self._verify_received( + FWUPD_DOM0_METADATA_DIR, + FWUPD_METADATA_FILES_REGEX, + updatevm + ) + self._jcat_verification( + self.metadata_file_jcat, + FWUPD_DOM0_METADATA_DIR + ) + os.umask(self.old_umask) + + def clean_cache(self, usbvm=False): + """Removes updates data + + Keyword arguments: + usbvm -- usbvm support flag + """ + print("Cleaning dom0 cache directories") + if os.path.exists(FWUPD_DOM0_METADATA_DIR): + shutil.rmtree(FWUPD_DOM0_METADATA_DIR) + if os.path.exists(FWUPD_DOM0_UPDATES_DIR): + shutil.rmtree(FWUPD_DOM0_UPDATES_DIR) + if os.path.exists(HEADS_UPDATES_DIR): + shutil.rmtree(HEADS_UPDATES_DIR) + if usbvm: + print("Cleaning usbvm cache directories") + self._clean_usbvm() diff -Nru fwupd-1.4.5/contrib/qubes/src/qubes_fwupd_heads.py fwupd-1.5.8/contrib/qubes/src/qubes_fwupd_heads.py --- fwupd-1.4.5/contrib/qubes/src/qubes_fwupd_heads.py 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/qubes/src/qubes_fwupd_heads.py 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,138 @@ +#!/usr/bin/python3 +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2021 Norbert Kamiński +# +# SPDX-License-Identifier: LGPL-2.1+ +# + +import subprocess +import os +import shutil +import xml.etree.ElementTree as ET +from distutils.version import LooseVersion as l_ver + +FWUPDTOOL = "/bin/fwupdtool" + +BOOT = "/boot" +HEADS_UPDATES_DIR = os.path.join(BOOT, "updates") + +EXIT_CODES = { + "ERROR": 1, + "SUCCESS": 0, + "NOTHING_TO_DO": 2, +} + + +class FwupdHeads: + def _get_hwids(self): + cmd_hwids = [FWUPDTOOL, "hwids"] + p = subprocess.Popen( + cmd_hwids, + stdout=subprocess.PIPE + ) + self.dom0_hwids_info = p.communicate()[0].decode() + if p.returncode != 0: + raise Exception("fwudp-qubes: Getting hwids info failed") + + def _gather_firmware_version(self): + """ + Checks if Qubes works under heads + """ + if "heads" in self.dom0_hwids_info: + self.heads_version = None + hwids = self.dom0_hwids_info.split("\n") + for line in hwids: + if line.startswith("BiosVersion: CBET4000 "): + self.heads_version = line.replace( + "BiosVersion: CBET4000 ", + "" + ).replace( + " heads", + "" + ) + else: + print("Device is not running under the heads firmware!!") + print("Exiting...") + return EXIT_CODES["NOTHING_TO_DO"] + + def _parse_metadata(self, metadata_file): + """ + Parse metadata info. + """ + cmd_metadata = ["zcat", metadata_file] + p = subprocess.Popen( + cmd_metadata, + stdout=subprocess.PIPE + ) + self.metadata_info = p.communicate()[0].decode() + if p.returncode != 0: + raise Exception("fwudp-qubes: Parsing metadata failed") + + def _parse_heads_updates(self, device): + """ + Parses heads updates info. + + Keyword arguments: + device -- Model of the updated device + """ + self.heads_update_url = None + self.heads_update_sha = None + self.heads_update_version = None + heads_metadata_info = None + root = ET.fromstring(self.metadata_info) + for component in root.findall("component"): + if f"heads.{device}" in component.find("id").text: + heads_metadata_info = component + if not heads_metadata_info: + print("No metadata info for chosen board") + return EXIT_CODES["NOTHING_TO_DO"] + for release in heads_metadata_info.find("releases").findall("release"): + release_ver = release.get("version") + if (self.heads_version == "heads" or + l_ver(release_ver) > l_ver(self.heads_version)): + if (not self.heads_update_version or + l_ver(release_ver) > l_ver(self.heads_update_version)): + self.heads_update_url = release.find("location").text + for sha in release.findall("checksum"): + if (".cab" in sha.attrib["filename"] + and sha.attrib["type"] == "sha256"): + self.heads_update_sha = sha.text + self.heads_update_version = release_ver + if self.heads_update_url: + return EXIT_CODES["SUCCESS"] + else: + print("Heads firmware is up to date.") + return EXIT_CODES["NOTHING_TO_DO"] + + def _copy_heads_firmware(self, arch_path): + """ + Copies heads update to the boot path + """ + heads_boot_path = os.path.join( + HEADS_UPDATES_DIR, + self.heads_update_version + ) + update_path = arch_path.replace(".cab", "/firmware.rom") + + heads_update_path = os.path.join( + heads_boot_path, + "firmware.rom" + ) + if not os.path.exists(HEADS_UPDATES_DIR): + os.mkdir(HEADS_UPDATES_DIR) + if os.path.exists(heads_update_path): + print( + f"Heads Update == {self.heads_update_version} " + "already downloaded." + ) + return EXIT_CODES["NOTHING_TO_DO"] + else: + os.mkdir(heads_boot_path) + shutil.copyfile(update_path, heads_update_path) + print( + f"Heads Update == {self.heads_update_version} " + f"available at {heads_boot_path}" + ) + return EXIT_CODES["SUCCESS"] diff -Nru fwupd-1.4.5/contrib/qubes/src/qubes_fwupdmgr.py fwupd-1.5.8/contrib/qubes/src/qubes_fwupdmgr.py --- fwupd-1.4.5/contrib/qubes/src/qubes_fwupdmgr.py 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/qubes/src/qubes_fwupdmgr.py 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,1135 @@ +#!/usr/bin/python3 +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2021 Norbert Kaminski +# +# SPDX-License-Identifier: LGPL-2.1+ +# + +import json +import os +import re +import shutil +import subprocess +import sys +import xml.etree.ElementTree as ET + +from pathlib import Path +from distutils.version import LooseVersion as l_ver + +FWUPD_QUBES_DIR = "/usr/share/qubes-fwupd" + +# Check if script is run by tests and append sys path properly +if __name__ == "__main__": + sys.path.append(os.path.join(FWUPD_QUBES_DIR, "src")) +else: + sys.path.append("./src") + +try: + from qubes_fwupd_heads import FwupdHeads + from qubes_fwupd_update import FwupdUpdate + from fwupd_receive_updates import FwupdReceiveUpdates +except ModuleNotFoundError: + raise ModuleNotFoundError( + "qubes-fwupd modules not found. " + "You may need to reinstall package." + ) + +FWUPD_DOM0_DIR = "/root/.cache/fwupd" +FWUPD_DOM0_METADATA_DIR = os.path.join(FWUPD_DOM0_DIR, "metadata") +FWUPD_DOM0_UPDATES_DIR = os.path.join(FWUPD_DOM0_DIR, "updates") +FWUPD_DOM0_METADATA_SIGNATURE = os.path.join( + FWUPD_DOM0_METADATA_DIR, + "firmware.xml.gz.asc" +) +FWUPD_DOM0_METADATA_FILE = os.path.join( + FWUPD_DOM0_METADATA_DIR, + "firmware.xml.gz" +) +FWUPD_DOM0_METADATA_JCAT = os.path.join( + FWUPD_DOM0_METADATA_DIR, + "firmware.xml.gz.jcat" +) +FWUPD_VM_LOG = os.path.join(FWUPD_DOM0_DIR, "usbvm-devices.log") +FWUPD_VM_VALIDATE = "/usr/libexec/qubes-fwupd/fwupd_usbvm_validate.py" +FWUPD_VM_DIR = "/home/user/.cache/fwupd" +FWUPD_VM_UPDATES_DIR = os.path.join(FWUPD_VM_DIR, "updates") +FWUPD_VM_METADATA_DIR = os.path.join(FWUPD_VM_DIR, "metadata") +FWUPD_VM_METADATA_SIGNATURE = os.path.join( + FWUPD_VM_METADATA_DIR, + "firmware.xml.gz.asc" +) +FWUPD_VM_METADATA_FILE = os.path.join( + FWUPD_VM_METADATA_DIR, + "firmware.xml.gz" +) +FWUPD_VM_METADATA_JCAT = os.path.join( + FWUPD_VM_METADATA_DIR, + "firmware.xml.gz.jcat" +) +FWUPD_DOWNLOAD_PREFIX = "https://fwupd.org/downloads/" + +FWUPDMGR = "/bin/fwupdmgr" +FWUPDAGENT = "/bin/fwupdagent" + +USBVM_N = "sys-usb" + +BIOS_UPDATE_FLAG = os.path.join(FWUPD_DOM0_DIR, "bios_update") +LVFS_TESTING_DOM0_FLAG = os.path.join(FWUPD_DOM0_DIR, "lvfs_testing") +LVFS_TESTING_USBVM_FLAG = os.path.join(FWUPD_VM_DIR, "lvfs_testing") +METADATA_REFRESH_REGEX = re.compile( + r"^Successfully refreshed metadata manually$" +) + +SPECIAL_CHAR_REGEX = re.compile(r'%20|&|\||#') + + +HELP = { + "Usage": [ + { + "Command": "qubes-fwupdmgr [OPTION…][FLAG..]", + "Example": "qubes-fwupdmgr refresh --whonix --url=\n", + } + ], + "Options": [ + { + "get-devices": "Get all devices that support firmware updates", + "get-updates": "Get the list of updates for connected hardware", + "refresh": "Refresh metadata from remote server", + "update": "Update chosen device to latest firmware version", + "update-heads": "Updates heads firmware to the latest version", + "downgrade": "Downgrade chosen device to chosen firmware version", + "clean": "Delete all cached update files\n" + } + ], + "Flags": [ + { + "--whonix": "Download firmware updates via Tor", + "--device": "Specify device for heads update (default - x230)", + "--url": "Address of the custom metadata remote server\n" + } + ], + "Help": [ + { + "-h --help": "Show help options\n" + } + ], +} + +EXIT_CODES = { + "ERROR": 1, + "SUCCESS": 0, + "NOTHING_TO_DO": 2, +} + + +class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates): + def _download_metadata(self, whonix=False, metadata_url=None): + """Initialize downloading metadata files. + + Keywords arguments: + whonix -- Flag enforces downloading the metadata updates via Tor + metadata_url -- Download metadata from the custom url + """ + self.download_metadata(whonix=whonix, metadata_url=metadata_url) + self.handle_metadata_update(self.updatevm, metadata_url=metadata_url) + if not os.path.exists(self.metadata_file): + raise FileNotFoundError("Metadata file does not exist") + + def _validate_usbvm_dirs(self): + """Validates if sys-ubs updates and metadata directories exist.""" + cmd_validate_dirs = [ + "qvm-run", + "--pass-io", + USBVM_N, + f'script --quiet --return --command "{FWUPD_VM_VALIDATE} dirs"' + ] + p = subprocess.Popen(cmd_validate_dirs) + p.wait() + if p.returncode != 0: + raise Exception("Validation of usbvm directories failed.") + + def _validate_usbvm_archive(self, arch_name, sha): + """Validates checksum and gpg signature of the archive file.""" + arch_path = os.path.join(FWUPD_VM_UPDATES_DIR, arch_name) + arch_validate = f"{FWUPD_VM_VALIDATE} updates {arch_path} {sha}" + cmd_validate_arch = [ + "qvm-run", + "--pass-io", + USBVM_N, + f'script --quiet --return --command "{arch_validate}"' + ] + p = subprocess.Popen(cmd_validate_arch) + p.wait() + if p.returncode != 0: + raise Exception("Validation of the archive file failed.") + + def _copy_usbvm_metadata(self): + """Copies metadata files to usbvm.""" + self.metadata_file_usbvm = self.metadata_file.replace( + FWUPD_DOM0_METADATA_DIR, + FWUPD_VM_METADATA_DIR + ) + self.metadata_file_jcat_usbvm = self.metadata_file_usbvm + ".jcat" + cat_file = f"cat > {self.metadata_file_usbvm}" + cmd_copy_file = ( + f'cat {self.metadata_file} | ' + f'qvm-run --nogui --pass-io {USBVM_N} "{cat_file}"' + ) + cat_jcat = f"cat > {self.metadata_file_jcat_usbvm}" + cmd_copy_jcat = ( + f'cat {self.metadata_file_jcat} | ' + f'qvm-run --nogui --pass-io {USBVM_N} "{cat_jcat}"' + ) + p = subprocess.Popen(cmd_copy_file, shell=True) + p.wait() + if p.returncode != 0: + raise Exception("Copying metadata file failed.") + p = subprocess.Popen(cmd_copy_jcat, shell=True) + p.wait() + if p.returncode != 0: + raise Exception("Copying metadata jcat failed.") + + def _validate_usbvm_metadata(self, metadata_url=None): + """Checks GPG signature of metadata files in usbvm.""" + usbvm_cmd = f'"{FWUPD_VM_VALIDATE} metadata"' + if metadata_url: + usbvm_cmd = ( + f'"{FWUPD_VM_VALIDATE} metadata --url={metadata_url}"' + ) + cmd_validate_metadata = [ + "qvm-run", + "--pass-io", + USBVM_N, + 'script --quiet --return --command' + f' {usbvm_cmd}' + ] + p = subprocess.Popen(cmd_validate_metadata) + p.wait() + if p.returncode != 0: + raise Exception("Metadata validation failed") + + def _refresh_usbvm_metadata(self): + """Refreshes metadata in usbvm.""" + sig_metadata_file = self.metadata_file_jcat_usbvm + cmd_refresh_metadata = [ + "qvm-run", + "--pass-io", + USBVM_N, + ( + 'script --quiet --return --command ' + f'"{FWUPDMGR} refresh {self.metadata_file_usbvm} ' + f'{sig_metadata_file} {self.lvfs}"' + ) + ] + p = subprocess.Popen(cmd_refresh_metadata) + p.wait() + if p.returncode != 0: + raise Exception("Metadata refresh in usbvm failed") + + def _copy_firmware_updates(self, arch_name): + """Copies updates files to usbvm. + + Keywords arguments: + arch_name - name of the archive file + """ + arch_path = os.path.join(FWUPD_DOM0_UPDATES_DIR, arch_name) + output_path = os.path.join(FWUPD_VM_UPDATES_DIR, arch_name) + cat_file = f"cat > {output_path}" + cmd_copy_file = ( + f'cat {arch_path} | ' + f'qvm-run --nogui --pass-io {USBVM_N} "{cat_file}"' + ) + p = subprocess.Popen(cmd_copy_file, shell=True) + p.wait() + if p.returncode != 0: + raise Exception("Copying metadata file failed.") + + def _install_usbvm_firmware_update(self, arch_name): + """Installs firmware update for specified device in dom0. + + Keywords arguments: + arch_name - name of the archive file + """ + arch_path = os.path.join(FWUPD_VM_UPDATES_DIR, arch_name) + CMD_update = [ + "qvm-run", + "--pass-io", + USBVM_N, + f'script --quiet --return --command' + f' "{FWUPDMGR} install {arch_path}" /dev/null' + ] + p = subprocess.Popen(CMD_update) + p.wait() + if p.returncode != 0: + raise Exception("fwudp-qubes: Firmware update failed") + + def _install_usbvm_firmware_downgrade(self, arch_name): + """Installs firmware downgrades for specified device in dom0. + + Keywords arguments: + arch_name - name of the archive file + """ + arch_path = os.path.join(FWUPD_VM_UPDATES_DIR, arch_name) + CMD_downgrade = [ + "qvm-run", + "--pass-io", + USBVM_N, + f'script --quiet --return --command' + f' "{FWUPDMGR} --allow-older install {arch_path}" /dev/null' + ] + p = subprocess.Popen(CMD_downgrade) + p.wait() + if p.returncode != 0: + raise Exception("fwudp-qubes: Firmware downgrade failed") + + def _clean_usbvm(self): + """Cleans usbvm directories.""" + cmd_clean = [ + "qvm-run", + "--pass-io", + USBVM_N, + f'script --quiet --return --command "{FWUPD_VM_VALIDATE} clean"' + ] + p = subprocess.Popen(cmd_clean) + p.wait() + if p.returncode != 0: + raise Exception("Cleaning usbvm directories failed") + + def _enable_lvfs_testing_dom0(self): + """Checks and enable lvfs-testing for custom metadata in dom0""" + cmd_lvfs_testing = [ + FWUPDMGR, + "enable-remote", + "-y", + "lvfs-testing" + ] + if not os.path.exists(LVFS_TESTING_DOM0_FLAG): + p = subprocess.Popen(cmd_lvfs_testing) + p.wait() + if p.returncode != 0: + raise Exception("Enabling dom0 lvfs-testing failed!!") + Path(LVFS_TESTING_DOM0_FLAG).touch(mode=0o644, exist_ok=False) + + def _enable_lvfs_testing_usbvm(self, usbvm=False): + """Checks and enable lvfs-testing for custom metadata in usbvm""" + if not usbvm: + return 0 + cmd_refresh_metadata = [ + "qvm-run", + "--pass-io", + USBVM_N, + ( + 'script --quiet --return --command ' + f'"{FWUPDMGR} enable-remote -y lvfs-testing"' + ) + ] + cmd_validate_flag = [ + "qvm-run", + "--pass-io", + USBVM_N, + ( + 'script --quiet --return --command ' + f'"ls {LVFS_TESTING_USBVM_FLAG} &>/dev/null"' + ) + ] + cmd_touch_flag = [ + "qvm-run", + "--pass-io", + USBVM_N, + ( + 'script --quiet --return --command ' + f'"touch {LVFS_TESTING_USBVM_FLAG}"' + ) + ] + flag = subprocess.Popen(cmd_validate_flag) + flag.wait() + if flag.returncode != 0: + p = subprocess.Popen(cmd_refresh_metadata) + p.wait() + if p.returncode != 0: + raise Exception("Enabling usbvm lvfs-testing failed!!") + p = subprocess.Popen(cmd_touch_flag) + p.wait() + if p.returncode != 0: + raise Exception("Creating flag failed!!") + + def refresh_metadata(self, usbvm=False, whonix=False, metadata_url=None): + """Updates metadata with downloaded files. + + Keyword arguments: + usbvm -- usbvm support flag + whonix -- Flag enforces downloading the metadata updates via Tor + metadata_url -- Use custom metadata from the url + """ + if metadata_url: + metadata_name = metadata_url.replace(FWUPD_DOWNLOAD_PREFIX, "") + self.metadata_file = os.path.join( + FWUPD_DOM0_METADATA_DIR, + metadata_name + ) + self.metadata_file_jcat = self.metadata_file + '.jcat' + self.lvfs = "lvfs-testing" + self._enable_lvfs_testing_dom0() + self._enable_lvfs_testing_usbvm(usbvm=usbvm) + else: + self.metadata_file = FWUPD_DOM0_METADATA_FILE + self.metadata_file_jcat = FWUPD_DOM0_METADATA_JCAT + self.lvfs = "lvfs" + self._download_metadata(whonix=whonix, metadata_url=metadata_url) + if usbvm: + self._validate_usbvm_dirs() + self._copy_usbvm_metadata() + self._validate_usbvm_metadata(metadata_url=metadata_url) + self._refresh_usbvm_metadata() + cmd_refresh = [ + FWUPDMGR, + "refresh", + self.metadata_file, + self.metadata_file_jcat, + self.lvfs + ] + p = subprocess.Popen( + cmd_refresh, + stdout=subprocess.PIPE + ) + self.output = p.communicate()[0].decode() + print(self.output) + if p.returncode != 0: + raise Exception("fwudp-qubes: Refresh failed") + if not METADATA_REFRESH_REGEX.match(self.output): + raise Exception("Manual metadata refresh failed!!!") + + def _get_dom0_updates(self): + """Gathers infromations about available updates.""" + cmd_get_dom0_updates = [ + FWUPDAGENT, + "get-updates" + ] + p = subprocess.Popen( + cmd_get_dom0_updates, + stdout=subprocess.PIPE + ) + self.dom0_updates_info = p.communicate()[0].decode() + if p.returncode != 0 and p.returncode != 2: + raise Exception("fwudp-qubes: Getting available updates failed") + + def _parse_dom0_updates_info(self, updates_info): + """Creates dictionary and list with information about updates. + + Keywords argument: + updates_info - gathered update information + """ + self.dom0_updates_info_dict = json.loads(updates_info) + self.dom0_updates_list = [ + { + "Name": device["Name"], + "Version": device["Version"], + "Releases": [ + { + "Version": update["Version"], + "Url": update["Uri"], + "Checksum": update["Checksum"][-1], + "Description": update["Description"] + } for update in device["Releases"] + ] + } for device in self.dom0_updates_info_dict["Devices"] + ] + + def _download_firmware_updates(self, url, sha, whonix=False): + """Initializes downloading firmware upadate archive. + + Keywords arguments: + url -- url path to the firmware upadate archive + sha -- SHA256 checksum of the firmware update archive + whonix -- Flag enforces downloading the updates via Tor + """ + self.cached = False + self.download_firmware_updates(url, sha, whonix=whonix) + if not self.cached: + self.handle_fw_update(self.updatevm, sha, self.arch_name) + update_path = self.arch_path.replace(".cab", "") + if not os.path.exists(update_path): + raise NotADirectoryError("Firmware update files do not exist") + + def _user_input(self, updates_dict, downgrade=False, usbvm=False): + """UI for update process. + + Keywords arguments: + updates_dict - list of updates for specified device + downgrade -- downgrade flag + """ + decorator = "======================================================" + if usbvm: + updates_list = updates_dict["dom0"] + updates_dict["usbvm"] + else: + updates_list = updates_dict["dom0"] + dom0_updates_num = len(updates_dict["dom0"]) + if len(updates_list) == 0: + print("No updates available.") + return EXIT_CODES["NOTHING_TO_DO"] + if downgrade: + print("Available downgrades:") + else: + print("Available updates:") + self._updates_crawler(updates_dict["dom0"]) + if usbvm: + self._updates_crawler( + updates_dict["usbvm"], + usbvm=True, + prefix=dom0_updates_num + ) + + while True: + try: + print("If you want to abandon process press 'N'.") + choice = input("Otherwise choose a device number: ") + if choice == 'N' or choice == 'n': + return EXIT_CODES["NOTHING_TO_DO"] + device_num = int(choice)-1 + if 0 <= device_num < len(updates_list): + if not downgrade: + if device_num >= dom0_updates_num: + return "usbvm", device_num-dom0_updates_num + else: + return "dom0", device_num + break + else: + raise ValueError() + except ValueError: + print("Invalid choice.") + + if downgrade: + while True: + try: + releases = updates_list[device_num]["Releases"] + for i, fw_dngd in enumerate(releases): + print(decorator) + print( + f" {i+1}. Firmware downgrade version:" + f"\t {fw_dngd['Version']}" + ) + description = fw_dngd["Description"].replace("

", "") + description = description.replace("

  • ", "") + description = description.replace("
      ", "") + description = description.replace("
    ", "") + description = description.replace("

    ", "\n ") + description = description.replace("
  • ", "\n ") + print(f" Description:{description}") + print("If you want to abandon downgrade process press N.") + choice = input("Otherwise choose downgrade number: ") + if choice == 'N' or choice == 'n': + return EXIT_CODES["NOTHING_TO_DO"] + downgrade_num = int(choice)-1 + if 0 <= downgrade_num < len(releases): + if device_num >= dom0_updates_num: + device_abs_num = device_num - dom0_updates_num + return "usbvm", device_abs_num, downgrade_num + else: + return "dom0", device_num, downgrade_num + else: + raise ValueError() + except ValueError: + print("Invalid choice.") + + def _parse_parameters(self, updates_dict, vm_name, choice): + """Parses device name, url, version and SHA256 checksum of the file list. + + Keywords arguments: + updates_dict - dictionary of updates for dom0 and usbvm + vm_name - VM name + choice -- number of device to be updated + """ + self.name = updates_dict[vm_name][choice]["Name"] + self.version = updates_dict[vm_name][choice]["Releases"][0]["Version"] + for ver_check in updates_dict[vm_name][choice]["Releases"]: + if l_ver(ver_check["Version"]) >= l_ver(self.version): + self.version = ver_check["Version"] + self.url = ver_check["Url"] + self.sha = ver_check["Checksum"] + + def _install_dom0_firmware_update(self, arch_path): + """Installs firmware update for specified device in dom0. + + Keywords arguments: + arch_path - absolute path to firmware update archive + """ + cmd_install = [ + FWUPDMGR, + "install", + arch_path + ] + p = subprocess.Popen(cmd_install) + p.wait() + if p.returncode != 0: + raise Exception("fwudp-qubes: Firmware update failed") + + def _read_dmi(self): + """Reads BIOS information from DMI.""" + cmd_dmidecode_version = [ + "dmidecode", + "-s", + "bios-version" + ] + p = subprocess.Popen(cmd_dmidecode_version, stdout=subprocess.PIPE) + p.wait() + self.dmi_version = p.communicate()[0].decode() + cmd_dmidecode = [ + "dmidecode", + "-t", + "bios" + ] + p = subprocess.Popen(cmd_dmidecode, stdout=subprocess.PIPE) + p.wait() + if p.returncode != 0: + raise Exception("dmidecode: Reading DMI failed") + return p.communicate()[0].decode() + + def _verify_dmi(self, path, version, downgrade=False): + """Verifies DMI tables for BIOS updates. + + Keywords arguments: + path -- absolute path of the updates files + version -- version of the update + downgrade -- downgrade flag + """ + dmi_info = self._read_dmi() + path_metainfo = os.path.join(path, "firmware.metainfo.xml") + tree = ET.parse(path_metainfo) + root = tree.getroot() + vendor = root.find("developer_name").text + if vendor is None: + raise ValueError("No vendor information in firmware metainfo.") + if vendor not in dmi_info: + raise ValueError("Wrong firmware provider.") + if not downgrade and l_ver(version) <= l_ver(self.dmi_version): + raise ValueError( + f"{version} < {self.dmi_version} Downgrade not allowed" + ) + + def _get_dom0_devices(self): + """Gathers information about devices connected in dom0.""" + cmd_get_dom0_devices = [ + FWUPDAGENT, + "get-devices" + ] + p = subprocess.Popen( + cmd_get_dom0_devices, + stdout=subprocess.PIPE + ) + self.dom0_devices_info = p.communicate()[0].decode() + if p.returncode != 0: + raise Exception("fwudp-qubes: Getting devices info failed") + + def _get_usbvm_devices(self): + """Gathers information about devices connected in usbvm.""" + if os.path.exists(FWUPD_VM_LOG): + os.remove(FWUPD_VM_LOG) + usbvm_cmd = f'"{FWUPDAGENT} get-devices"' + log_file = f" > {FWUPD_VM_LOG}" + cmd_get_usbvm_devices = ( + f'qvm-run --nogui --pass-io {USBVM_N} {usbvm_cmd}{log_file}' + ) + p = subprocess.Popen( + cmd_get_usbvm_devices, + shell=True + ) + p.wait() + if (p.returncode != 0 and p.returncode != 2 + and not os.path.exists(FWUPD_VM_LOG)): + raise Exception("fwudp-qubes: Getting usbvm devices info failed") + if not os.path.exists(FWUPD_VM_LOG): + raise Exception("usbvm device info log does not exist") + + def _parse_usbvm_updates(self, usbvm_devices_info): + """Creates dictionary and list with information about updates. + + Keywords argument: + usbvm_devices_info - gathered usbvm information + """ + self.usbvm_updates_list = [] + if "No detected devices" in usbvm_devices_info: + return EXIT_CODES["NOTHING_TO_DO"] + usbvm_device_info_dict = json.loads(usbvm_devices_info) + for device in usbvm_device_info_dict["Devices"]: + if "Releases" in device: + self.usbvm_updates_list.append( + { + "Name": device["Name"], + "Version": device["Version"], + "Releases": [] + } + ) + current_version = device["Version"] + for update in device["Releases"]: + if l_ver(update["Version"]) > current_version: + self.usbvm_updates_list[-1]["Releases"].append( + { + "Version": update["Version"], + "Url": update["Uri"], + "Checksum": update["Checksum"][-1], + "Description": update["Description"] + } + ) + if not self.usbvm_updates_list[-1]["Releases"]: + self.usbvm_updates_list.pop() + + def update_firmware(self, usbvm=False, whonix=False): + """Updates firmware of the specified device. + + Keyword arguments: + usbvm -- usbvm support flag + whonix -- Flag enforces downloading the metadata updates via Tor + """ + self._get_dom0_updates() + self._parse_dom0_updates_info(self.dom0_updates_info) + if usbvm: + self._get_usbvm_devices() + with open(FWUPD_VM_LOG) as usbvm_device_info: + raw = usbvm_device_info.read() + self._parse_usbvm_updates(raw) + update_dict = { + "usbvm": self.usbvm_updates_list, + "dom0": self.dom0_updates_list + } + ret_input = self._user_input(update_dict, usbvm=True) + else: + update_dict = { + "dom0": self.dom0_updates_list + } + ret_input = self._user_input(update_dict) + if ret_input == EXIT_CODES["NOTHING_TO_DO"]: + exit(EXIT_CODES["NOTHING_TO_DO"]) + vm_name, choice = ret_input + self._parse_parameters(update_dict, vm_name, choice) + self._download_firmware_updates(self.url, self.sha, whonix=whonix) + if self.name == "System Firmware": + Path(BIOS_UPDATE_FLAG).touch(mode=0o644, exist_ok=True) + extracted_path = self.arch_path.replace(".cab", "") + self._verify_dmi(extracted_path, self.version) + if vm_name == "dom0": + self._install_dom0_firmware_update(self.arch_path) + if vm_name == "usbvm": + self._validate_usbvm_dirs() + self._copy_firmware_updates(self.arch_name) + self._validate_usbvm_archive(self.arch_name, self.sha) + self._install_usbvm_firmware_update(self.arch_name) + + def _parse_downgrades(self, device_list): + """Parses information about possible downgrades. + + Keywords argument: + device_list -- list of connected devices + """ + downgrades = [] + if "No detected devices" in device_list: + return downgrades + dom0_devices_info_dict = json.loads(device_list) + for device in dom0_devices_info_dict["Devices"]: + if "Releases" in device: + try: + version = device["Version"] + except KeyError: + continue + downgrades.append( + { + "Name": device["Name"], + "Version": device["Version"], + "Releases": [ + { + "Version": downgrade["Version"], + "Description": downgrade["Description"], + "Url": downgrade["Uri"], + "Checksum": downgrade["Checksum"][-1] + } for downgrade in device["Releases"] + if l_ver(downgrade["Version"]) < l_ver(version) + ] + } + ) + return downgrades + + def _install_dom0_firmware_downgrade(self, arch_path): + """Installs firmware downgrade for specified device. + + Keywords arguments: + arch_path - absolute path to firmware downgrade archive + """ + cmd_install = [ + FWUPDMGR, + "--allow-older", + "install", + arch_path + ] + p = subprocess.Popen(cmd_install) + p.wait() + if p.returncode != 0: + raise Exception("fwudp-qubes: Firmware downgrade failed") + + def downgrade_firmware(self, usbvm=False, whonix=False): + """Downgrades firmware of the specified device. + + Keyword arguments: + usbvm -- usbvm support flag + whonix -- Flag enforces downloading the metadata updates via Tor + """ + self._get_dom0_devices() + dom0_downgrades = self._parse_downgrades(self.dom0_devices_info) + if usbvm: + self._get_usbvm_devices() + with open(FWUPD_VM_LOG) as usbvm_device_info: + raw = usbvm_device_info.read() + usbvm_downgrades = self._parse_downgrades(raw) + downgrade_dict = { + "usbvm": usbvm_downgrades, + "dom0": dom0_downgrades + } + ret_input = self._user_input( + downgrade_dict, + downgrade=True, + usbvm=True + ) + else: + downgrade_dict = { + "dom0": dom0_downgrades + } + ret_input = self._user_input(downgrade_dict, downgrade=True) + if ret_input == EXIT_CODES["NOTHING_TO_DO"]: + exit(EXIT_CODES["NOTHING_TO_DO"]) + vm_name, device_choice, downgrade_choice = ret_input + releases = downgrade_dict[vm_name][device_choice]["Releases"] + downgrade_url = releases[downgrade_choice]["Url"] + downgrade_sha = releases[downgrade_choice]["Checksum"] + self._download_firmware_updates( + downgrade_url, + downgrade_sha, + whonix=whonix + ) + if downgrade_dict[vm_name][device_choice]["Name"] == "System Firmware": + Path(BIOS_UPDATE_FLAG).touch(mode=0o644, exist_ok=True) + extracted_path = self.arch_path.replace(".cab", "") + self._verify_dmi( + extracted_path, + downgrade_dict[vm_name][device_choice]["Version"], + downgrade=True + ) + if vm_name == "dom0": + self._install_dom0_firmware_downgrade(self.arch_path) + if vm_name == "usbvm": + self._validate_usbvm_dirs() + self._copy_firmware_updates(self.arch_name) + self._validate_usbvm_archive(self.arch_name, downgrade_sha) + self._install_usbvm_firmware_downgrade(self.arch_name) + + def _output_crawler(self, updev_dict, level, help_f=False, dom0=True): + """Prints device and updates information as a tree. + + Keywords arguments: + updev_dict -- update/device information dictionary + level -- level of the tree + """ + def _tabs(key_word): + return key_word + '\t'*(4 - int(len(key_word)/8)) + + decorator = "===================================" + print(2*decorator) + for updev_key in updev_dict: + style = '\t'*level + output = style + _tabs(updev_key + ":") + if len(updev_key) > 12: + continue + if updev_key == "Icons": + continue + if updev_key == "Releases": + continue + if updev_key == "Name": + print(style + updev_dict["Name"]) + print(2*decorator) + continue + if isinstance(updev_dict[updev_key], str): + print(output + updev_dict[updev_key]) + elif isinstance(updev_dict[updev_key], int): + print(output + str(updev_dict[updev_key])) + elif isinstance(updev_dict[updev_key][0], str): + for i, data in enumerate(updev_dict[updev_key]): + if i == 0: + print(output + u'\u00B7' + data) + continue + print(style + _tabs(' ') + u'\u00B7' + data) + elif isinstance(updev_dict[updev_key][0], dict): + if level == 0 and help_f is True: + print(output) + else: + if level == 0 and dom0 is True: + print(f"Dom0 {output}") + elif level == 0 and dom0 is False: + print(f"{USBVM_N} {output}") + + for nested_dict in updev_dict[updev_key]: + self._output_crawler(nested_dict, level+1) + + def _updates_crawler(self, updates_list, usbvm=False, prefix=0): + """Prints updates information for dom0 and usbvm + + Keywords arguments: + updates_list -- list of devices updates + usbvm -- usbvm support flag + prefix -- device number prefix + """ + available_updates = False + decorator = "======================================================" + print(decorator) + if usbvm: + print(f"{USBVM_N} updates:") + else: + print("Dom0 updates:") + print(decorator) + if len(updates_list) == 0: + print("No updates available.") + return EXIT_CODES["NOTHING_TO_DO"] + else: + for i, device in enumerate(updates_list): + if len(device["Releases"]) == 0: + continue + if not available_updates: + print("Available updates:") + print(decorator) + print("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^") + print(f"{i+1+prefix}. Device: {device['Name']}") + print(f" Current firmware version:\t {device['Version']}") + for update in device["Releases"]: + print(decorator) + print( + " Firmware update " + f"version:\t {update['Version']}" + ) + print(f" URL:\t {update['Url']}") + print(f" SHA256 checksum:\t {update['Checksum']}") + description = update["Description"].replace("

    ", "") + description = description.replace("

  • ", "") + description = description.replace("
      ", "") + description = description.replace("
    ", "") + description = description.replace("

    ", "\n\t") + description = description.replace("
  • ", "\n\t") + print(f" Description: {description}") + print(decorator) + available_updates = True + if not available_updates: + print("No updates available.") + return EXIT_CODES["NOTHING_TO_DO"] + + def get_devices_qubes(self, usbvm=False): + """Gathers and prints devices information. + + Keyword arguments: + usbvm -- usbvm support flag + """ + self._get_dom0_devices() + dom0_devices_info_dict = json.loads(self.dom0_devices_info) + self._output_crawler(dom0_devices_info_dict, 0) + if usbvm: + self._get_usbvm_devices() + with open(FWUPD_VM_LOG) as usbvm_device_info: + raw = usbvm_device_info.read() + if "No detected devices" not in raw: + usbvm_device_info_dict = json.loads(raw) + else: + print(f"No detected devices in {USBVM_N}") + return EXIT_CODES["NOTHING_TO_DO"] + self._output_crawler(usbvm_device_info_dict, 0, dom0=False) + + def get_updates_qubes(self, usbvm=False): + """Gathers and prints updates information. + + Keyword arguments: + usbvm -- usbvm support flag + """ + self._get_dom0_updates() + self._parse_dom0_updates_info(self.dom0_updates_info) + self._updates_crawler(self.dom0_updates_list) + if usbvm: + self._get_usbvm_devices() + with open(FWUPD_VM_LOG) as usbvm_device_info: + raw = usbvm_device_info.read() + self._parse_usbvm_updates(raw) + self._updates_crawler(self.usbvm_updates_list, usbvm=True) + + def help(self): + """Prints help information""" + self._output_crawler(HELP, 0, help_f=True) + + def check_usbvm(self): + """Checks if usbvm is running""" + cmd_xl_list = [ + "xl", + "list" + ] + p = subprocess.Popen( + cmd_xl_list, + stdout=subprocess.PIPE + ) + self.output = p.communicate()[0].decode() + if p.returncode != 0: + raise Exception("fwudp-qubes: Firmware downgrade failed") + return USBVM_N in self.output + + def trusted_cleanup(self, usbvm=False): + """Deletes trusted directory. + + Keyword arguments: + usbvm -- usbvm support flag + """ + trusted_path = os.path.join(FWUPD_DOM0_UPDATES_DIR, "trusted.cab") + if os.path.exists(trusted_path): + os.remove(trusted_path) + shutil.rmtree(trusted_path.replace(".cab", "")) + if usbvm: + self._clean_usbvm() + + def refresh_metadata_after_bios_update(self, usbvm=False): + """Refreshes metadata after bios update + + Keyword arguments: + usbvm -- usbvm support flag + """ + if os.path.exists(BIOS_UPDATE_FLAG): + print("BIOS was updated. Refreshing metadata...") + if "--whonix" in sys.argv: + self.refresh_metadata(usbvm=usbvm, whonix=True) + else: + self.refresh_metadata(usbvm=usbvm) + os.remove(BIOS_UPDATE_FLAG) + + def heads_update(self, device="x230", whonix=False, metadata_url=None): + """ + Updates heads firmware + + Keyword arguments: + device -- Model of the updated device + whonix -- Flag enforces downloading the metadata updates via Tor + metadata_url -- Use custom metadata from the url + """ + self._check_fwupdtool_version() + if metadata_url: + custom_metadata_name = metadata_url.replace( + FWUPD_DOWNLOAD_PREFIX, + "" + ) + self.metadata_file = os.path.join( + FWUPD_DOM0_METADATA_DIR, + custom_metadata_name + ) + else: + self.metadata_file = FWUPD_DOM0_METADATA_FILE + self._get_hwids() + self._download_metadata(whonix=whonix, metadata_url=metadata_url) + self._parse_metadata(self.metadata_file) + if self._gather_firmware_version() == EXIT_CODES["NOTHING_TO_DO"]: + return EXIT_CODES["NOTHING_TO_DO"] + if self._parse_heads_updates(device) == EXIT_CODES["NOTHING_TO_DO"]: + return EXIT_CODES["NOTHING_TO_DO"] + self._download_firmware_updates( + self.heads_update_url, + self.heads_update_sha + ) + return_code = self._copy_heads_firmware(self.arch_path) + if return_code == EXIT_CODES["NOTHING_TO_DO"]: + exit(EXIT_CODES["NOTHING_TO_DO"]) + elif return_code == EXIT_CODES["SUCCESS"]: + print() + while True: + try: + print("An update requires a reboot to complete.") + choice = input("Do you want to restart now? (Y|N)\n") + if choice == 'N' or choice == 'n': + return EXIT_CODES["SUCCESS"] + elif choice == 'Y' or choice == 'y': + print("Rebooting...") + os.system("reboot") + else: + raise ValueError() + except ValueError: + print("Invalid choice.") + else: + raise Exception("Copying heads update failed!!") + + def validate_dom0_dirs(self): + """Validates and creates directories""" + if not os.path.exists(FWUPD_DOM0_DIR): + self._create_dirs(FWUPD_DOM0_DIR) + if os.path.exists(FWUPD_DOM0_METADATA_DIR): + shutil.rmtree(FWUPD_DOM0_METADATA_DIR) + self._create_dirs(FWUPD_DOM0_METADATA_DIR) + else: + self._create_dirs(FWUPD_DOM0_METADATA_DIR) + if not os.path.exists(FWUPD_DOM0_UPDATES_DIR): + self._create_dirs(FWUPD_DOM0_UPDATES_DIR) + os.umask(self.old_umask) + + +def main(): + if os.geteuid() != 0: + print("You need to have root privileges to run this script.\n") + exit(EXIT_CODES["ERROR"]) + + q = QubesFwupdmgr() + sys_usb = q.check_usbvm() + q.validate_dom0_dirs() + q.trusted_cleanup(usbvm=sys_usb) + q.refresh_metadata_after_bios_update(usbvm=sys_usb) + + metadata_url = None + device = "x230" + + if not os.path.exists(FWUPD_DOM0_DIR): + q.refresh_metadata(usbvm=sys_usb) + + if len(sys.argv) < 2: + q.help() + exit(1) + for arg in sys.argv: + if "--url=" in arg: + metadata_url = arg.replace("--url=", "") + if FWUPD_DOWNLOAD_PREFIX not in metadata_url: + print( + "Metadata must be stored in the Linux" + " Vendor Firmware Service (https://fwupd.org/)" + ) + print("Exiting...") + exit(1) + if "--device=" in arg: + device = arg.replace("--board=", "") + + if sys.argv[1] == "get-updates": + q.get_updates_qubes(usbvm=sys_usb) + elif sys.argv[1] == "get-devices": + q.get_devices_qubes(usbvm=sys_usb) + elif sys.argv[1] == "update" and "--whonix" in sys.argv: + q.update_firmware(usbvm=sys_usb, whonix=True) + elif sys.argv[1] == "update" and "--whonix" not in sys.argv: + q.update_firmware(usbvm=sys_usb) + elif sys.argv[1] == "downgrade" and "--whonix" in sys.argv: + q.downgrade_firmware(usbvm=sys_usb, whonix=True) + elif sys.argv[1] == "downgrade" and "--whonix" not in sys.argv: + q.downgrade_firmware(usbvm=sys_usb) + elif sys.argv[1] == "clean": + q.clean_cache(usbvm=sys_usb) + elif sys.argv[1] == "refresh" and "--whonix" not in sys.argv: + q.refresh_metadata(usbvm=sys_usb, metadata_url=metadata_url) + elif sys.argv[1] == "refresh" and "--whonix" in sys.argv: + q.refresh_metadata( + usbvm=sys_usb, + whonix=True, + metadata_url=metadata_url + ) + elif sys.argv[1] == "update-heads" and "--whonix" not in sys.argv: + q.heads_update(device=device, metadata_url=metadata_url) + elif sys.argv[1] == "update-heads" and "--whonix" in sys.argv: + q.heads_update(device=device, metadata_url=metadata_url, whonix=True) + else: + q.help() + exit(1) + + +if __name__ == '__main__': + main() diff -Nru fwupd-1.4.5/contrib/qubes/src/qubes_fwupd_update.py fwupd-1.5.8/contrib/qubes/src/qubes_fwupd_update.py --- fwupd-1.4.5/contrib/qubes/src/qubes_fwupd_update.py 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/qubes/src/qubes_fwupd_update.py 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,169 @@ +#!/usr/bin/python3 +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2021 Norbert Kaminski +# +# SPDX-License-Identifier: LGPL-2.1+ +# + +import grp +import os +import re +import subprocess + +FWUPD_DOM0_DIR = "/root/.cache/fwupd" +FWUPD_VM_DOWNLOAD = "/usr/libexec/qubes-fwupd/fwupd_download_updates.py" +FWUPD_DOM0_UPDATES_DIR = os.path.join(FWUPD_DOM0_DIR, "updates") +FWUPD_DOWNLOAD_PREFIX = "https://fwupd.org/downloads/" + +SPECIAL_CHAR_REGEX = re.compile(r'%20|&|\||#') +UPDATEVM_REGEX = re.compile(r'^sys-') + +WARNING_COLOR = '\033[93m' + + +class FwupdUpdate: + def _create_dirs(self, *args): + """Method creates directories. + + Keyword arguments: + *args -- paths to be created + """ + qubes_gid = grp.getgrnam('qubes').gr_gid + self.old_umask = os.umask(0o002) + if args is None: + raise Exception("Creating directories failed, no paths given.") + for file_path in args: + if not os.path.exists(file_path): + os.mkdir(file_path) + os.chown(file_path, -1, qubes_gid) + elif os.stat(file_path).st_gid != qubes_gid: + print( + f"{WARNING_COLOR}Warning: You should move a personal files" + f" from {file_path}. Cleaning cache will cause lose of " + f"the personal data!!{WARNING_COLOR}" + ) + + def _specify_updatevm(self): + cmd_updatevm = [ + "qubes-prefs", + "--force-root", + "updatevm", + ] + p = subprocess.Popen( + cmd_updatevm, + stdout=subprocess.PIPE + ) + self.updatevm = p.communicate()[0].decode().split("\n")[0] + if p.returncode != 0 and not UPDATEVM_REGEX.match(self.updatevm): + self.updatevm = None + raise Exception("Specifing updatevm failed") + + def _check_updatevm(self): + """Checks if usbvm is running""" + cmd_xl_list = [ + "xl", + "list" + ] + p = subprocess.Popen( + cmd_xl_list, + stdout=subprocess.PIPE + ) + output = p.communicate()[0].decode() + if p.returncode != 0: + raise Exception("fwudp-qubes: Firmware downgrade failed") + return self.updatevm in output + + def _encrypt_update_url(self, url): + self.enc_url = url + self.arch_name = url.replace(FWUPD_DOWNLOAD_PREFIX, "") + self.arch_path = os.path.join(FWUPD_DOM0_UPDATES_DIR, self.arch_name) + if "&" in url: + self.enc_url = self.enc_url.replace("&", "--and--") + self.arch_name = "untrusted.cab" + if "|" in url: + self.enc_url = self.enc_url.replace("|", "--or--") + self.arch_name = "untrusted.cab" + if "#" in url: + self.enc_url = self.enc_url.replace("#", "--hash--") + self.arch_name = "untrusted.cab" + if "%20" in url: + self.arch_name = "untrusted.cab" + + def download_metadata(self, whonix=False, metadata_url=None): + """Initialize downloading metadata files. + + Keywords arguments: + whonix -- Flag enforces downloading the metadata updates via Tor + metadata_url -- Download metadata from the custom url + """ + if not whonix: + self._specify_updatevm() + else: + self.updatevm = "sys-whonix" + if not self._check_updatevm(): + raise Exception(f"{self.updatevm} is not running!!") + if not os.path.exists(FWUPD_DOM0_DIR): + self._create_dirs(FWUPD_DOM0_DIR) + if metadata_url: + cmd_metadata = [ + "qvm-run", + "--pass-io", + self.updatevm, + ( + 'script --quiet --return --command ' + f'"{FWUPD_VM_DOWNLOAD} --metadata' + f' --url={metadata_url}"' + ) + ] + else: + cmd_metadata = [ + "qvm-run", + "--pass-io", + self.updatevm, + ( + 'script --quiet --return --command ' + f'"{FWUPD_VM_DOWNLOAD} --metadata"' + ) + ] + p = subprocess.Popen(cmd_metadata) + p.wait() + if p.returncode != 0: + raise Exception("Metadata download failed.") + + def download_firmware_updates(self, url, sha, whonix=False): + """Initializes downloading firmware upadate archive. + + Keywords arguments: + url -- url path to the firmware upadate archive + sha -- SHA256 checksum of the firmware update archive + whonix -- Flag enforces downloading the updates via Tor + """ + if not whonix: + self._specify_updatevm() + else: + self.updatevm = "sys-whonix" + if not self._check_updatevm(): + raise Exception(f"{self.updatevm} is not running!!") + if not os.path.exists(FWUPD_DOM0_DIR): + self._create_dirs(FWUPD_DOM0_DIR) + self._encrypt_update_url(url) + if not os.path.exists(self.arch_path): + cmd_firmware_download = [ + "qvm-run", + "--pass-io", + self.updatevm, + ( + 'script --quiet --return --command ' + f'"{FWUPD_VM_DOWNLOAD} --url={self.enc_url}' + f' --sha={sha}"' + ) + ] + p = subprocess.Popen(cmd_firmware_download) + p.wait() + if p.returncode != 0: + raise Exception("Firmware download failed.") + else: + self.cached = True + print("Firmware already downloaded. Using cached files.") diff -Nru fwupd-1.4.5/contrib/qubes/src/vms/fwupd_common_vm.py fwupd-1.5.8/contrib/qubes/src/vms/fwupd_common_vm.py --- fwupd-1.4.5/contrib/qubes/src/vms/fwupd_common_vm.py 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/qubes/src/vms/fwupd_common_vm.py 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,109 @@ +#!/usr/bin/python3 +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2021 Norbert Kamiński +# +# SPDX-License-Identifier: LGPL-2.1+ +# + +import grp +import hashlib +import os +import shutil +import subprocess + +FWUPD_VM_DIR = "/home/user/.cache/fwupd" +FWUPD_VM_UPDATES_DIR = os.path.join(FWUPD_VM_DIR, "updates") +FWUPD_VM_METADATA_DIR = os.path.join(FWUPD_VM_DIR, "metadata") +WARNING_COLOR = '\033[93m' +FWUPD_PKI = "/etc/pki/fwupd" + + +class FwupdVmCommon: + def _create_dirs(self, *args): + """Method creates directories. + + Keyword arguments: + *args -- paths to be created + """ + qubes_gid = grp.getgrnam('qubes').gr_gid + self.old_umask = os.umask(0o002) + if args is None: + raise Exception("Creating directories failed, no paths given.") + for file_path in args: + if not os.path.exists(file_path): + os.mkdir(file_path) + os.chown(file_path, -1, qubes_gid) + elif os.stat(file_path).st_gid != qubes_gid: + print( + f"{WARNING_COLOR}Warning: You should move a personal files" + f" from {file_path}. Cleaning cache will cause lose of " + f"the personal data!!{WARNING_COLOR}" + ) + + def check_shasum(self, file_path, sha): + """Compares computed SHA256 checksum with `sha` parameter. + + Keyword arguments: + file_path -- absolute path to the file + sha -- SHA256 checksum of the file + """ + with open(file_path, 'rb') as f: + c_sha = hashlib.sha256(f.read()).hexdigest() + if c_sha != sha: + self.clean_vm_cache() + raise ValueError( + "Computed checksum %s did NOT match %s. " % + (c_sha, sha) + ) + + def validate_vm_dirs(self): + """Validates and creates directories""" + print("Validating directories") + if not os.path.exists(FWUPD_VM_DIR): + self._create_dirs(FWUPD_VM_DIR) + if os.path.exists(FWUPD_VM_METADATA_DIR): + shutil.rmtree(FWUPD_VM_METADATA_DIR) + self._create_dirs(FWUPD_VM_METADATA_DIR) + else: + self._create_dirs(FWUPD_VM_METADATA_DIR) + if not os.path.exists(FWUPD_VM_UPDATES_DIR): + self._create_dirs(FWUPD_VM_UPDATES_DIR) + os.umask(self.old_umask) + + def _jcat_verification(self, file_path, file_directory): + """Verifies sha1 and sha256 checksum, GPG signature, + and PKCS#7 signature. + + Keyword argument: + file_path -- absolute path to jcat file + file_directory -- absolute path to the directory to jcat file location + """ + cmd_jcat = [ + "jcat-tool", + "verify", + f"{file_path}", + "--public-keys", + FWUPD_PKI + ] + p = subprocess.Popen( + cmd_jcat, + cwd=file_directory, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE + ) + stdout, __ = p.communicate() + verification = stdout.decode('utf-8') + print(verification) + if p.returncode != 0: + self.clean_vm_cache() + raise Exception('jcat-tool: Verification failed') + + def clean_vm_cache(self): + """Removes updates data""" + print("Cleaning cache directories") + if os.path.exists(FWUPD_VM_METADATA_DIR): + shutil.rmtree(FWUPD_VM_METADATA_DIR) + if os.path.exists(FWUPD_VM_UPDATES_DIR): + shutil.rmtree(FWUPD_VM_UPDATES_DIR) diff -Nru fwupd-1.4.5/contrib/qubes/src/vms/fwupd_download_updates.py fwupd-1.5.8/contrib/qubes/src/vms/fwupd_download_updates.py --- fwupd-1.4.5/contrib/qubes/src/vms/fwupd_download_updates.py 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/qubes/src/vms/fwupd_download_updates.py 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,149 @@ +#!/usr/bin/python3 +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2021 Norbert Kamiński +# +# SPDX-License-Identifier: LGPL-2.1+ +# +import sys +import subprocess +import os + +from fwupd_common_vm import FwupdVmCommon + +FWUPD_VM_DIR = "/home/user/.cache/fwupd" +FWUPD_VM_UPDATES_DIR = os.path.join(FWUPD_VM_DIR, "updates") +FWUPD_VM_METADATA_DIR = os.path.join(FWUPD_VM_DIR, "metadata") +FWUPD_DOWNLOAD_PREFIX = "https://fwupd.org/downloads/" +METADATA_URL = "https://fwupd.org/downloads/firmware.xml.gz" +METADATA_URL_JCAT = "https://fwupd.org/downloads/firmware.xml.gz.jcat" + + +class DownloadData(FwupdVmCommon): + def _decrypt_update_url(self, url): + self.dec_url = url + if "--and--" in url: + self.dec_url = self.dec_url.replace("--and--", "&") + self.arch_name = "untrusted.cab" + if "--or--" in url: + self.dec_url = self.dec_url.replace("--or--", "|") + self.arch_name = "untrusted.cab" + if "--hash--" in url: + self.dec_url = self.dec_url.replace("--hash--", "#") + self.arch_name = "untrusted.cab" + if "%20" in url: + self.arch_name = "untrusted.cab" + + def _download_metadata_file(self): + """Download metadata file""" + if self.custom_url is None: + metadata_url = METADATA_URL + else: + metadata_url = self.custom_url + cmd_metadata = [ + "wget", + "-P", + FWUPD_VM_METADATA_DIR, + metadata_url + ] + p = subprocess.Popen(cmd_metadata) + p.wait() + if p.returncode != 0: + raise Exception("fwudp-qubes: Downloading metadata file failed") + if not os.path.exists(self.metadata_file): + raise FileNotFoundError( + "fwudp-qubes: Downloaded metadata file does not exist" + ) + + def _download_metadata_jcat(self): + """Download metadata jcat signature""" + if self.custom_url is None: + metadata_url = METADATA_URL + else: + metadata_url = self.custom_url + cmd_metadata = [ + "wget", + "-P", + FWUPD_VM_METADATA_DIR, + f"{metadata_url}.jcat" + ] + p = subprocess.Popen(cmd_metadata) + p.wait() + if p.returncode != 0: + raise Exception("fwudp-qubes: Downloading metadata file failed") + if not os.path.exists(f"{self.metadata_file}.jcat"): + raise FileNotFoundError( + "fwudp-qubes: Downloaded metadata file does not exist" + ) + + def download_metadata(self, url=None): + """Downloads default metadata and its signatures""" + if url is not None: + self.custom_url = url + custom_metadata_name = url.replace( + FWUPD_DOWNLOAD_PREFIX, + "" + ) + self.metadata_file = os.path.join( + FWUPD_VM_METADATA_DIR, + custom_metadata_name + ) + else: + self.custom_url = None + self.metadata_file = os.path.join( + FWUPD_VM_METADATA_DIR, + "firmware.xml.gz" + ) + self.validate_vm_dirs() + self._download_metadata_file() + self._download_metadata_jcat() + + def download_updates(self, url, sha): + """ + Downloads update form given url + + Keyword argument: + url - url address of the update + """ + self.validate_vm_dirs() + self.arch_name = url.replace("https://fwupd.org/downloads/", "") + self._decrypt_update_url(url) + update_path = os.path.join(FWUPD_VM_UPDATES_DIR, self.arch_name) + cmd_update = [ + "wget", + "-O", + update_path, + self.dec_url + ] + p = subprocess.Popen(cmd_update) + p.wait() + if p.returncode != 0: + raise Exception("fwudp-qubes: Downloading update file failed") + if not os.path.exists(update_path): + raise FileNotFoundError( + "fwudp-qubes: Downloaded update file does not exist" + ) + self.check_shasum(update_path, sha) + print("Update file downloaded successfully") + + +def main(): + url = None + sha = None + dn = DownloadData() + for arg in sys.argv: + if "--url=" in arg: + url = arg.replace("--url=", "") + if "--sha=" in arg: + sha = arg.replace("--sha=", "") + if "--metadata" in sys.argv: + dn.download_metadata(url=url) + elif url and sha: + dn.download_updates(url, sha) + else: + raise Exception("Invalid command!!!") + + +if __name__ == '__main__': + main() diff -Nru fwupd-1.4.5/contrib/qubes/src/vms/fwupd_usbvm_validate.py fwupd-1.5.8/contrib/qubes/src/vms/fwupd_usbvm_validate.py --- fwupd-1.4.5/contrib/qubes/src/vms/fwupd_usbvm_validate.py 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/qubes/src/vms/fwupd_usbvm_validate.py 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,158 @@ +#!/usr/bin/python3 +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2021 Norbert Kamiński +# +# SPDX-License-Identifier: LGPL-2.1+ +# + +import glob +import os +import shutil +import subprocess +import sys + +from fwupd_common_vm import FwupdVmCommon + +FWUPD_VM_DIR = "/home/user/.cache/fwupd" +FWUPD_VM_UPDATES_DIR = os.path.join(FWUPD_VM_DIR, "updates") +FWUPD_VM_METADATA_DIR = os.path.join(FWUPD_VM_DIR, "metadata") +FWUPD_VM_METADATA_JCAT = os.path.join( + FWUPD_VM_METADATA_DIR, + "firmware.xml.gz.jcat" +) +FWUPD_VM_METADATA_FILE = os.path.join( + FWUPD_VM_METADATA_DIR, + "firmware.xml.gz" +) +FWUPDMGR = "/bin/fwupdmgr" +FWUPD_DOWNLOAD_PREFIX = "https://fwupd.org/downloads/" + + +class FwupdUsbvmUpdates(FwupdVmCommon): + def _verify_received(self, files_path, regex_pattern): + """Checks if sent files match regex filename pattern. + + Keyword arguments: + + files_path -- absolute path to inspected directory + regex_pattern -- pattern of the expected files + """ + for untrusted_f in os.listdir(files_path): + if not regex_pattern.match(untrusted_f): + raise Exception( + 'Dom0 sent unexpected file' + ) + f = untrusted_f + assert '/' not in f + assert '\0' not in f + assert '\x1b' not in f + path_f = os.path.join(files_path, f) + if os.path.islink(path_f) or not os.path.isfile(path_f): + raise Exception( + 'Dom0 sent not regular file' + ) + + def _extract_archive(self, archive_path, output_path): + """Extracts archive file to the specified directory. + + Keyword arguments: + archive_path -- absolute path to archive file + output_path -- absolute path to the output directory + """ + cmd_extract = [ + "gcab", + "-x", + f"--directory={output_path}", + f"{archive_path}" + ] + p = subprocess.Popen(cmd_extract, stdout=subprocess.PIPE) + p.communicate()[0].decode('ascii') + if p.returncode != 0: + raise Exception( + 'gcab: Error while extracting %s.' % + archive_path + ) + + def validate_metadata(self, metadata_url=None): + """Validates received the metadata files.""" + print("Running validation of the metadata files") + if metadata_url: + metadata_name = metadata_url.replace( + FWUPD_DOWNLOAD_PREFIX, + "" + ) + metadata_file = os.path.join( + FWUPD_VM_METADATA_DIR, + metadata_name + ) + else: + metadata_file = FWUPD_VM_METADATA_FILE + try: + self._jcat_verification( + f"{metadata_file}.jcat", + FWUPD_VM_METADATA_DIR + ) + except Exception as e: + print(str(e), file=sys.stderr) + self.clean_vm_cache() + exit(1) + + def validate_updates(self, archive_path, sha): + """Validates recived an update file. + + Keyword arguments: + archive_path - path to the firmware update archive + sha -- SHA256 checksum of the firmware update archive + """ + print("Running validation of the update archive") + self.check_shasum(archive_path, sha) + archive_name = archive_path.replace(f"{FWUPD_VM_UPDATES_DIR}/", "") + output_path = archive_path.replace(".cab", "") + arch_temp = os.path.join(output_path, archive_name) + os.mkdir(output_path) + shutil.copyfile(archive_path, arch_temp) + self._extract_archive( + arch_temp, + output_path + ) + signature_name = os.path.join(output_path, "firmware*.jcat") + file_path = glob.glob(signature_name) + try: + self._jcat_verification(file_path[0], output_path) + shutil.rmtree(output_path) + except Exception as e: + print(str(e), file=sys.stderr) + self.clean_vm_cache() + exit(1) + + +def main(): + f = FwupdUsbvmUpdates() + f_val = FwupdVmCommon() + metadata_url = None + if len(sys.argv) < 2: + raise Exception("Invalid number of arguments.") + for arg in sys.argv: + if "--url=" in arg: + metadata_url = arg.replace("--url=", "") + if sys.argv[1] == "metadata": + f.validate_metadata(metadata_url=metadata_url) + elif sys.argv[1] == "dirs": + f_val.validate_vm_dirs() + elif sys.argv[1] == "clean": + f.clean_vm_cache() + elif sys.argv[1] == "updates" and len(sys.argv) < 4: + raise Exception( + "Invalid number of arguments.\n" + "Expected archive path and checksum." + ) + elif sys.argv[1] == "updates" and not len(sys.argv) < 4: + f.validate_updates(sys.argv[2], sys.argv[3]) + else: + raise Exception("Invaild command") + + +if __name__ == '__main__': + main() diff -Nru fwupd-1.4.5/contrib/qubes/test/fwupd_logs.py fwupd-1.5.8/contrib/qubes/test/fwupd_logs.py --- fwupd-1.4.5/contrib/qubes/test/fwupd_logs.py 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/qubes/test/fwupd_logs.py 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,859 @@ +#!/usr/bin/python3 +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2021 Norbert Kamiński +# +# SPDX-License-Identifier: LGPL-2.1+ +# + +UPDATE_INFO = """{ + "Devices" : [ + { + "Name" : "ColorHug2", + "DeviceId" : "b0a78eb71f4eeea7df8fb114522556ba8ce22074", + "Guid" : [ + "2082b5e0-7a64-478a-b1b2-e3404fab6dad", + "aa4b4156-9732-55db-9500-bf6388508ee3", + "101ee86a-7bea-59fb-9f89-6b6297ceed3b", + "2fa8891f-3ece-53a4-adc4-0dd875685f30" + ], + "Summary" : "An open source display colorimeter", + "Plugin" : "colorhug", + "Protocol" : "com.hughski.colorhug", + "Flags" : [ + "updatable", + "supported", + "registered", + "self-recovery", + "add-counterpart-guids" + ], + "Vendor" : "Hughski Ltd.", + "VendorId" : "USB:0x273F", + "Version" : "2.0.6", + "VersionFormat" : "triplet", + "Icons" : [ + "colorimeter-colorhug" + ], + "InstallDuration" : 8, + "Created" : 1614224175, + "Releases" : [ + { + "AppstreamId" : "com.hughski.ColorHug2.firmware", + "RemoteId" : "lvfs", + "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter", + "Description" : "

    This release fixes prevents the firmware returning an error when the remote SHA1 hash was never sent.

    ", + "Version" : "2.0.7", + "Filename" : "hughski-colorhug2-2.0.7.cab", + "Protocol" : "com.hughski.colorhug", + "Checksum" : [ + "80bddeb898cda5b87d9837e13a9ace19846053bf", + "32c4a2c9be787cdf1d757c489d6455bd7bb14053425180b6d331c37e1ccc1cda" + ], + "License" : "GPL-2.0+", + "Size" : 16384, + "Created" : 1482901200, + "Locations" : [ + "https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab", + "ipfs://QmUByRuHG9Gb2s8gKKVqDcjhUrn8vy62B4WqjbpWDD42cf" + ], + "Uri" : "https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab", + "Homepage" : "http://www.hughski.com/", + "SourceUrl" : "https://github.com/hughski/colorhug2-firmware", + "Vendor" : "Hughski Limited", + "Flags" : [ + "is-upgrade" + ], + "InstallDuration" : 8 + } + ] + } + ] + } +""" + +DMI_DECODE = """# dmidecode 3.1 +Getting SMBIOS data from sysfs. +SMBIOS 3.1.1 present. + +Handle 0x0000, DMI type 0, 26 bytes +BIOS Information + Vendor: Dell Inc. + Version: P1.00 + Release Date: 02/09/2018 + Address: 0xF0000 + Runtime Size: 64 kB + ROM Size: 16 MB + Characteristics: + PCI is supported + BIOS is upgradeable + BIOS shadowing is allowed + Boot from CD is supported + Selectable boot is supported + BIOS ROM is socketed + EDD is supported + 5.25"/1.2 MB floppy services are supported (int 13h) + 3.5"/720 kB floppy services are supported (int 13h) + 3.5"/2.88 MB floppy services are supported (int 13h) + Print screen service is supported (int 5h) + 8042 keyboard services are supported (int 9h) + Serial services are supported (int 14h) + Printer services are supported (int 17h) + ACPI is supportedUSB legacy is supported + BIOS boot specification is supported + Targeted content distribution is supported + UEFI is supported + BIOS Revision: 5.13 +""" + +GET_DEVICES = """{ + "Devices" : [ + { + "Name" : "ColorHug2", + "DeviceId" : "cf294bf55b333004beb7c41f952c1838c23e1f4a", + "Guid" : [ + "2082b5e0-7a64-478a-b1b2-e3404fab6dad", + "aa4b4156-9732-55db-9500-bf6388508ee3", + "101ee86a-7bea-59fb-9f89-6b6297ceed3b", + "2fa8891f-3ece-53a4-adc4-0dd875685f30" + ], + "Summary" : "An open source display colorimeter", + "Plugin" : "colorhug", + "Protocol" : "com.hughski.colorhug", + "Flags" : [ + "updatable", + "supported", + "registered", + "self-recovery", + "add-counterpart-guids" + ], + "Vendor" : "Hughski Ltd.", + "VendorId" : "USB:0x273F", + "Version" : "2.0.6", + "VersionFormat" : "triplet", + "Icons" : [ + "colorimeter-colorhug" + ], + "InstallDuration" : 8, + "Created" : 1614246373, + "Releases" : [ + { + "AppstreamId" : "com.hughski.ColorHug2.firmware", + "RemoteId" : "lvfs", + "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter", + "Description" : "

    This release fixes prevents the firmware returning an error when the remote SHA1 hash was never sent.

    ", + "Version" : "2.0.7", + "Filename" : "hughski-colorhug2-2.0.7.cab", + "Protocol" : "com.hughski.colorhug", + "Checksum" : [ + "80bddeb898cda5b87d9837e13a9ace19846053bf", + "32c4a2c9be787cdf1d757c489d6455bd7bb14053425180b6d331c37e1ccc1cda" + ], + "License" : "GPL-2.0+", + "Size" : 16384, + "Created" : 1482901200, + "Locations" : [ + "https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab", + "ipfs://QmUByRuHG9Gb2s8gKKVqDcjhUrn8vy62B4WqjbpWDD42cf" + ], + "Uri" : "https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab", + "Homepage" : "http://www.hughski.com/", + "SourceUrl" : "https://github.com/hughski/colorhug2-firmware", + "Vendor" : "Hughski Limited", + "Flags" : [ + "is-upgrade" + ], + "InstallDuration" : 8 + }, + { + "AppstreamId" : "com.hughski.ColorHug2.firmware", + "RemoteId" : "lvfs", + "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter", + "Description" : "

    This stable release fixes the following problems:

    • Fix the swapped LEDs on the second half of batch 16
    • Fix the firmware upgrade process using new versions of fwupd
    ", + "Version" : "2.0.6", + "Filename" : "hughski-colorhug2-2.0.6.cab", + "Protocol" : "com.hughski.colorhug", + "Checksum" : [ + "60e28bb402b427dbce19e150d63987f5e18c1880", + "a646b1798ce7f5ac26229aa85c35cc4f44a5bd8bfc9e5332a8ec815aef075566" + ], + "License" : "GPL-2.0+", + "Size" : 16384, + "Created" : 1450792062, + "Locations" : [ + "https://fwupd.org/downloads/170f2c19f17b7819644d3fcc7617621cc3350a04-hughski-colorhug2-2.0.6.cab", + "ipfs://QmdWFrYo1YJxgGU37Qy7LkwPQM26vPMVxLRANUga6TzSjW" + ], + "Uri" : "https://fwupd.org/downloads/170f2c19f17b7819644d3fcc7617621cc3350a04-hughski-colorhug2-2.0.6.cab", + "Homepage" : "http://www.hughski.com/", + "SourceUrl" : "https://github.com/hughski/colorhug2-firmware", + "Vendor" : "Hughski Limited", + "InstallDuration" : 8 + }, + { + "AppstreamId" : "com.hughski.ColorHug2.firmware", + "RemoteId" : "lvfs", + "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter", + "Description" : "

    This stable release fixes the following problems:

    • Fix the swapped LEDs on batch 16
    • Make the self test more sensitive to detect floating pins
    ", + "Version" : "2.0.5", + "Filename" : "hughski-colorhug2-2.0.5.cab", + "Protocol" : "com.hughski.colorhug", + "Checksum" : [ + "e37b9d360d61157657335d80585a005ff2593108", + "8cd379eb2e1467e4fda92c20650306dc7e598b1d421841bbe19d9ed6ea01e3ee" + ], + "License" : "GPL-2.0+", + "Size" : 16384, + "Created" : 1444059405, + "Locations" : [ + "https://fwupd.org/downloads/f7dd4ab29fa610438571b8b62b26b0b0e57bb35b-hughski-colorhug2-2.0.5.cab", + "ipfs://QmQ648kwvv52wuqPoKjm5zLGXngQnmuJzp1xtJmTEbzgz5" + ], + "Uri" : "https://fwupd.org/downloads/f7dd4ab29fa610438571b8b62b26b0b0e57bb35b-hughski-colorhug2-2.0.5.cab", + "Homepage" : "http://www.hughski.com/", + "SourceUrl" : "https://github.com/hughski/colorhug2-firmware", + "Vendor" : "Hughski Limited", + "Flags" : [ + "is-downgrade" + ], + "InstallDuration" : 8 + }, + { + "AppstreamId" : "com.hughski.ColorHug2.firmware", + "RemoteId" : "lvfs", + "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter", + "Description" : "

    This unstable release adds the following features:

    • Add TakeReadingArray to enable panel latency measurements
    • Speed up the auto-scaled measurements considerably, using 256ms as the smallest sample duration
    ", + "Version" : "2.0.2", + "Filename" : "hughski-colorhug2-2.0.2.cab", + "Protocol" : "com.hughski.colorhug", + "Checksum" : [ + "1b43bd71bbed2cf0e9c9efcca79799f07b3d0dd2", + "c09674fb818d4a1033dbde2fab5885716aed1d8b751b428f16687a78f2a4d61f" + ], + "License" : "GPL-2.0+", + "Size" : 15680, + "Created" : 1416675439, + "Locations" : [ + "https://fwupd.org/downloads/30a121f26c039745aeb5585252d4a9b5386d71cb-hughski-colorhug2-2.0.2.cab", + "ipfs://QmZ1DKKsWZQuvnff2DJTDJESMaXTpsc5zfNGX7Sb2HibAn" + ], + "Uri" : "https://fwupd.org/downloads/30a121f26c039745aeb5585252d4a9b5386d71cb-hughski-colorhug2-2.0.2.cab", + "Homepage" : "http://www.hughski.com/", + "SourceUrl" : "https://github.com/hughski/colorhug2-firmware", + "Vendor" : "Hughski Limited", + "Flags" : [ + "is-downgrade" + ], + "InstallDuration" : 8 + } + ] + }, + { + "Name" : "Display controller", + "DeviceId" : "ecf0d22adf39a244a723466378a8884aa22b7e78", + "Guid" : [ + "e358a53d-98bc-5565-b55e-7df8e0d06c5e", + "7365091f-756a-5c83-878c-edd1120ca718", + "06208e9f-1dd0-5857-b700-3d77525793aa", + "af9ff5a0-c613-5da3-bab8-5d411adebbca" + ], + "Plugin" : "optionrom", + "Flags" : [ + "internal", + "registered", + "can-verify", + "can-verify-image" + ], + "VendorId" : "PCI:0x1234", + "Version" : "02", + "VersionFormat" : "plain", + "Icons" : [ + "audio-card" + ], + "Created" : 1614209932 + }, + { + "Name" : "Intel(R) Core™ i7-7700HQ CPU @ 2.80GHz", + "DeviceId" : "4bde70ba4e39b28f9eab1628f9dd6e6244c03027", + "Guid" : [ + "b9a2dd81-159e-5537-a7db-e7101d164d3f", + "30249f37-d140-5d3e-9319-186b1bd5cac3", + "809a0b93-8a12-5338-a571-ad5583acf896", + "d0f754d5-1395-5573-bc83-85ba955da70a" + ], + "Plugin" : "cpu", + "Flags" : [ + "internal", + "registered" + ], + "Vendor" : "Intel", + "Version" : "0x000000de", + "VersionFormat" : "hex", + "VersionRaw" : 222, + "Icons" : [ + "computer" + ], + "Created" : 1614209932 + } + ] +} +""" + +GET_DEVICES_NO_UPDATES = """{ + "Devices" : [ + { + "Name" : "ColorHug2", + "DeviceId" : "203f56e4e186d078ce76725e708400aafc253aac", + "Guid" : [ + "2082b5e0-7a64-478a-b1b2-e3404fab6dad", + "aa4b4156-9732-55db-9500-bf6388508ee3", + "101ee86a-7bea-59fb-9f89-6b6297ceed3b", + "2fa8891f-3ece-53a4-adc4-0dd875685f30" + ], + "Summary" : "An open source display colorimeter", + "Plugin" : "colorhug", + "Protocol" : "com.hughski.colorhug", + "Flags" : [ + "updatable", + "supported", + "registered", + "self-recovery", + "add-counterpart-guids" + ], + "Vendor" : "Hughski Ltd.", + "VendorId" : "USB:0x273F", + "Version" : "2.0.7", + "VersionFormat" : "triplet", + "Icons" : [ + "colorimeter-colorhug" + ], + "InstallDuration" : 8, + "Created" : 1592916092, + "Releases" : [ + { + "AppstreamId" : "com.hughski.ColorHug2.firmware", + "RemoteId" : "lvfs", + "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter", + "Description" : "

    This release fixes prevents the firmware returning an error when the remote SHA1 hash was never sent.

    ", + "Version" : "2.0.7", + "Filename" : "658851e6f27c4d87de19cd66b97b610d100efe09", + "Protocol" : "com.hughski.colorhug", + "Checksum" : [ + "490be5c0b13ca4a3f169bf8bc682ba127b8f7b96" + ], + "License" : "GPL-2.0+", + "Size" : 16384, + "Created" : 1482901200, + "Uri" : "https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab", + "Homepage" : "http://www.hughski.com/", + "SourceUrl" : "https://github.com/hughski/colorhug2-firmware", + "Vendor" : "Hughski Limited", + "InstallDuration" : 8 + }, + { + "AppstreamId" : "com.hughski.ColorHug2.firmware", + "RemoteId" : "lvfs", + "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter", + "Description" : "

    This stable release fixes the following problems:

    • Fix the swapped LEDs on the second half of batch 16
    • Fix the firmware upgrade process using new versions of fwupd
    ", + "Version" : "2.0.6", + "Filename" : "f038b5ca40e6d7c1c0299a9e1dcc129d5f6371b6", + "Protocol" : "com.hughski.colorhug", + "Checksum" : [ + "03c9c14db1894a00035ececcfae192865a710e52" + ], + "License" : "GPL-2.0+", + "Size" : 16384, + "Created" : 1450792062, + "Uri" : "https://fwupd.org/downloads/170f2c19f17b7819644d3fcc7617621cc3350a04-hughski-colorhug2-2.0.6.cab", + "Homepage" : "http://www.hughski.com/", + "SourceUrl" : "https://github.com/hughski/colorhug2-firmware", + "Vendor" : "Hughski Limited", + "Flags" : [ + "is-downgrade" + ], + "InstallDuration" : 8 + }, + { + "AppstreamId" : "com.hughski.ColorHug2.firmware", + "RemoteId" : "lvfs", + "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter", + "Description" : "

    This stable release fixes the following problems:

    • Fix the swapped LEDs on batch 16
    • Make the self test more sensitive to detect floating pins
    ", + "Version" : "2.0.5", + "Filename" : "ae76c6b704b60f9d1d88dc2c8ec8a62d7b2331dc", + "Protocol" : "com.hughski.colorhug", + "Checksum" : [ + "4ee9dfa38df3b810f739d8a19d13da1b3175fb87" + ], + "License" : "GPL-2.0+", + "Size" : 16384, + "Created" : 1444059405, + "Uri" : "https://fwupd.org/downloads/f7dd4ab29fa610438571b8b62b26b0b0e57bb35b-hughski-colorhug2-2.0.5.cab", + "Homepage" : "http://www.hughski.com/", + "SourceUrl" : "https://github.com/hughski/colorhug2-firmware", + "Vendor" : "Hughski Limited", + "Flags" : [ + "is-downgrade" + ], + "InstallDuration" : 8 + }, + { + "AppstreamId" : "com.hughski.ColorHug2.firmware", + "RemoteId" : "lvfs", + "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter", + "Description" : "

    This unstable release adds the following features:

    • Add TakeReadingArray to enable panel latency measurements
    • Speed up the auto-scaled measurements considerably, using 256ms as the smallest sample duration
    ", + "Version" : "2.0.2", + "Filename" : "d4b3144daeb2418634f9d464d88d55590bcd9ac7", + "Protocol" : "com.hughski.colorhug", + "Checksum" : [ + "448527af3ce019d03dbb77aaebaa7eb893f1ea20" + ], + "License" : "GPL-2.0+", + "Size" : 15680, + "Created" : 1416675439, + "Uri" : "https://fwupd.org/downloads/30a121f26c039745aeb5585252d4a9b5386d71cb-hughski-colorhug2-2.0.2.cab", + "Homepage" : "http://www.hughski.com/", + "SourceUrl" : "https://github.com/hughski/colorhug2-firmware", + "Vendor" : "Hughski Limited", + "Flags" : [ + "is-downgrade" + ], + "InstallDuration" : 8 + } + ] + }, + { + "Name" : "GP106 [GeForce GTX 1060 6GB]", + "DeviceId" : "71b677ca0f1bc2c5b804fa1d59e52064ce589293", + "Guid" : [ + "b080a9ba-fff8-5de0-b641-26f782949f94", + "f95bfce3-18e4-58b0-bd81-136457521383" + ], + "Plugin" : "optionrom", + "Flags" : [ + "internal", + "registered", + "can-verify", + "can-verify-image" + ], + "Vendor" : "NVIDIA Corporation", + "VendorId" : "PCI:0x10DE", + "Version" : "a1", + "VersionFormat" : "plain", + "Icons" : [ + "audio-card" + ], + "Created" : 1592899254 + }, + { + "Name" : "Intel(R) Core™ i5-8400 CPU @ 2.80GHz", + "DeviceId" : "4bde70ba4e39b28f9eab1628f9dd6e6244c03027", + "Guid" : [ + "b9a2dd81-159e-5537-a7db-e7101d164d3f" + ], + "Plugin" : "cpu", + "Flags" : [ + "internal", + "registered" + ], + "Vendor" : "GenuineIntel", + "Version" : "0xd6", + "VersionFormat" : "hex", + "Icons" : [ + "computer" + ], + "Created" : 1592899249 + }, + { + "Name" : "SSDPR-CX400-256", + "DeviceId" : "948241a24320627284597ec95079cc1341c90518", + "Guid" : [ + "09fa3842-45bc-5226-a8ec-1668fc61f88f", + "57d6b2ff-710d-5cd2-98be-4f6b8b7c5287", + "36bebd37-b680-5d56-83a1-6693033d4098" + ], + "Summary" : "ATA Drive", + "Plugin" : "ata", + "Protocol" : "org.t13.ata", + "Flags" : [ + "internal", + "updatable", + "require-ac", + "registered", + "needs-reboot", + "usable-during-update" + ], + "Vendor" : "Phison", + "VendorId" : "ATA:0x1987", + "Version" : "SBFM61.3", + "VersionFormat" : "plain", + "Icons" : [ + "drive-harddisk" + ], + "Created" : 1592899254 + } + ] +} +""" + + +GET_DEVICES_NO_VERSION = """{ + "Devices" : [ + { + "Name" : "ColorHug2", + "DeviceId" : "203f56e4e186d078ce76725e708400aafc253aac", + "Guid" : [ + "2082b5e0-7a64-478a-b1b2-e3404fab6dad", + "aa4b4156-9732-55db-9500-bf6388508ee3", + "101ee86a-7bea-59fb-9f89-6b6297ceed3b", + "2fa8891f-3ece-53a4-adc4-0dd875685f30" + ], + "Summary" : "An open source display colorimeter", + "Plugin" : "colorhug", + "Protocol" : "com.hughski.colorhug", + "Flags" : [ + "updatable", + "supported", + "registered", + "self-recovery", + "add-counterpart-guids" + ], + "Vendor" : "Hughski Ltd.", + "VendorId" : "USB:0x273F", + "VersionFormat" : "triplet", + "Icons" : [ + "colorimeter-colorhug" + ], + "InstallDuration" : 8, + "Created" : 1592916092, + "Releases" : [ + { + "AppstreamId" : "com.hughski.ColorHug2.firmware", + "RemoteId" : "lvfs", + "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter", + "Description" : "

    This release fixes prevents the firmware returning an error when the remote SHA1 hash was never sent.

    ", + "Version" : "2.0.7", + "Filename" : "658851e6f27c4d87de19cd66b97b610d100efe09", + "Protocol" : "com.hughski.colorhug", + "Checksum" : [ + "490be5c0b13ca4a3f169bf8bc682ba127b8f7b96" + ], + "License" : "GPL-2.0+", + "Size" : 16384, + "Created" : 1482901200, + "Uri" : "https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab", + "Homepage" : "http://www.hughski.com/", + "SourceUrl" : "https://github.com/hughski/colorhug2-firmware", + "Vendor" : "Hughski Limited", + "InstallDuration" : 8 + }, + { + "AppstreamId" : "com.hughski.ColorHug2.firmware", + "RemoteId" : "lvfs", + "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter", + "Description" : "

    This stable release fixes the following problems:

    • Fix the swapped LEDs on the second half of batch 16
    • Fix the firmware upgrade process using new versions of fwupd
    ", + "Filename" : "f038b5ca40e6d7c1c0299a9e1dcc129d5f6371b6", + "Protocol" : "com.hughski.colorhug", + "Checksum" : [ + "03c9c14db1894a00035ececcfae192865a710e52" + ], + "License" : "GPL-2.0+", + "Size" : 16384, + "Created" : 1450792062, + "Uri" : "https://fwupd.org/downloads/170f2c19f17b7819644d3fcc7617621cc3350a04-hughski-colorhug2-2.0.6.cab", + "Homepage" : "http://www.hughski.com/", + "SourceUrl" : "https://github.com/hughski/colorhug2-firmware", + "Vendor" : "Hughski Limited", + "Flags" : [ + "is-downgrade" + ], + "InstallDuration" : 8 + }, + { + "AppstreamId" : "com.hughski.ColorHug2.firmware", + "RemoteId" : "lvfs", + "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter", + "Description" : "

    This stable release fixes the following problems:

    • Fix the swapped LEDs on batch 16
    • Make the self test more sensitive to detect floating pins
    ", + "Version" : "2.0.5", + "Filename" : "ae76c6b704b60f9d1d88dc2c8ec8a62d7b2331dc", + "Protocol" : "com.hughski.colorhug", + "Checksum" : [ + "4ee9dfa38df3b810f739d8a19d13da1b3175fb87" + ], + "License" : "GPL-2.0+", + "Size" : 16384, + "Created" : 1444059405, + "Uri" : "https://fwupd.org/downloads/f7dd4ab29fa610438571b8b62b26b0b0e57bb35b-hughski-colorhug2-2.0.5.cab", + "Homepage" : "http://www.hughski.com/", + "SourceUrl" : "https://github.com/hughski/colorhug2-firmware", + "Vendor" : "Hughski Limited", + "Flags" : [ + "is-downgrade" + ], + "InstallDuration" : 8 + }, + { + "AppstreamId" : "com.hughski.ColorHug2.firmware", + "RemoteId" : "lvfs", + "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter", + "Description" : "

    This unstable release adds the following features:

    • Add TakeReadingArray to enable panel latency measurements
    • Speed up the auto-scaled measurements considerably, using 256ms as the smallest sample duration
    ", + "Version" : "2.0.2", + "Filename" : "d4b3144daeb2418634f9d464d88d55590bcd9ac7", + "Protocol" : "com.hughski.colorhug", + "Checksum" : [ + "448527af3ce019d03dbb77aaebaa7eb893f1ea20" + ], + "License" : "GPL-2.0+", + "Size" : 15680, + "Created" : 1416675439, + "Uri" : "https://fwupd.org/downloads/30a121f26c039745aeb5585252d4a9b5386d71cb-hughski-colorhug2-2.0.2.cab", + "Homepage" : "http://www.hughski.com/", + "SourceUrl" : "https://github.com/hughski/colorhug2-firmware", + "Vendor" : "Hughski Limited", + "Flags" : [ + "is-downgrade" + ], + "InstallDuration" : 8 + } + ] + }, + { + "Name" : "ColorHug2", + "DeviceId" : "203f56e4e186d078ce76725e708400aafc253aac", + "Guid" : [ + "2082b5e0-7a64-478a-b1b2-e3404fab6dad", + "aa4b4156-9732-55db-9500-bf6388508ee3", + "101ee86a-7bea-59fb-9f89-6b6297ceed3b", + "2fa8891f-3ece-53a4-adc4-0dd875685f30" + ], + "Summary" : "An open source display colorimeter", + "Plugin" : "colorhug", + "Protocol" : "com.hughski.colorhug", + "Flags" : [ + "updatable", + "supported", + "registered", + "self-recovery", + "add-counterpart-guids" + ], + "Vendor" : "Hughski Ltd.", + "Version" : "2.0.6", + "VendorId" : "USB:0x273F", + "VersionFormat" : "triplet", + "Icons" : [ + "colorimeter-colorhug" + ], + "InstallDuration" : 8, + "Created" : 1592916092, + "Releases" : [ + { + "AppstreamId" : "com.hughski.ColorHug2.firmware", + "RemoteId" : "lvfs", + "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter", + "Description" : "

    This release fixes prevents the firmware returning an error when the remote SHA1 hash was never sent.

    ", + "Version" : "2.0.7", + "Filename" : "658851e6f27c4d87de19cd66b97b610d100efe09", + "Protocol" : "com.hughski.colorhug", + "Checksum" : [ + "490be5c0b13ca4a3f169bf8bc682ba127b8f7b96" + ], + "License" : "GPL-2.0+", + "Size" : 16384, + "Created" : 1482901200, + "Uri" : "https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab", + "Homepage" : "http://www.hughski.com/", + "SourceUrl" : "https://github.com/hughski/colorhug2-firmware", + "Vendor" : "Hughski Limited", + "InstallDuration" : 8 + }, + { + "AppstreamId" : "com.hughski.ColorHug2.firmware", + "RemoteId" : "lvfs", + "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter", + "Description" : "

    This stable release fixes the following problems:

    • Fix the swapped LEDs on the second half of batch 16
    • Fix the firmware upgrade process using new versions of fwupd
    ", + "Version" : "2.0.6", + "Filename" : "f038b5ca40e6d7c1c0299a9e1dcc129d5f6371b6", + "Protocol" : "com.hughski.colorhug", + "Checksum" : [ + "03c9c14db1894a00035ececcfae192865a710e52" + ], + "License" : "GPL-2.0+", + "Size" : 16384, + "Created" : 1450792062, + "Uri" : "https://fwupd.org/downloads/170f2c19f17b7819644d3fcc7617621cc3350a04-hughski-colorhug2-2.0.6.cab", + "Homepage" : "http://www.hughski.com/", + "SourceUrl" : "https://github.com/hughski/colorhug2-firmware", + "Vendor" : "Hughski Limited", + "Flags" : [ + "is-downgrade" + ], + "InstallDuration" : 8 + }, + { + "AppstreamId" : "com.hughski.ColorHug2.firmware", + "RemoteId" : "lvfs", + "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter", + "Description" : "

    This stable release fixes the following problems:

    • Fix the swapped LEDs on batch 16
    • Make the self test more sensitive to detect floating pins
    ", + "Version" : "2.0.5", + "Filename" : "ae76c6b704b60f9d1d88dc2c8ec8a62d7b2331dc", + "Protocol" : "com.hughski.colorhug", + "Checksum" : [ + "4ee9dfa38df3b810f739d8a19d13da1b3175fb87" + ], + "License" : "GPL-2.0+", + "Size" : 16384, + "Created" : 1444059405, + "Uri" : "https://fwupd.org/downloads/f7dd4ab29fa610438571b8b62b26b0b0e57bb35b-hughski-colorhug2-2.0.5.cab", + "Homepage" : "http://www.hughski.com/", + "SourceUrl" : "https://github.com/hughski/colorhug2-firmware", + "Vendor" : "Hughski Limited", + "Flags" : [ + "is-downgrade" + ], + "InstallDuration" : 8 + }, + { + "AppstreamId" : "com.hughski.ColorHug2.firmware", + "RemoteId" : "lvfs", + "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter", + "Description" : "

    This unstable release adds the following features:

    • Add TakeReadingArray to enable panel latency measurements
    • Speed up the auto-scaled measurements considerably, using 256ms as the smallest sample duration
    ", + "Version" : "2.0.2", + "Filename" : "d4b3144daeb2418634f9d464d88d55590bcd9ac7", + "Protocol" : "com.hughski.colorhug", + "Checksum" : [ + "448527af3ce019d03dbb77aaebaa7eb893f1ea20" + ], + "License" : "GPL-2.0+", + "Size" : 15680, + "Created" : 1416675439, + "Uri" : "https://fwupd.org/downloads/30a121f26c039745aeb5585252d4a9b5386d71cb-hughski-colorhug2-2.0.2.cab", + "Homepage" : "http://www.hughski.com/", + "SourceUrl" : "https://github.com/hughski/colorhug2-firmware", + "Vendor" : "Hughski Limited", + "Flags" : [ + "is-downgrade" + ], + "InstallDuration" : 8 + } + ] + }, + { + "Name" : "GP106 [GeForce GTX 1060 6GB]", + "DeviceId" : "71b677ca0f1bc2c5b804fa1d59e52064ce589293", + "Guid" : [ + "b080a9ba-fff8-5de0-b641-26f782949f94", + "f95bfce3-18e4-58b0-bd81-136457521383" + ], + "Plugin" : "optionrom", + "Flags" : [ + "internal", + "registered", + "can-verify", + "can-verify-image" + ], + "Vendor" : "NVIDIA Corporation", + "VendorId" : "PCI:0x10DE", + "VersionFormat" : "plain", + "Icons" : [ + "audio-card" + ], + "Created" : 1592899254 + }, + { + "Name" : "Intel(R) Core™ i5-8400 CPU @ 2.80GHz", + "DeviceId" : "4bde70ba4e39b28f9eab1628f9dd6e6244c03027", + "Guid" : [ + "b9a2dd81-159e-5537-a7db-e7101d164d3f" + ], + "Plugin" : "cpu", + "Flags" : [ + "internal", + "registered" + ], + "Vendor" : "GenuineIntel", + "Version" : "0xd6", + "VersionFormat" : "hex", + "Icons" : [ + "computer" + ], + "Created" : 1592899249 + }, + { + "Name" : "SSDPR-CX400-256", + "DeviceId" : "948241a24320627284597ec95079cc1341c90518", + "Guid" : [ + "09fa3842-45bc-5226-a8ec-1668fc61f88f", + "57d6b2ff-710d-5cd2-98be-4f6b8b7c5287", + "36bebd37-b680-5d56-83a1-6693033d4098" + ], + "Summary" : "ATA Drive", + "Plugin" : "ata", + "Protocol" : "org.t13.ata", + "Flags" : [ + "internal", + "updatable", + "require-ac", + "registered", + "needs-reboot", + "usable-during-update" + ], + "Vendor" : "Phison", + "VendorId" : "ATA:0x1987", + "Version" : "SBFM61.3", + "VersionFormat" : "plain", + "Icons" : [ + "drive-harddisk" + ], + "Created" : 1592899254 + } + ] +} +""" + +HEADS_XML = """ + + + com.3mdeb.heads.x230.firmware + Heads x230 System Update + x230 heads system firmware + +

    x230 heads system firmware

    +
    + + 596c3466-0506-5ca5-a68f-dc34532a93d3 + + http://osresearch.net/ + CC0-1.0 + GPLv2 + coreboot + + X-System + + + + https://fwupd.org/downloads/e747a435bf24fd6081b77b6704b39cec5fa2dcf62e0ca6b86d8a6460121a1d07-heads_coreboot_x230-v0_2_3.cab + 1a54e69ca2b58d1218035115d481480eaf4c66e4 + ba519a7a5d8136c8ade0cf0c775c58f3165f42798ff631c3f57f075897ef1586 + 76373f1b5a157b6563d3605271472901b03f57f3 + 9a9c5dbd3faf90ff7a1f4c9be8d71c4db93dd69fa690f8722fec19c5a51aed9e + +

    Fixes flash-gui issue.

    +
    + 12582912 + 12591670 +
    + + https://fwupd.org/downloads/1a0f0ad487a40bb27a49db55e256a207a33dac92c5c53761501c9fb89e4fd115-heads_coreboot_x230-v0_2_2.cab + 58e85d012ad1d5c6f98e8fe65202b4d6c8a6ec03 + 94430160d35cf74adf29c7fc1490b44497e1a3f0fff72733efe2982c61c9a772 + 8e97ce38396e281fcf9a5a248819925a2fa04265 + a6774661407622f345bf0ac2f113540507f0288bb97bf5dba586059c0653f659 + +

    Lenovo x230 heads system firmware

    +
    + 12582912 + 12591680 +
    +
    +
    +
    +""" diff -Nru fwupd-1.4.5/contrib/qubes/test/logs/firmware.metainfo.xml fwupd-1.5.8/contrib/qubes/test/logs/firmware.metainfo.xml --- fwupd-1.4.5/contrib/qubes/test/logs/firmware.metainfo.xml 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/qubes/test/logs/firmware.metainfo.xml 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,44 @@ + + + com.dell.uefi6180aaaa.firmware + Latitude 7390 2-in-1 + Firmware for the Dell Latitude 7390 2-in-1 + +

    Updating the system firmware improves performance.

    +
    + + 6180aaaa-5529-4bbf-b4fd-65b4f788de5b + + http://support.dell.com/ + CC0-1.0 + proprietary + Dell Inc. + + X-System + + + quad + dell-bios + org.uefi.capsule + + + + b03252481573f600c7f530d7a4c24bd62c810412 + bd866bcd2b5964da4b20d3f57128746efb7afefe648cf7284f2fae399225f1ac + +

    This stable release fixes the following issues:

    +
      +
    • Firmware updates to address the Intel Security Advisories.
    • +
    • Enhanced the system firmware auto recovery function when system firmware does not work.
    • +
    • Updated the BIOS warning message that is displayed when an AC adapter with low wattage is connected to the system.
    • +
    • Updated the Intel CPU Microcode.
    • +
    +
    + 14699068 + + CVE-2019-14607 + CVE-2019-11157 + +
    +
    +
    diff -Nru fwupd-1.4.5/contrib/qubes/test/logs/get_devices.log fwupd-1.5.8/contrib/qubes/test/logs/get_devices.log --- fwupd-1.4.5/contrib/qubes/test/logs/get_devices.log 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/qubes/test/logs/get_devices.log 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,22 @@ +====================================================================== +Dom0 Devices: +====================================================================== + ColorHug2 +====================================================================== + DeviceId: b0a78eb71f4eeea7df8fb114522556ba8ce22074 + Guid: ·2082b5e0-7a64-478a-b1b2-e3404fab6dad + ·aa4b4156-9732-55db-9500-bf6388508ee3 + ·101ee86a-7bea-59fb-9f89-6b6297ceed3b + ·2fa8891f-3ece-53a4-adc4-0dd875685f30 + Summary: An open source display colorimeter + Plugin: colorhug + Protocol: com.hughski.colorhug + Flags: ·updatable + ·supported + ·registered + ·self-recovery + ·add-counterpart-guids + Vendor: Hughski Ltd. + VendorId: USB:0x273F + Version: 2.0.6 + Created: 1614224175 diff -Nru fwupd-1.4.5/contrib/qubes/test/logs/get_updates.log fwupd-1.5.8/contrib/qubes/test/logs/get_updates.log --- fwupd-1.4.5/contrib/qubes/test/logs/get_updates.log 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/qubes/test/logs/get_updates.log 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,15 @@ +====================================================== +sys-usb updates: +====================================================== +Available updates: +====================================================== +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +1. Device: ColorHug2 + Current firmware version: 2.0.6 +====================================================== + Firmware update version: 2.0.7 + URL: https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab + SHA256 checksum: 32c4a2c9be787cdf1d757c489d6455bd7bb14053425180b6d331c37e1ccc1cda + Description: This release fixes prevents the firmware returning an error when the remote SHA1 hash was never sent. + +====================================================== diff -Nru fwupd-1.4.5/contrib/qubes/test/logs/help.log fwupd-1.5.8/contrib/qubes/test/logs/help.log --- fwupd-1.4.5/contrib/qubes/test/logs/help.log 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/qubes/test/logs/help.log 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,25 @@ +====================================================================== +Usage: +====================================================================== + Command: qubes-fwupdmgr [OPTION…][FLAG..] + Example: qubes-fwupdmgr refresh --whonix --url= + +Options: +====================================================================== + get-devices: Get all devices that support firmware updates + get-updates: Get the list of updates for connected hardware + refresh: Refresh metadata from remote server + update: Update chosen device to latest firmware version + update-heads: Updates heads firmware to the latest version + downgrade: Downgrade chosen device to chosen firmware version + clean: Delete all cached update files + +Flags: +====================================================================== + --whonix: Download firmware updates via Tor + --device: Specify device for heads update (default - x230) + --url: Address of the custom metadata remote server + +Help: +====================================================================== + -h --help: Show help options diff -Nru fwupd-1.4.5/contrib/qubes/test/logs/metainfo_name/firmware.metainfo.xml fwupd-1.5.8/contrib/qubes/test/logs/metainfo_name/firmware.metainfo.xml --- fwupd-1.4.5/contrib/qubes/test/logs/metainfo_name/firmware.metainfo.xml 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/qubes/test/logs/metainfo_name/firmware.metainfo.xml 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,44 @@ + + + com.dell.uefi6180aaaa.firmware + Latitude 7390 2-in-1 + Firmware for the Dell Latitude 7390 2-in-1 + +

    Updating the system firmware improves performance.

    +
    + + 6180aaaa-5529-4bbf-b4fd-65b4f788de5b + + http://support.dell.com/ + CC0-1.0 + proprietary + Wrong name + + X-System + + + quad + dell-bios + org.uefi.capsule + + + + b03252481573f600c7f530d7a4c24bd62c810412 + bd866bcd2b5964da4b20d3f57128746efb7afefe648cf7284f2fae399225f1ac + +

    This stable release fixes the following issues:

    +
      +
    • Firmware updates to address the Intel Security Advisories.
    • +
    • Enhanced the system firmware auto recovery function when system firmware does not work.
    • +
    • Updated the BIOS warning message that is displayed when an AC adapter with low wattage is connected to the system.
    • +
    • Updated the Intel CPU Microcode.
    • +
    +
    + 14699068 + + CVE-2019-14607 + CVE-2019-11157 + +
    +
    +
    diff -Nru fwupd-1.4.5/contrib/qubes/test/logs/metainfo_version/firmware.metainfo.xml fwupd-1.5.8/contrib/qubes/test/logs/metainfo_version/firmware.metainfo.xml --- fwupd-1.4.5/contrib/qubes/test/logs/metainfo_version/firmware.metainfo.xml 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/qubes/test/logs/metainfo_version/firmware.metainfo.xml 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,44 @@ + + + com.dell.uefi6180aaaa.firmware + Latitude 7390 2-in-1 + Firmware for the Dell Latitude 7390 2-in-1 + +

    Updating the system firmware improves performance.

    +
    + + 6180aaaa-5529-4bbf-b4fd-65b4f788de5b + + http://support.dell.com/ + CC0-1.0 + proprietary + Dell Inc. + + X-System + + + quad + dell-bios + org.uefi.capsule + + + + b03252481573f600c7f530d7a4c24bd62c810412 + bd866bcd2b5964da4b20d3f57128746efb7afefe648cf7284f2fae399225f1ac + +

    This stable release fixes the following issues:

    +
      +
    • Firmware updates to address the Intel Security Advisories.
    • +
    • Enhanced the system firmware auto recovery function when system firmware does not work.
    • +
    • Updated the BIOS warning message that is displayed when an AC adapter with low wattage is connected to the system.
    • +
    • Updated the Intel CPU Microcode.
    • +
    +
    + 14699068 + + CVE-2019-14607 + CVE-2019-11157 + +
    +
    +
    diff -Nru fwupd-1.4.5/contrib/qubes/test/test_qubes_fwupd_heads.py fwupd-1.5.8/contrib/qubes/test/test_qubes_fwupd_heads.py --- fwupd-1.4.5/contrib/qubes/test/test_qubes_fwupd_heads.py 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/qubes/test/test_qubes_fwupd_heads.py 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,135 @@ +#!/usr/bin/python3 +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2021 Norbert Kamiński +# +# SPDX-License-Identifier: LGPL-2.1+ +# + +import io +import os +import platform +import shutil +import imp +import src.qubes_fwupd_heads as qf_heads +import sys +import unittest + +from test.fwupd_logs import HEADS_XML + +CUSTOM_METADATA = "https://fwupd.org/downloads/firmware-3c81bfdc9db5c8a42c09d38091944bc1a05b27b0.xml.gz" +QUBES_FWUPDMGR_REPO = "./src/qubes_fwupdmgr.py" +QUBES_FWUPDMGR_BINDIR = "/usr/sbin/qubes-fwupdmgr" + + +class TestQubesFwupdHeads(unittest.TestCase): + def setUp(self): + if os.path.exists(QUBES_FWUPDMGR_REPO): + self.qfwupd = imp.load_source( + "qubes_fwupdmgr", + QUBES_FWUPDMGR_REPO + ) + elif os.path.exists(QUBES_FWUPDMGR_BINDIR): + self.qfwupd = imp.load_source( + "qubes_fwupdmgr", + QUBES_FWUPDMGR_BINDIR + ) + self.q = qf_heads.FwupdHeads() + self.maxDiff = 2000 + self.captured_output = io.StringIO() + sys.stdout = self.captured_output + + @unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") + def test_get_hwids(self): + self.q._check_fwupdtool_version() + self.q._get_hwids() + self.assertNotEqual(self.q.dom0_hwids_info, "") + + def test_gather_firmware_version_empty(self): + self.q.dom0_hwids_info = "" + return_code = self.q._gather_firmware_version() + self.assertEqual(return_code, 2) + + def test_gather_firmware_version(self): + self.q.dom0_hwids_info = "BiosVersion: CBET4000 0.2.2 heads" + self.q._gather_firmware_version() + self.assertEqual(self.q.heads_version, "0.2.2") + + @unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") + def test_parse_metadata(self): + qmgr = self.qfwupd.QubesFwupdmgr() + qmgr.metadata_file = CUSTOM_METADATA.replace( + "https://fwupd.org/downloads", + self.qfwupd.FWUPD_DOM0_METADATA_DIR + ) + qmgr._download_metadata(metadata_url=CUSTOM_METADATA) + self.q._parse_metadata(qmgr.metadata_file) + self.assertTrue(self.q.metadata_info) + + def test_check_heads_updates_default_heads(self): + self.q.metadata_info = HEADS_XML + self.q.heads_version = "heads" + return_code = self.q._parse_heads_updates("x230") + self.assertEqual(return_code, 0) + self.assertEqual( + self.q.heads_update_url, + "https://fwupd.org/downloads/e747a435bf24fd6081b77b6704b39cec5fa2dcf62e0ca6b86d8a6460121a1d07-heads_coreboot_x230-v0_2_3.cab" + ) + self.assertEqual( + self.q.heads_update_sha, + "1a54e69ca2b58d1218035115d481480eaf4c66e4" + ) + self.assertEqual( + self.q.heads_update_version, + "0.2.3" + ) + + def test_check_heads_updates_no_updates(self): + self.q.metadata_info = HEADS_XML + self.q.heads_version = "0.2.3" + return_code = self.q._parse_heads_updates("x230") + self.assertEqual(return_code, 2) + + def test_check_heads_updates_lower_version(self): + self.q.metadata_info = HEADS_XML + self.q.heads_version = "0.2.2" + return_code = self.q._parse_heads_updates("x230") + self.assertEqual(return_code, 0) + self.assertEqual( + self.q.heads_update_url, + "https://fwupd.org/downloads/e747a435bf24fd6081b77b6704b39cec5fa2dcf62e0ca6b86d8a6460121a1d07-heads_coreboot_x230-v0_2_3.cab" + ) + self.assertEqual( + self.q.heads_update_sha, + "1a54e69ca2b58d1218035115d481480eaf4c66e4" + ) + self.assertEqual( + self.q.heads_update_version, + "0.2.3" + ) + + @unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") + def test_copy_heads_firmware(self): + qmgr = self.qfwupd.QubesFwupdmgr() + self.q.heads_update_url = "https://fwupd.org/downloads/e747a435bf24fd6081b77b6704b39cec5fa2dcf62e0ca6b86d8a6460121a1d07-heads_coreboot_x230-v0_2_3.cab" + self.q.heads_update_sha = "1a54e69ca2b58d1218035115d481480eaf4c66e4" + self.q.heads_update_version = "0.2.3" + qmgr._download_firmware_updates( + self.q.heads_update_url, + self.q.heads_update_sha + ) + heads_boot_path = os.path.join( + qf_heads.HEADS_UPDATES_DIR, + self.q.heads_update_version + ) + if os.path.exists(heads_boot_path): + shutil.rmtree(heads_boot_path) + ret_code = self.q._copy_heads_firmware(qmgr.arch_path) + self.assertNotEqual(ret_code, self.qfwupd.EXIT_CODES["NO_UPDATES"]) + firmware_path = os.path.join(heads_boot_path, "firmware.rom") + self.assertTrue(os.path.exists(firmware_path)) + + +if __name__ == '__main__': + unittest.main() diff -Nru fwupd-1.4.5/contrib/qubes/test/test_qubes_fwupdmgr.py fwupd-1.5.8/contrib/qubes/test/test_qubes_fwupdmgr.py --- fwupd-1.4.5/contrib/qubes/test/test_qubes_fwupdmgr.py 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/qubes/test/test_qubes_fwupdmgr.py 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,1010 @@ +#!/usr/bin/python3 +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2021 Norbert Kamiński +# +# SPDX-License-Identifier: LGPL-2.1+ +# + +import json +import unittest +import os +import subprocess +import sys +import imp +import io +import platform +from distutils.version import LooseVersion as l_ver +from pathlib import Path +from test.fwupd_logs import UPDATE_INFO, GET_DEVICES, DMI_DECODE +from test.fwupd_logs import GET_DEVICES_NO_UPDATES, GET_DEVICES_NO_VERSION +from unittest.mock import patch + + +QUBES_FWUPDMGR_REPO = "./src/qubes_fwupdmgr.py" +QUBES_FWUPDMGR_BINDIR = "/usr/sbin/qubes-fwupdmgr" + +if os.path.exists(QUBES_FWUPDMGR_REPO): + qfwupd = imp.load_source( + "qubes_fwupdmgr", + QUBES_FWUPDMGR_REPO + ) +elif os.path.exists(QUBES_FWUPDMGR_BINDIR): + qfwupd = imp.load_source( + "qubes_fwupdmgr", + QUBES_FWUPDMGR_BINDIR + ) + +FWUPD_DOM0_DIR = "/root/.cache/fwupd" +FWUPD_DOM0_UPDATES_DIR = os.path.join(FWUPD_DOM0_DIR, "updates") +FWUPD_DOM0_UNTRUSTED_DIR = os.path.join(FWUPD_DOM0_UPDATES_DIR, "untrusted") +FWUPD_VM_LOG = os.path.join(FWUPD_DOM0_DIR, "usbvm-devices.log") +FWUPD_DOM0_METADATA_DIR = os.path.join(FWUPD_DOM0_DIR, "metadata") +FWUPD_DOM0_METADATA_FILE = os.path.join( + FWUPD_DOM0_METADATA_DIR, + "firmware.xml.gz" +) +FWUPD_DOM0_METADATA_FILE_JCAT = os.path.join( + FWUPD_DOM0_METADATA_DIR, + "firmware.xml.gz" +) +FWUPD_VM_DIR = "/home/user/.cache/fwupd" +FWUPD_VM_UPDATES_DIR = os.path.join(FWUPD_VM_DIR, "updates") +FWUPD_VM_METADATA_DIR = os.path.join(FWUPD_VM_DIR, "metadata") +FWUPD_VM_METADATA_FILE = os.path.join( + FWUPD_VM_METADATA_DIR, + "firmware.xml.gz" +) +FWUPD_VM_METADATA_FILE_JCAT = os.path.join( + FWUPD_VM_METADATA_DIR, + "firmware.xml.gz.jcat" +) +REQUIRED_DEV = "Requires device not connected" +REQUIRED_USBVM = "Requires sys-usb" +XL_LIST_LOG = "Name ID Mem VCPUs State Time(s)" +USBVM_N = "sys-usb" +FWUPDMGR = "/bin/fwupdmgr" +BIOS_UPDATE_FLAG = os.path.join(FWUPD_DOM0_DIR, "bios_update") +LVFS_TESTING_DOM0_FLAG = os.path.join(FWUPD_DOM0_DIR, "lvfs_testing") +LVFS_TESTING_USBVM_FLAG = os.path.join(FWUPD_VM_DIR, "lvfs_testing") +CUSTOM_METADATA = "https://fwupd.org/downloads/firmware-3c81bfdc9db5c8a42c09d38091944bc1a05b27b0.xml.gz" + + +def check_usbvm(): + """Checks if sys-usb is running""" + if 'qubes' not in platform.release(): + return False + q = qfwupd.QubesFwupdmgr() + q.check_usbvm() + return "sys-usb" in q.output + + +def device_connected_dom0(): + """Checks if the testing device is connected in dom0""" + if 'qubes' not in platform.release(): + return False + q = qfwupd.QubesFwupdmgr() + q._get_dom0_devices() + return "ColorHug2" in q.dom0_devices_info + + +def device_connected_usbvm(): + """Checks if the testing device is connected in usbvm""" + if not check_usbvm(): + return False + q = qfwupd.QubesFwupdmgr() + q._validate_usbvm_dirs() + if not os.path.exists(FWUPD_DOM0_DIR): + q.refresh_metadata() + q._get_usbvm_devices() + with open(FWUPD_VM_LOG) as usbvm_device_info: + return "ColorHug2" in usbvm_device_info.read() + + +def check_whonix_updatevm(): + """Checks if the sys-whonix is running""" + if 'qubes' not in platform.release(): + return False + q = qfwupd.QubesFwupdmgr() + q.check_usbvm() + return "sys-whonix" in q.output + + +class TestQubesFwupdmgr(unittest.TestCase): + def setUp(self): + self.q = qfwupd.QubesFwupdmgr() + self.maxDiff = 2000 + self.captured_output = io.StringIO() + sys.stdout = self.captured_output + + @unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") + def test_download_metadata(self): + self.q.metadata_file = FWUPD_DOM0_METADATA_FILE + self.q._download_metadata() + self.assertTrue( + os.path.exists(FWUPD_DOM0_METADATA_FILE), + msg="Metadata update file does not exist", + ) + self.assertTrue( + os.path.exists(FWUPD_DOM0_METADATA_FILE_JCAT), + msg="Metadata signature does not exist", + ) + + @unittest.skipUnless(check_whonix_updatevm(), "Requires sys-whonix") + def test_download_metadata_whonix(self): + self.q.metadata_file = FWUPD_DOM0_METADATA_FILE + self.q._download_metadata(whonix=True) + self.assertTrue( + os.path.exists(FWUPD_DOM0_METADATA_FILE), + msg="Metadata update file does not exist", + ) + self.assertTrue( + os.path.exists(FWUPD_DOM0_METADATA_FILE_JCAT), + msg="Metadata signature does not exist", + ) + + @unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") + def test_download_custom_metadata(self): + self.q.metadata_file = CUSTOM_METADATA.replace( + "https://fwupd.org/downloads", + FWUPD_DOM0_METADATA_DIR + ) + self.q.metadata_file_jcat = self.q.metadata_file + '.jcat' + self.q._download_metadata(metadata_url=CUSTOM_METADATA) + self.assertTrue( + os.path.exists(self.q.metadata_file), + msg="Metadata update file does not exist", + ) + self.assertTrue( + os.path.exists(self.q.metadata_file_jcat), + msg="Metadata signature does not exist", + ) + + @unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") + def test_refresh_metadata_dom0(self): + self.q.refresh_metadata() + self.assertEqual( + self.q.output, + 'Successfully refreshed metadata manually\n', + msg="Metadata refresh failed." + ) + + @unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") + def test_refresh_metadata_dom0_custom(self): + self.q.refresh_metadata(metadata_url=CUSTOM_METADATA) + self.assertEqual( + self.q.output, + 'Successfully refreshed metadata manually\n', + msg="Metadata refresh failed." + ) + + @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM) + def test_refresh_metadata_usbvm(self): + self.q.refresh_metadata(usbvm=True) + self.assertEqual( + self.q.output, + 'Successfully refreshed metadata manually\n', + msg="Metadata refresh failed." + ) + + @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM) + def test_refresh_metadata_usbvm_custom(self): + self.q.refresh_metadata(usbvm=True, metadata_url=CUSTOM_METADATA) + self.assertEqual( + self.q.output, + 'Successfully refreshed metadata manually\n', + msg="Metadata refresh failed." + ) + + @unittest.skipUnless(check_whonix_updatevm(), "Requires sys-whonix") + def test_refresh_metadata_whonix(self): + self.q.refresh_metadata(whonix=True) + self.assertEqual( + self.q.output, + 'Successfully refreshed metadata manually\n', + msg="Metadata refresh failed." + ) + + @unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") + def test_get_dom0_updates(self): + self.q._get_dom0_updates() + self.assertIn( + "Devices", + self.q.dom0_updates_info, + msg="Getting available updates failed" + ) + + def test_parse_updates_info(self): + self.q._parse_dom0_updates_info(UPDATE_INFO) + self.assertEqual( + self.q.dom0_updates_list[0]["Name"], + "ColorHug2", + msg="Wrong device name" + ) + self.assertEqual( + self.q.dom0_updates_list[0]["Version"], + "2.0.6", + msg="Wrong update version" + ) + self.assertEqual( + self.q.dom0_updates_list[0]["Releases"][0]["Url"], + "https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab", + msg="Wrong update URL" + ) + self.assertEqual( + self.q.dom0_updates_list[0]["Releases"][0]["Checksum"], + "32c4a2c9be787cdf1d757c489d6455bd7bb14053425180b6d331c37e1ccc1cda", + msg="Wrong checksum" + ) + + @unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") + def test_download_firmware_updates(self): + self.q._download_firmware_updates( + "https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab", + "32c4a2c9be787cdf1d757c489d6455bd7bb14053425180b6d331c37e1ccc1cda" + ) + update_path = os.path.join( + FWUPD_DOM0_UPDATES_DIR, + "0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7" + ) + self.assertTrue(os.path.exists(update_path)) + + @unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") + def test_download_firmware_special_char(self): + self.q._download_firmware_updates( + "https://fwupd.org/downloads/bc334d8b098f2e91603c5f7dfdc837fb01797bbe-Dell%20XPS%2015%209560&Precision%205520%20System%20BIOS_Ver.1.18.0.cab", + "86d9e5e35b0b264be1bb1e49ec16ccd1330390423bfe962267a58c27be7712b8" + ) + update_path = os.path.join( + FWUPD_DOM0_UPDATES_DIR, + "trusted" + ) + self.assertTrue(os.path.exists(update_path)) + + @unittest.skipUnless(check_whonix_updatevm(), "Requires sys-whonix") + def test_download_firmware_updates_whonix(self): + self.q._download_firmware_updates( + "https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab", + "32c4a2c9be787cdf1d757c489d6455bd7bb14053425180b6d331c37e1ccc1cda", + whonix=True, + ) + update_path = os.path.join( + FWUPD_DOM0_UPDATES_DIR, + "0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7" + ) + self.assertTrue(os.path.exists(update_path)) + + def test_user_input_empty_dict(self): + downgrade_dict = { + "usbvm": [], + "dom0": [] + } + self.assertEqual(self.q._user_input(downgrade_dict), 2) + + def test_user_input_n(self): + user_input = ['sth', 'n'] + with patch('builtins.input', side_effect=user_input): + self.q._parse_dom0_updates_info(UPDATE_INFO) + downgrade_dict = { + "usbvm": self.q.dom0_updates_list, + "dom0": self.q.dom0_updates_list + } + choice = self.q._user_input( + downgrade_dict, + usbvm=True + ) + self.assertEqual(choice, 2) + user_input = ['sth', 'N'] + with patch('builtins.input', side_effect=user_input): + self.q._parse_dom0_updates_info(UPDATE_INFO) + downgrade_dict = { + "usbvm": self.q.dom0_updates_list, + "dom0": self.q.dom0_updates_list + } + choice = self.q._user_input( + downgrade_dict, + usbvm=True + ) + self.assertEqual(choice, 2) + + def test_user_input_choice(self): + user_input = ['6', '1'] + with patch('builtins.input', side_effect=user_input): + self.q._parse_dom0_updates_info(UPDATE_INFO) + updates_dict = { + "usbvm": self.q.dom0_updates_list, + "dom0": self.q.dom0_updates_list + } + key, choice = self.q._user_input(updates_dict) + self.assertEqual(key, "dom0") + self.assertEqual(choice, 0) + + def test_user_input_choice_usbvm(self): + user_input = ['6', '2'] + with patch('builtins.input', side_effect=user_input): + self.q._parse_dom0_updates_info(UPDATE_INFO) + updates_dict = { + "usbvm": self.q.dom0_updates_list, + "dom0": self.q.dom0_updates_list + } + key, choice = self.q._user_input(updates_dict, usbvm=True) + self.assertEqual(key, "usbvm") + self.assertEqual(choice, 0) + + def test_parse_parameters(self): + self.q._parse_dom0_updates_info(UPDATE_INFO) + update_dict = {"dom0": self.q.dom0_updates_list} + self.q._parse_parameters(update_dict, "dom0", 0) + self.assertEqual( + self.q.url, + "https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab" + ) + self.assertEqual( + self.q.sha, + "32c4a2c9be787cdf1d757c489d6455bd7bb14053425180b6d331c37e1ccc1cda" + ) + self.assertEqual( + self.q.version, + "2.0.7" + ) + + @unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") + def test_clean_cache_dom0(self): + self.q.clean_cache() + self.assertFalse(os.path.exists(FWUPD_DOM0_METADATA_DIR)) + self.assertFalse(os.path.exists(FWUPD_DOM0_UNTRUSTED_DIR)) + + @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM) + def test_clean_cache_dom0_n_usbvm(self): + self.q._validate_usbvm_dirs() + self.q.clean_cache(usbvm=True) + self.assertFalse(os.path.exists(FWUPD_DOM0_METADATA_DIR)) + self.assertFalse(os.path.exists(FWUPD_DOM0_UNTRUSTED_DIR)) + cmd_validate_metadata = [ + "qvm-run", + "--pass-io", + "sys-usb", + f"! [ -d {FWUPD_VM_METADATA_DIR} ]" + ] + p = subprocess.Popen(cmd_validate_metadata) + p.wait() + self.assertEqual( + p.returncode, + 0, + msg="Creating metadata directory failed" + ) + cmd_validate_udpdate = [ + "qvm-run", + "--pass-io", + "sys-usb", + f"! [ -d {FWUPD_VM_UPDATES_DIR} ]" + ] + p = subprocess.Popen(cmd_validate_udpdate) + p.wait() + self.assertEqual( + p.returncode, + 0, + msg="Cleaning update directory failed" + ) + + def test_output_crawler(self): + crawler_output = io.StringIO() + sys.stdout = crawler_output + self.q._output_crawler(json.loads(UPDATE_INFO), 0) + with open("test/logs/get_devices.log", "r") as get_devices: + self.assertEqual( + get_devices.read(), + crawler_output.getvalue().strip() + "\n" + ) + sys.stdout = self.captured_output + + @unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") + def test_get_dom0_devices(self): + self.q._get_dom0_devices() + self.assertIsNotNone(self.q.dom0_devices_info) + + @unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") + def test_get_devices_qubes_dom0(self): + get_devices_output = io.StringIO() + sys.stdout = get_devices_output + self.q.get_devices_qubes() + self.assertNotEqual(get_devices_output.getvalue().strip(), "") + sys.stdout = self.captured_output + + @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM) + def test_get_devices_qubes_usbvm(self): + get_devices_output = io.StringIO() + sys.stdout = get_devices_output + self.q.get_devices_qubes(usbvm=True) + self.assertNotEqual(get_devices_output.getvalue().strip(), "") + sys.stdout = self.captured_output + + @unittest.skipUnless(device_connected_dom0(), REQUIRED_DEV) + def test_get_updates_qubes_dom0(self): + get_updates_output = io.StringIO() + sys.stdout = get_updates_output + self.q.get_updates_qubes() + self.assertNotEqual(get_updates_output.getvalue().strip(), "") + sys.stdout = self.captured_output + + @unittest.skipUnless(device_connected_usbvm(), REQUIRED_DEV) + def test_get_updates_qubes_usbvm(self): + get_updates_output = io.StringIO() + sys.stdout = get_updates_output + self.q.get_updates_qubes(usbvm=True) + self.assertNotEqual(get_updates_output.getvalue().strip(), "") + sys.stdout = self.captured_output + + def test_help(self): + help_output = io.StringIO() + sys.stdout = help_output + self.q.help() + with open("test/logs/help.log", "r") as help_log: + self.assertEqual( + help_log.read(), + help_output.getvalue().strip() + "\n" + ) + sys.stdout = self.captured_output + + @patch( + 'test.test_qubes_fwupdmgr.qfwupd.QubesFwupdmgr._read_dmi', + return_value=DMI_DECODE + ) + def test_verify_dmi(self, output): + self.q.dmi_version = "P.1.0" + self.q._verify_dmi("test/logs/", "P1.1") + + @patch( + 'test.test_qubes_fwupdmgr.qfwupd.QubesFwupdmgr._read_dmi', + return_value=DMI_DECODE + ) + def test_verify_dmi_wrong_vendor(self, output): + with self.assertRaises(ValueError) as wrong_vendor: + self.q.dmi_version = "P.1.0" + self.q._verify_dmi("test/logs/metainfo_name/", "P1.1") + self.assertIn( + "Wrong firmware provider.", + str(wrong_vendor.exception) + ) + + @patch( + 'test.test_qubes_fwupdmgr.qfwupd.QubesFwupdmgr._read_dmi', + return_value=DMI_DECODE + ) + def test_verify_dmi_version(self, output): + self.q.dmi_version = "P1.0" + with self.assertRaises(ValueError) as downgrade: + self.q._verify_dmi("test/logs/metainfo_version/", "P0.1") + self.assertIn( + "P0.1 < P1.0 Downgrade not allowed", + str(downgrade.exception) + ) + + @unittest.skipUnless(device_connected_dom0(), REQUIRED_DEV) + def test_downgrade_firmware_dom0(self): + old_version = None + self.q._get_dom0_devices() + downgrades = self.q._parse_downgrades(self.q.dom0_devices_info) + for number, device in enumerate(downgrades): + if "Name" not in device: + continue + if device["Name"] == "ColorHug2": + old_version = device["Version"] + break + if old_version is None: + self.fail("Test device not found") + user_input = [str(number+1), '1'] + with patch('builtins.input', side_effect=user_input): + self.q.downgrade_firmware() + self.q._get_dom0_devices() + downgrades = self.q._parse_downgrades(self.q.dom0_devices_info) + new_version = downgrades[number]["Version"] + self.assertGreater(l_ver(old_version), l_ver(new_version)) + + @unittest.skipUnless( + check_whonix_updatevm() and device_connected_usbvm(), + REQUIRED_DEV + ) + def test_update_n_downgrade_firmware_whonix(self): + old_version = None + self.q.clean_cache(usbvm=True) + self.q._get_dom0_devices() + dom0_downgrades = self.q._parse_downgrades( + self.q.dom0_devices_info + ) + self.q._get_usbvm_devices() + with open(FWUPD_VM_LOG) as usbvm_device_info: + raw = usbvm_device_info.read() + downgrades = self.q._parse_downgrades(raw) + for number, device in enumerate(downgrades): + if "Name" not in device: + continue + if device["Name"] == "ColorHug2": + old_version = device["Version"] + break + if old_version is None: + self.fail("Test device not found") + user_input = [str(number+1+len(dom0_downgrades)), '1'] + with patch('builtins.input', side_effect=user_input): + self.q.downgrade_firmware(usbvm=True, whonix=True) + self.q._get_usbvm_devices() + with open(FWUPD_VM_LOG) as usbvm_device_info: + raw = usbvm_device_info.read() + downgrades = self.q._parse_downgrades(raw) + new_version = downgrades[number]["Version"] + self.assertGreater(l_ver(old_version), l_ver(new_version)) + old_version = None + new_version = None + self.q._get_dom0_updates() + self.q._parse_dom0_updates_info(self.q.dom0_updates_info) + self.q._get_usbvm_devices() + with open(FWUPD_VM_LOG) as usbvm_device_info: + raw = usbvm_device_info.read() + self.q._parse_usbvm_updates(raw) + for number, device in enumerate(self.q.usbvm_updates_list): + if "Name" not in device: + continue + if device["Name"] == "ColorHug2": + old_version = device["Version"] + break + if old_version is None: + self.fail("Test device not found") + user_input = [str(number+1+len(self.q.dom0_updates_list)), '1'] + with patch('builtins.input', side_effect=user_input): + self.q.update_firmware(usbvm=True, whonix=True) + self.q._get_usbvm_devices() + with open(FWUPD_VM_LOG) as usbvm_device_info: + raw = usbvm_device_info.read() + usbvm_devices_info_dict = json.loads(raw) + for device in usbvm_devices_info_dict["Devices"]: + if "Name" not in device: + continue + if device["Name"] == "ColorHug2": + new_version = device["Version"] + break + if new_version is None: + self.fail("Test device not found") + self.assertLess(l_ver(old_version), l_ver(new_version)) + + @unittest.skipUnless(device_connected_usbvm(), REQUIRED_DEV) + def test_downgrade_firmware_usbvm(self): + old_version = None + self.q._get_dom0_devices() + dom0_downgrades = self.q._parse_downgrades( + self.q.dom0_devices_info + ) + self.q._get_usbvm_devices() + with open(FWUPD_VM_LOG) as usbvm_device_info: + raw = usbvm_device_info.read() + downgrades = self.q._parse_downgrades(raw) + for number, device in enumerate(downgrades): + if "Name" not in device: + continue + if device["Name"] == "ColorHug2": + old_version = device["Version"] + break + if old_version is None: + self.fail("Test device not found") + user_input = [str(number+1+len(dom0_downgrades)), '1'] + with patch('builtins.input', side_effect=user_input): + self.q.downgrade_firmware(usbvm=True) + self.q._get_usbvm_devices() + with open(FWUPD_VM_LOG) as usbvm_device_info: + raw = usbvm_device_info.read() + downgrades = self.q._parse_downgrades(raw) + new_version = downgrades[number]["Version"] + self.assertGreater(l_ver(old_version), l_ver(new_version)) + + def test_parse_downgrades(self): + downgrades = self.q._parse_downgrades(GET_DEVICES) + self.assertEqual( + downgrades[0]["Name"], + "ColorHug2" + ) + self.assertEqual( + downgrades[0]["Version"], + "2.0.6" + ) + self.assertEqual( + downgrades[0]["Releases"][0]["Version"], + "2.0.5" + ) + self.assertEqual( + downgrades[0]["Releases"][0]["Url"], + "https://fwupd.org/downloads/f7dd4ab29fa610438571b8b62b26b0b0e57bb35b-hughski-colorhug2-2.0.5.cab" + ) + self.assertEqual( + downgrades[0]["Releases"][0]["Checksum"], + "8cd379eb2e1467e4fda92c20650306dc7e598b1d421841bbe19d9ed6ea01e3ee" + ) + + def test_parse_downgrades_no_version(self): + downgrades = self.q._parse_downgrades(GET_DEVICES_NO_VERSION) + self.assertEqual( + downgrades[0]["Name"], + "ColorHug2" + ) + self.assertEqual( + downgrades[0]["Version"], + "2.0.6" + ) + self.assertEqual( + downgrades[0]["Releases"][0]["Version"], + "2.0.5" + ) + self.assertEqual( + downgrades[0]["Releases"][0]["Url"], + "https://fwupd.org/downloads/f7dd4ab29fa610438571b8b62b26b0b0e57bb35b-hughski-colorhug2-2.0.5.cab" + ) + self.assertEqual( + downgrades[0]["Releases"][0]["Checksum"], + "4ee9dfa38df3b810f739d8a19d13da1b3175fb87" + ) + + def test_user_input_downgrade_usbvm(self): + user_input = ['2', '6', 'sth', '2.2.1', '', ' ', '\0', '2'] + with patch('builtins.input', side_effect=user_input): + downgrade_list = self.q._parse_downgrades(GET_DEVICES) + downgrade_dict = { + "usbvm": downgrade_list, + "dom0": downgrade_list + } + key, device_choice, downgrade_choice = self.q._user_input( + downgrade_dict, + downgrade=True, + usbvm=True + ) + self.assertEqual(key, "usbvm") + self.assertEqual(device_choice, 0) + self.assertEqual(downgrade_choice, 1) + + def test_user_input_downgrade_dom0(self): + user_input = ['1', '6', 'sth', '2.2.1', '', ' ', '\0', '2'] + with patch('builtins.input', side_effect=user_input): + downgrade_list = self.q._parse_downgrades(GET_DEVICES) + downgrade_dict = { + "dom0": downgrade_list + } + key, device_choice, downgrade_choice = self.q._user_input( + downgrade_dict, + downgrade=True, + ) + self.assertEqual(key, "dom0") + self.assertEqual(device_choice, 0) + self.assertEqual(downgrade_choice, 1) + + def test_user_input_downgrade_N(self): + user_input = ['N'] + with patch('builtins.input', side_effect=user_input): + downgrade_list = self.q._parse_downgrades(GET_DEVICES) + downgrade_dict = { + "usbvm": downgrade_list, + "dom0": downgrade_list + } + N_choice = self.q._user_input( + downgrade_dict, + downgrade=True, + usbvm=True + ) + self.assertEqual(N_choice, 2) + + @unittest.skipUnless(device_connected_dom0(), REQUIRED_DEV) + def test_update_firmware_dom0(self): + old_version = None + new_version = None + self.q._get_dom0_updates() + self.q._parse_dom0_updates_info(self.q.dom0_updates_info) + for number, device in enumerate(self.q.dom0_updates_list): + if "Name" not in device: + continue + if device["Name"] == "ColorHug2": + old_version = device["Version"] + break + if old_version is None: + self.fail("Test device not found") + user_input = [str(number+1)] + with patch('builtins.input', side_effect=user_input): + self.q.update_firmware() + self.q._get_dom0_devices() + dom0_devices_info_dict = json.loads(self.q.dom0_devices_info) + for device in dom0_devices_info_dict["Devices"]: + if "Name" not in device: + continue + if device["Name"] == "ColorHug2": + new_version = device["Version"] + break + if new_version is None: + self.fail("Test device not found") + self.assertLess(l_ver(old_version), l_ver(new_version)) + + @unittest.skipUnless(device_connected_usbvm(), REQUIRED_DEV) + def test_update_firmware_usbvm(self): + old_version = None + new_version = None + self.q._get_dom0_updates() + self.q._parse_dom0_updates_info(self.q.dom0_updates_info) + self.q._get_usbvm_devices() + with open(FWUPD_VM_LOG) as usbvm_device_info: + raw = usbvm_device_info.read() + self.q._parse_usbvm_updates(raw) + for number, device in enumerate(self.q.usbvm_updates_list): + if "Name" not in device: + continue + if device["Name"] == "ColorHug2": + old_version = device["Version"] + break + if old_version is None: + self.fail("Test device not found") + user_input = [str(number+1+len(self.q.dom0_updates_list)), '1'] + with patch('builtins.input', side_effect=user_input): + self.q.update_firmware(usbvm=True) + self.q._get_usbvm_devices() + with open(FWUPD_VM_LOG) as usbvm_device_info: + raw = usbvm_device_info.read() + usbvm_devices_info_dict = json.loads(raw) + for device in usbvm_devices_info_dict["Devices"]: + if "Name" not in device: + continue + if device["Name"] == "ColorHug2": + new_version = device["Version"] + break + if new_version is None: + self.fail("Test device not found") + self.assertLess(l_ver(old_version), l_ver(new_version)) + + @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM) + def test_get_usbvm_devices(self): + self.q._get_usbvm_devices() + self.assertTrue(os.path.exists(FWUPD_VM_LOG)) + + def test_parse_usbvm_updates(self): + self.q._parse_usbvm_updates(GET_DEVICES) + self.assertEqual(self.q.usbvm_updates_list[0]["Name"], "ColorHug2") + self.assertEqual(self.q.usbvm_updates_list[0]["Version"], "2.0.6") + self.assertListEqual( + self.q.usbvm_updates_list[0]["Releases"], + [ + { + 'Checksum': '32c4a2c9be787cdf1d757c489d6455bd7bb14053425180b6d331c37e1ccc1cda', + 'Description': '

    This release fixes prevents the firmware returning an ' + 'error when the remote SHA1 hash was never sent.

    ', + 'Url': 'https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab', + 'Version': '2.0.7' + } + ] + ) + + def test_parse_usbvm_updates_no_updates_available(self): + self.q._parse_usbvm_updates(GET_DEVICES_NO_UPDATES) + self.assertListEqual(self.q.usbvm_updates_list, []) + + def test_updates_crawler(self): + crawler_output = io.StringIO() + sys.stdout = crawler_output + self.q._parse_usbvm_updates(GET_DEVICES) + self.q._updates_crawler(self.q.usbvm_updates_list, usbvm=True) + with open("test/logs/get_updates.log", "r") as getupdates: + self.assertEqual( + getupdates.read(), + crawler_output.getvalue().strip() + "\n" + ) + sys.stdout = self.captured_output + + @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM) + def test_validate_usbvm_dirs(self): + self.q._validate_usbvm_dirs() + cmd_validate_metadata = [ + "qvm-run", + "--pass-io", + "sys-usb", + f"[ -d {FWUPD_VM_METADATA_DIR} ]" + ] + p = subprocess.Popen(cmd_validate_metadata) + p.wait() + self.assertEqual( + p.returncode, + 0, + msg="Creating metadata directory failed" + ) + cmd_validate_udpdate = [ + "qvm-run", + "--pass-io", + "sys-usb", + f"[ -d {FWUPD_VM_UPDATES_DIR} ]" + ] + p = subprocess.Popen(cmd_validate_udpdate) + p.wait() + self.assertEqual( + p.returncode, + 0, + msg="Creating update directory failed" + ) + + @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM) + def test_copy_usbvm_metadata(self): + self.q.metadata_file = FWUPD_DOM0_METADATA_FILE + self.q.metadata_file_jcat = self.q.metadata_file + '.jcat' + self.q._download_metadata() + self.q._validate_usbvm_dirs() + self.q._copy_usbvm_metadata() + cmd_validate_metadata_file = [ + "qvm-run", + "--pass-io", + "sys-usb", + f"[ -f {FWUPD_VM_METADATA_FILE} ]" + ] + p = subprocess.Popen(cmd_validate_metadata_file) + p.wait() + self.assertEqual( + p.returncode, + 0, + msg="Metadata file does not exist" + ) + cmd_validate_metadata_jcat = [ + "qvm-run", + "--pass-io", + "sys-usb", + f"[ -f {FWUPD_VM_METADATA_FILE_JCAT} ]" + ] + p = subprocess.Popen(cmd_validate_metadata_jcat) + p.wait() + self.assertEqual( + p.returncode, + 0, + msg="Metadata jcat signature does not exist" + ) + + @unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") + def test_enable_lvfs_testing_dom0(self): + if os.path.exists(LVFS_TESTING_DOM0_FLAG): + os.remove(LVFS_TESTING_DOM0_FLAG) + self.q._enable_lvfs_testing_dom0() + self.assertTrue(os.path.exists(LVFS_TESTING_DOM0_FLAG)) + + @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM) + def test_enable_lvfs_testing_usbvm(self): + cmd_validate_flag = [ + "qvm-run", + "--pass-io", + USBVM_N, + ( + 'script --quiet --return --command ' + f'"ls {LVFS_TESTING_USBVM_FLAG} &>/dev/null"' + ) + ] + cmd_rm_flag = [ + "qvm-run", + "--pass-io", + USBVM_N, + ( + 'script --quiet --return --command ' + f'"rm {LVFS_TESTING_USBVM_FLAG}"' + ) + ] + flag = subprocess.Popen(cmd_validate_flag) + flag.wait() + if flag.returncode == 0: + rm_flag = subprocess.Popen(cmd_rm_flag) + rm_flag.wait() + if rm_flag.returncode != 0: + raise Exception("Removing lvfs-testing flag failed!!") + self.q._enable_lvfs_testing_usbvm(usbvm=True) + flag = subprocess.Popen(cmd_validate_flag) + flag.wait() + self.assertEqual(flag.returncode, 0) + + @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM) + def test_validate_usbvm_metadata(self): + self.q.metadata_file = FWUPD_DOM0_METADATA_FILE + self.q.metadata_file_jcat = self.q.metadata_file + '.jcat' + self.q._download_metadata() + self.q._validate_usbvm_dirs() + self.q._copy_usbvm_metadata() + self.q._validate_usbvm_metadata() + + @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM) + def test_refresh_usbvm_metadata(self): + self.q.metadata_file = FWUPD_DOM0_METADATA_FILE + self.q.metadata_file_jcat = self.q.metadata_file + '.jcat' + self.q.lvfs = "lvfs" + self.q._download_metadata() + self.q._validate_usbvm_dirs() + self.q._copy_usbvm_metadata() + self.q._validate_usbvm_metadata() + self.q._refresh_usbvm_metadata() + + @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM) + def test_clean_usbvm(self): + self.q._validate_usbvm_dirs() + self.q._clean_usbvm() + cmd_validate_metadata = [ + "qvm-run", + "--pass-io", + "sys-usb", + f"! [ -d {FWUPD_VM_METADATA_DIR} ]" + ] + p = subprocess.Popen(cmd_validate_metadata) + p.wait() + self.assertEqual( + p.returncode, + 0, + msg="Cleaning metadata directory failed" + ) + cmd_validate_udpdate = [ + "qvm-run", + "--pass-io", + "sys-usb", + f"! [ -d {FWUPD_VM_METADATA_DIR} ]" + ] + p = subprocess.Popen(cmd_validate_udpdate) + p.wait() + self.assertEqual( + p.returncode, + 0, + msg="Cleaning update directory failed" + ) + + @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM) + def test_validate_usbvm_archive(self): + url = "https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab" + sha = "32c4a2c9be787cdf1d757c489d6455bd7bb14053425180b6d331c37e1ccc1cda" + name = url.replace("https://fwupd.org/downloads/", "") + self.q._clean_usbvm() + self.q._validate_usbvm_dirs() + self.q._download_firmware_updates( + url, + sha + ) + self.q._copy_firmware_updates( + name + ) + self.q._validate_usbvm_archive( + name, + sha + ) + cmd_validate_udpdate = [ + "qvm-run", + "--pass-io", + "sys-usb", + "[ -f %s ]" % + os.path.join(FWUPD_VM_UPDATES_DIR, name) + ] + p = subprocess.Popen(cmd_validate_udpdate) + p.wait() + self.assertEqual( + p.returncode, + 0, + msg="Archive validation failed" + ) + + @unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") + def test_check_usbvm(self): + self.q.check_usbvm() + self.assertIn(XL_LIST_LOG, self.q.output) + + @unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") + def test_bios_refresh_metadata(self): + sys_usb = self.q.check_usbvm() + Path(BIOS_UPDATE_FLAG).touch(mode=0o644, exist_ok=True) + self.q.refresh_metadata_after_bios_update(usbvm=sys_usb) + self.assertEqual( + self.q.output, + 'Successfully refreshed metadata manually\n', + msg="Metadata refresh failed." + ) + + @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM) + def test_trusted_cleanup(self): + trusted_path = os.path.join(FWUPD_DOM0_UPDATES_DIR, "trusted.cab") + if not os.path.exists(trusted_path): + Path(FWUPD_DOM0_UPDATES_DIR).mkdir(exist_ok=True) + Path(trusted_path).touch(mode=0o644, exist_ok=True) + os.mkdir(trusted_path.replace(".cab", "")) + self.q.trusted_cleanup(usbvm=True) + self.assertFalse(os.path.exists(trusted_path)) + self.assertFalse(os.path.exists(trusted_path.replace(".cab", ""))) + + +if __name__ == '__main__': + unittest.main() diff -Nru fwupd-1.4.5/contrib/README.md fwupd-1.5.8/contrib/README.md --- fwupd-1.4.5/contrib/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/contrib/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -11,39 +11,54 @@ To prepare the Docker container run this command: ``` -OS=fedora ./generate_docker.py +OS=fedora ./generate_docker.py build ``` To build the RPMs run this command (from the root of your git checkout): ``` -docker run --privileged -t -v `pwd`:/build fwupd-fedora +docker run --privileged -t -v `pwd`:/github/workspace fwupd-fedora ``` RPMs will be made available in your working directory when complete. +To build additional RPM packages for Qubes OS (fwupd-qubes-dom0 and +fwupd-qubes-vm) add `QUBES=true` environment variable: + +``` +docker run --privileged -e QUBES=true -t -v `pwd`:/github/workspace fwupd-fedora +``` + + ## DEB packages A Dockerfile for Debian or Ubuntu can be generated in `contrib`. To prepare the Docker container run one of these commands: ``` -OS=debian-x86_64 ./generate_docker.py -OS=debian-i386 ./generate_docker.py -OS=ubuntu-x86_64 ./generate_docker.py +OS=debian-x86_64 ./generate_docker.py build +OS=debian-i386 ./generate_docker.py build +OS=ubuntu-x86_64 ./generate_docker.py build ``` To build the DEBs run one of these commands (from the root of your git checkout): ``` -docker run --privileged -t -v `pwd`:/build fwupd-debian-x86_64 -docker run --privileged -t -v `pwd`:/build fwupd-debian-i386 -docker run --privileged -t -v `pwd`:/build fwupd-ubuntu-x86_64 +docker run --privileged -t -v `pwd`:/github/workspace fwupd-debian-x86_64 +docker run --privileged -t -v `pwd`:/github/workspace fwupd-debian-i386 +docker run --privileged -t -v `pwd`:/github/workspace fwupd-ubuntu-x86_64 ``` DEBs will be made available in your working directory when complete. +To build additional DEB package for Qubes OS (fwupd-qubes-vm-whonix) +add `QUBES=true` environment variable: + +``` +docker run --privileged -t -v `pwd`:/github/workspace fwupd-debian-x86_64-qubes +``` + ## PKG packages A Dockerfile for Arch can be generated in `contrib`. @@ -62,7 +77,7 @@ PKGs will be made available in your working directory when complete. ## Additional packages -Submissions for generating additional packages for other distribution mechanisms are also welcome. +Submissions for generating additional packages for other distribution mechanisms are also welcome. All builds should occur in Docker containers. Please feel free to submit the following: diff -Nru fwupd-1.4.5/contrib/setup-win32.nsi fwupd-1.5.8/contrib/setup-win32.nsi --- fwupd-1.4.5/contrib/setup-win32.nsi 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/contrib/setup-win32.nsi 2021-03-31 20:08:32.000000000 +0000 @@ -40,19 +40,17 @@ File "/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libgnutls-30.dll" File "/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libgobject-2.0-0.dll" File "/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libgusb-2.dll" - File "/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libhogweed-4.dll" + File "/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libhogweed-5.dll" File "/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libidn2-0.dll" File "/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libintl-8.dll" File "/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libjson-glib-1.0-0.dll" File "/usr/x86_64-w64-mingw32/sys-root/mingw/bin/liblzma-5.dll" - File "/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libnettle-6.dll" + File "/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libnettle-7.dll" File "/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libp11-kit-0.dll" File "/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libpcre-1.dll" - File "/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libpsl-5.dll" - File "/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libsoup-2.4-1.dll" + File "/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libcurl-4.dll" File "/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libsqlite3-0.dll" File "/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libtasn1-6.dll" - File "/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libunistring-2.dll" File "/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libusb-1.0.dll" File "/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libwinpthread-1.dll" File "/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libxml2-2.dll" @@ -65,7 +63,7 @@ File "libfwupd-2.dll" File "libfwupdplugin-1.dll" File "libgcab-1.0-0.dll" - File "libxmlb-1.dll" + File "libxmlb-2.dll" File "libjcat-1.dll" SetOutPath "$INSTDIR\fwupd-plugins-3" File /r "fwupd-plugins-3/libfu_plugin_*.dll" diff -Nru fwupd-1.4.5/contrib/snap/dbxtool.wrapper fwupd-1.5.8/contrib/snap/dbxtool.wrapper --- fwupd-1.4.5/contrib/snap/dbxtool.wrapper 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/contrib/snap/dbxtool.wrapper 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,2 @@ +#!/bin/sh +exec "$SNAP/fwupd-command" $SNAP/bin/dbxtool $@ diff -Nru fwupd-1.4.5/data/90-fwupd-devices.rules fwupd-1.5.8/data/90-fwupd-devices.rules --- fwupd-1.4.5/data/90-fwupd-devices.rules 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/data/90-fwupd-devices.rules 2021-03-31 20:08:32.000000000 +0000 @@ -4,23 +4,5 @@ # SPDX-License-Identifier: LGPL-2.1+ # -# VIA USB 3.0 VL811 Hub -SUBSYSTEM=="usb", DRIVER=="hub", ATTRS{idVendor}=="2109", ATTRS{idProduct}=="0810", ENV{FWUPD_GUID}="adbb9034-b577-42c2-a661-1ee4f49ef64c", ENV{FWUPD_VENDOR}="VIA", ENV{FWUPD_MODEL}="USB 3.0 VL811 Hub" - -# VIA USB 3.0 VL811+ Hub -SUBSYSTEM=="usb", DRIVER=="hub", ATTRS{idVendor}=="2109", ATTRS{idProduct}=="0811", ENV{FWUPD_GUID}="54f84d05-c917-4c50-8b35-44feabaaa323", ENV{FWUPD_VENDOR}="VIA", ENV{FWUPD_MODEL}="USB 3.0 VL811+ Hub" - -# VIA USB 3.0 VL812 Hub -SUBSYSTEM=="usb", DRIVER=="hub", ATTRS{idVendor}=="2109", ATTRS{idProduct}=="0812", ENV{FWUPD_GUID}="cd0314ec-b80f-4d1a-a24f-c409183a8b2d", ENV{FWUPD_VENDOR}="VIA", ENV{FWUPD_MODEL}="USB 3.0 VL812 Hub" - -# VIA USB 3.0 VL812 B2 Hub -SUBSYSTEM=="usb", DRIVER=="hub", ATTRS{idVendor}=="2109", ATTRS{idProduct}=="2812", ENV{FWUPD_GUID}="26470009-97a8-4028-867a-bbbac6ee7bf0", ENV{FWUPD_VENDOR}="VIA", ENV{FWUPD_MODEL}="USB 3.0 VL812 B2 Hub" - -ENV{FWUPD_GUID}=="*?", ENV{ID_MODEL}=="", IMPORT{builtin}="usb_id" -ENV{FWUPD_GUID}=="*?", ENV{ID_MODEL_FROM_DATABASE}=="", IMPORT{builtin}="hwdb --subsystem=usb" - -# PCI cards with ROM -SUBSYSTEM=="pci", TEST=="/sys$devpath/rom", ENV{FWUPD_GUID}="$attr{vendor}:$attr{device}" - # NVMe hardware SUBSYSTEM=="nvme", ENV{ID_VENDOR_FROM_DATABASE}=="", IMPORT{builtin}="hwdb --subsystem=pci" diff -Nru fwupd-1.4.5/data/bash-completion/fwupdagent fwupd-1.5.8/data/bash-completion/fwupdagent --- fwupd-1.4.5/data/bash-completion/fwupdagent 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/data/bash-completion/fwupdagent 2021-03-31 20:08:32.000000000 +0000 @@ -2,6 +2,7 @@ 'get-devices' 'get-updates' 'get-upgrades' + 'security' ) _fwupdagent_opts=( diff -Nru fwupd-1.4.5/data/bash-completion/fwupdmgr.in fwupd-1.5.8/data/bash-completion/fwupdmgr.in --- fwupd-1.4.5/data/bash-completion/fwupdmgr.in 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/data/bash-completion/fwupdmgr.in 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,6 @@ _fwupdmgr_cmd_list=( 'activate' + 'block-firmware' 'clear-history' 'clear-offline' 'clear-results' @@ -7,6 +8,7 @@ 'downgrade' 'enable-remote' 'get-approved-firmware' + 'get-blocked-firmware' 'get-details' 'get-devices' 'get-history' @@ -16,14 +18,18 @@ 'get-topology' 'get-updates' 'get-upgrades' + 'get-plugins' 'install' 'modify-config' 'modify-remote' 'reinstall' 'refresh' 'report-history' + 'security' 'set-approved-firmware' + 'switch-branch' 'unlock' + 'unblock-firmware' 'update' 'upgrade' 'verify' @@ -36,6 +42,7 @@ '--offline' '--allow-reinstall' '--allow-older' + '--allow-branch-switch' '--force' '--assume-yes' '--no-history' @@ -43,10 +50,13 @@ '--no-metadata-check' '--no-reboot-check' '--no-safety-check' - '--show-all-devices' + '--no-remote-check' + '--show-all' '--sign' '--filter' '--disable-ssl-strict' + '--ipfs' + '--ignore-power' ) _show_filters() @@ -94,7 +104,7 @@ esac case $command in - activate|clear-results|downgrade|get-releases|get-results|unlock|verify|verify-update) + activate|clear-results|downgrade|get-releases|get-results|unlock|verify|verify-update|get-updates|switch-branch) if [[ "$prev" = "$command" ]]; then _show_device_ids else diff -Nru fwupd-1.4.5/data/bash-completion/fwupdtool.in fwupd-1.5.8/data/bash-completion/fwupdtool.in --- fwupd-1.4.5/data/bash-completion/fwupdtool.in 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/data/bash-completion/fwupdtool.in 2021-03-31 20:08:32.000000000 +0000 @@ -1,7 +1,12 @@ _fwupdtool_cmd_list=( 'activate' 'build-firmware' + 'esp-list' + 'esp-mount' + 'esp-unmount' + 'firmware-build' 'firmware-convert' + 'firmware-extract' 'firmware-parse' 'get-updates' 'get-upgrades' @@ -20,14 +25,19 @@ 'install-blob' 'monitor' 'reinstall' + 'security' + 'switch-branch' 'self-sign' 'smbios-dump' 'attach' 'detach' - 'firmware-read' + 'firmware-dump' 'refresh' 'verify-update' 'watch' + 'unbind-driver' + 'bind-driver' + 'export-hwids' ) _fwupdtool_opts=( @@ -36,13 +46,16 @@ '--allow-reinstall' '--allow-older' '--force' - '--show-all-devices' - '--plugin-whitelist' + '--show-all' + '--plugins' '--prepare' '--cleanup' '--filter' '--disable-ssl-strict' '--no-safety-check' + '--ignore-checksum' + '--ignore-vid-pid' + '--ignore-power' ) _show_filters() @@ -81,7 +94,7 @@ command=${COMP_WORDS[1]} case $prev in - --plugin-whitelist) + --plugins) _show_plugins return 0 ;; @@ -92,7 +105,7 @@ esac case $command in - get-details|install|install-blob|firmware-read) + get-details|install|install-blob|firmware-dump) #find files if [[ "$prev" = "$command" ]]; then _filedir @@ -101,7 +114,7 @@ _show_modifiers fi ;; - attach|detach|activate|verify-update|reinstall) + attach|detach|activate|verify-update|reinstall|get-updates) if [[ "$prev" = "$command" ]]; then _show_device_ids #modifiers diff -Nru fwupd-1.4.5/data/daemon.conf fwupd-1.5.8/data/daemon.conf --- fwupd-1.4.5/data/daemon.conf 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/data/daemon.conf 2021-03-31 20:08:32.000000000 +0000 @@ -1,12 +1,12 @@ [fwupd] -# Allow blacklisting specific devices by their GUID +# Allow blocking specific devices by their GUID # Uses semicolons as delimiter -BlacklistDevices= +DisabledDevices= -# Allow blacklisting specific plugins +# Allow blocking specific plugins # Uses semicolons as delimiter -BlacklistPlugins=test;invalid +DisabledPlugins=test;test_ble;invalid # Maximum archive size that can be loaded in Mb, with 0 for the default ArchiveSizeMax=0 @@ -32,3 +32,13 @@ # A list of firmware checksums that has been approved by the site admin # If unset, all firmware is approved ApprovedFirmware= + +# Allow blocking specific devices by their checksum, either SHA1 or SHA256 +# Uses semicolons as delimiter +BlockedFirmware= + +# Allowed URI schemes in the preference order; failed downloads from the first +# scheme will be retried with the next in order until no choices remain. +# +# If unset or no schemes are listed, the default will be: file,https,http,ipfs +UriSchemes= diff -Nru fwupd-1.4.5/data/device-tests/devices/broadcom-bcm5719.json fwupd-1.5.8/data/device-tests/devices/broadcom-bcm5719.json --- fwupd-1.4.5/data/device-tests/devices/broadcom-bcm5719.json 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/data/device-tests/devices/broadcom-bcm5719.json 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,12 @@ +{ + "name": "NetXtreme BCM5719", + "guids": [ + "ec5b8a9e-973b-58cc-935b-8322fabaebe9" + ], + "releases": [ + { + "version": "0.4.44", + "file": "dfbb6529d3f7051497cc7e736848b5b6e276ff93b39bc765948663606dc87c25-bcm5719-0.4.44.cab" + } + ] +} diff -Nru fwupd-1.4.5/data/device-tests/devices/dell-kh08p.json fwupd-1.5.8/data/device-tests/devices/dell-kh08p.json --- fwupd-1.4.5/data/device-tests/devices/dell-kh08p.json 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/data/device-tests/devices/dell-kh08p.json 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,16 @@ +{ + "name": "Dell KH08P [BCM5719]", + "guids": [ + "ec5b8a9e-973b-58cc-935b-8322fabaebe9" + ], + "releases": [ + { + "version": "0.4.62", + "file": "6cf165037a381eb29c183319e031def6b87e3ce955781ecf73f28751a1365db2-kh08p-bcm5719-0.4.62.cab" + }, + { + "version": "0.4.64", + "file": "4b8eb1735b7461e0f6f856447527bc0edbb31b4681e71aaef488a62a65fa14eb-kh08p-bcm5719-0.4.64.cab" + } + ] +} diff -Nru fwupd-1.4.5/data/device-tests/devices/hp-dock-g5.json fwupd-1.5.8/data/device-tests/devices/hp-dock-g5.json --- fwupd-1.4.5/data/device-tests/devices/hp-dock-g5.json 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/data/device-tests/devices/hp-dock-g5.json 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,16 @@ +{ + "name": "HP USB-C Dock G5", + "guids": [ + "9434f89a-3351-536d-a281-f70203326833" + ], + "releases": [ + { + "version": "1.0.8.0", + "file": "c320fae2f84bf362cbbddb0f57d899b42e4e05d52a53e8a01e131495c7f10fe6-HP-USBC_DOCK_G5-V1.0.8.0.cab" + }, + { + "version": "1.0.11.0", + "file": "61467bb36546de4449bfc72f9001fb0824606a8ef0b268383f145acf59c473f8-HP-USBC_DOCK_G5-V1.0.11.0.cab" + } + ] +} diff -Nru fwupd-1.4.5/data/device-tests/devices/hyper-no-sku-vli-tier1.json fwupd-1.5.8/data/device-tests/devices/hyper-no-sku-vli-tier1.json --- fwupd-1.4.5/data/device-tests/devices/hyper-no-sku-vli-tier1.json 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/data/device-tests/devices/hyper-no-sku-vli-tier1.json 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,16 @@ +{ + "name": "Hyper USB-C Hub [VL817+VL103]", + "guids": [ + "a476b1bb-9f8e-5ad4-a0ed-afadb52334fc" + ], + "releases": [ + { + "version": "90.83", + "file": "ecfebc47d63a5319e35da39bd6124b80e90138a208bc9134c9d1b256b232a704-Hyper-USB-C_Hub.cab" + }, + { + "version": "80.83", + "file": "1694cceda16068b24d7627caace4bd373ecae73aca891f610dec0fe5a4d1207c-Hyper-USB-C_Hub_Old.cab" + } + ] +} diff -Nru fwupd-1.4.5/data/device-tests/devices/hyper-no-sku-vli-tier3.json fwupd-1.5.8/data/device-tests/devices/hyper-no-sku-vli-tier3.json --- fwupd-1.4.5/data/device-tests/devices/hyper-no-sku-vli-tier3.json 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/data/device-tests/devices/hyper-no-sku-vli-tier3.json 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,16 @@ +{ + "name": "Hyper USB-C Hub [VL817+VL103]", + "guids": [ + "0a120f99-b0f4-52af-9af9-e13155634370" + ], + "releases": [ + { + "version": "154.36.9.55", + "file": "ecfebc47d63a5319e35da39bd6124b80e90138a208bc9134c9d1b256b232a704-Hyper-USB-C_Hub.cab" + }, + { + "version": "138.36.9.55", + "file": "1694cceda16068b24d7627caace4bd373ecae73aca891f610dec0fe5a4d1207c-Hyper-USB-C_Hub_Old.cab" + } + ] +} diff -Nru fwupd-1.4.5/data/device-tests/devices/lenovo-03x7608-vli-tier1.json fwupd-1.5.8/data/device-tests/devices/lenovo-03x7608-vli-tier1.json --- fwupd-1.4.5/data/device-tests/devices/lenovo-03x7608-vli-tier1.json 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/data/device-tests/devices/lenovo-03x7608-vli-tier1.json 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,16 @@ +{ + "name": "Lenovo Travel Hub Gen2 [VL817]", + "guids": [ + "3fc55e47-f57a-55bd-9f41-ac60280bd689" + ], + "releases": [ + { + "version": "4.64", + "file": "a1c4d77e21d2733519d09bb2cce558b76052483ca5e976f7e49898e8a0ab6c86-Lenovo-Travel_Hub_Gen2_New.cab" + }, + { + "version": "4.44", + "file": "4c1cc0c3f855a2435f8e3b5dafe26f05148c151e9164e8c3c7c41507f9155e0f-Lenovo-Travel_Hub_Gen2_Old.cab" + } + ] +} diff -Nru fwupd-1.4.5/data/device-tests/devices/lenovo-03x7608-vli-tier3.json fwupd-1.5.8/data/device-tests/devices/lenovo-03x7608-vli-tier3.json --- fwupd-1.4.5/data/device-tests/devices/lenovo-03x7608-vli-tier3.json 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/data/device-tests/devices/lenovo-03x7608-vli-tier3.json 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,16 @@ +{ + "name": "Lenovo Travel Hub Gen2 [VL817]", + "guids": [ + "3ae6610b-5c33-5714-96e3-05735eb9b2a5" + ], + "releases": [ + { + "version": "138.4.69.18", + "file": "a1c4d77e21d2733519d09bb2cce558b76052483ca5e976f7e49898e8a0ab6c86-Lenovo-Travel_Hub_Gen2_New.cab" + }, + { + "version": "138.4.17.18", + "file": "4c1cc0c3f855a2435f8e3b5dafe26f05148c151e9164e8c3c7c41507f9155e0f-Lenovo-Travel_Hub_Gen2_Old.cab" + } + ] +} diff -Nru fwupd-1.4.5/data/device-tests/devices/lenovo-03x7609-cxaudio.json fwupd-1.5.8/data/device-tests/devices/lenovo-03x7609-cxaudio.json --- fwupd-1.4.5/data/device-tests/devices/lenovo-03x7609-cxaudio.json 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/data/device-tests/devices/lenovo-03x7609-cxaudio.json 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,13 @@ +{ + "name": "Lenovo USB-C Dock Gen2 (CXAUDIO)", + "guids": [ + "dbb8d54c-42e6-5215-b7ac-1df16872bb06" + ], + "repeat": 2, + "releases": [ + { + "version": "49-0E-14", + "file": "a5c8f0883f6089b780a25490b53eb8d5d6ba8a1d109ce44f18bd2b2ef3ffe315-Lenovo-ThinkPad-USBCGen2Dock-Firmware-49-0E-14.cab" + } + ] +} diff -Nru fwupd-1.4.5/data/device-tests/devices/lenovo-40au0065-vli-tier1.json fwupd-1.5.8/data/device-tests/devices/lenovo-40au0065-vli-tier1.json --- fwupd-1.4.5/data/device-tests/devices/lenovo-40au0065-vli-tier1.json 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/data/device-tests/devices/lenovo-40au0065-vli-tier1.json 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,16 @@ +{ + "name": "Lenovo USB-C Mini Dock [VL817]", + "guids": [ + "f281c1df-c3d5-5f8a-984d-e9548ffc95fe" + ], + "releases": [ + { + "version": "4.154", + "file": "3b183e21869e4fce8bc81b3357de2fd1ee47b35e272e26169ebaee88faa39e03-Lenovo-Mini_Dock_New.cab" + }, + { + "version": "4.94", + "file": "f55a307af1dc66d46bc12460ced828b31b2ee2a78c1d58d4f474958c2c6d134e-Lenovo-Mini_Dock_Old.cab" + } + ] +} diff -Nru fwupd-1.4.5/data/device-tests/devices/lenovo-40au0065-vli-tier2.json fwupd-1.5.8/data/device-tests/devices/lenovo-40au0065-vli-tier2.json --- fwupd-1.4.5/data/device-tests/devices/lenovo-40au0065-vli-tier2.json 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/data/device-tests/devices/lenovo-40au0065-vli-tier2.json 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,16 @@ +{ + "name": "Lenovo USB-C Mini Dock [VL211]", + "guids": [ + "d636c717-44c4-5fcf-9d7f-b96f9c5f6608" + ], + "releases": [ + { + "version": "4.43", + "file": "3b183e21869e4fce8bc81b3357de2fd1ee47b35e272e26169ebaee88faa39e03-Lenovo-Mini_Dock_New.cab" + }, + { + "version": "4.33", + "file": "f55a307af1dc66d46bc12460ced828b31b2ee2a78c1d58d4f474958c2c6d134e-Lenovo-Mini_Dock_Old.cab" + } + ] +} diff -Nru fwupd-1.4.5/data/device-tests/devices/lenovo-40au0065-vli-tier3.json fwupd-1.5.8/data/device-tests/devices/lenovo-40au0065-vli-tier3.json --- fwupd-1.4.5/data/device-tests/devices/lenovo-40au0065-vli-tier3.json 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/data/device-tests/devices/lenovo-40au0065-vli-tier3.json 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,16 @@ +{ + "name": "Lenovo USB-C Mini Dock [VL103]", + "guids": [ + "3ae6610b-5c33-5714-96e3-05735eb9b2a5" + ], + "releases": [ + { + "version": "138.4.24.38", + "file": "3b183e21869e4fce8bc81b3357de2fd1ee47b35e272e26169ebaee88faa39e03-Lenovo-Mini_Dock_New.cab" + }, + { + "version": "138.4.23.38", + "file": "f55a307af1dc66d46bc12460ced828b31b2ee2a78c1d58d4f474958c2c6d134e-Lenovo-Mini_Dock_Old.cab" + } + ] +} diff -Nru fwupd-1.4.5/data/device-tests/devices/system76-thelio.json fwupd-1.5.8/data/device-tests/devices/system76-thelio.json --- fwupd-1.4.5/data/device-tests/devices/system76-thelio.json 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/data/device-tests/devices/system76-thelio.json 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,21 @@ +{ + "name": "System76 Thelio Io", + "guids": [ + "fdac0b40-51c6-591b-a049-e9cfc05e9271" + ], + "protocol": "org.usb.dfu", + "releases": [ + { + "version": "0.0.0", + "file": "ed423e586cdd35d41f0dd708ea8e5b5b97c54d48eef7e23a02d9a088b231b3fd-thelio-io_0.0.0.cab" + }, + { + "version": "1.0.0", + "file": "1be9bcfa7b5f0db2bca927505f82d8829be5882ca295e33af492d0e1fdacc162-thelio-io_1.0.0.cab" + }, + { + "version": "1.0.2", + "file": "63d4a480162b729fc57ff7c92c1e2254540f43d6-thelio-io_1.0.2.cab" + } + ] +} diff -Nru fwupd-1.4.5/data/fish-completion/fwupdmgr.fish fwupd-1.5.8/data/fish-completion/fwupdmgr.fish --- fwupd-1.4.5/data/fish-completion/fwupdmgr.fish 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/data/fish-completion/fwupdmgr.fish 2021-03-31 20:08:32.000000000 +0000 @@ -18,7 +18,8 @@ complete -c fwupdmgr -l offline -d 'Schedule installation for next reboot when possible' complete -c fwupdmgr -l allow-reinstall -d 'Allow reinstalling existing firmware versions' complete -c fwupdmgr -l allow-older -d 'Allow downgrading firmware versions' -complete -c fwupdmgr -l force -d 'Override warnings and force the action' +complete -c fwupdmgr -l allow-branch-switch -d 'Allow switching firmware branch' +complete -c fwupdmgr -l force -d 'Force the action by relaxing some runtime checks' complete -c fwupdmgr -s y -l assume-yes -d 'Answer yes to all questions' complete -c fwupdmgr -l sign -d 'Sign the uploaded data with the client certificate' complete -c fwupdmgr -l no-unreported-check -d 'Do not check for unreported history' @@ -26,12 +27,15 @@ complete -c fwupdmgr -l no-reboot-check -d 'Do not check for reboot after update' complete -c fwupdmgr -l no-safety-check -d 'Do not perform device safety checks' complete -c fwupdmgr -l no-history -d 'Do not write to the history database' -complete -c fwupdmgr -l show-all-devices -d 'Show devices that are not updatable' -complete -c fwupdmgr -l disable-ssl-strict -d 'Ignore SSL strict checks when downloading files' +complete -c fwupdmgr -l show-all -d 'Show all results' +complete -c fwupdmgr -l disable-ssl-strict -d 'Ignore SSL strict checks when downloading' +complete -c fwupdmgr -l ipfs -d 'Use IPFS when downloading files' complete -c fwupdmgr -l filter -d 'Filter with a set of device flags' +complete -c fwupdmgr -l ignore-power -d 'Ignore requirement of external power source' # complete subcommands complete -c fwupdmgr -n '__fish_use_subcommand' -x -a activate -d 'Activate devices' +complete -c fwupdmgr -n '__fish_use_subcommand' -x -a block-firmware -d 'Blocks a specific firmware from being installed' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a clear-history -d 'Erase all firmware update history' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a clear-offline -d 'Clears any updates scheduled to be updated offline' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a clear-results -d 'Clears the results from the last update' @@ -39,6 +43,7 @@ complete -c fwupdmgr -n '__fish_use_subcommand' -x -a downgrade -d 'Downgrades the firmware on a device' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a enable-remote -d 'Enables a given remote' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a get-approved-firmware -d 'Gets the list of approved firmware' +complete -c fwupdmgr -n '__fish_use_subcommand' -x -a get-blocked-firmware -d 'Gets the list of blocked firmware' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a get-details -d 'Gets details about a firmware file' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a get-devices -d 'Get all devices that support firmware updates' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a get-history -d 'Show history of firmware updates' @@ -47,19 +52,22 @@ complete -c fwupdmgr -n '__fish_use_subcommand' -x -a get-results -d 'Gets the results from the last update' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a get-updates -d 'Gets the list of updates for connected hardware' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a install -d 'Install a firmware file on this hardware' -complete -c fwupdmgr -n '__fish_use_subcommand' -x -a modify-config -d 'Modifies a daemon configuration value.' +complete -c fwupdmgr -n '__fish_use_subcommand' -x -a modify-config -d 'Modifies a daemon configuration value' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a modify-remote -d 'Modifies a given remote' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a refresh -d 'Refresh metadata from remote server' -complete -c fwupdmgr -n '__fish_use_subcommand' -x -a reinstall -d 'Reinstall current firmware on the device.' +complete -c fwupdmgr -n '__fish_use_subcommand' -x -a reinstall -d 'Reinstall current firmware on the device' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a report-history -d 'Share firmware history with the developers' -complete -c fwupdmgr -n '__fish_use_subcommand' -x -a set-approved-firmware -d 'Sets the list of approved firmware.' +complete -c fwupdmgr -n '__fish_use_subcommand' -x -a security -d 'Gets the host security attributes' +complete -c fwupdmgr -n '__fish_use_subcommand' -x -a set-approved-firmware -d 'Sets the list of approved firmware' +complete -c fwupdmgr -n '__fish_use_subcommand' -x -a switch-branch -d 'Switch the firmware branch on the device' +complete -c fwupdmgr -n '__fish_use_subcommand' -x -a unblock-firmware -d 'Unblocks a specific firmware from being installed' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a unlock -d 'Unlocks the device for firmware access' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a update -d 'Updates all firmware to latest versions available' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a verify -d 'Checks cryptographic hash matches firmware' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a verify-update -d 'Update the stored cryptographic hash with current ROM contents' # commands exclusively consuming device IDs -set -l deviceid_consumers activate clear-results downgrade get-releases get-results reinstall unlock update verify verify-update +set -l deviceid_consumers activate clear-results downgrade get-releases get-results get-updates reinstall switch-branch unlock update verify verify-update # complete device IDs complete -c fwupdmgr -n "__fish_seen_subcommand_from $deviceid_consumers" -x -a "(__fish_fwupdmgr_devices)" # complete files and device IDs diff -Nru fwupd-1.4.5/data/fwupd.shutdown.in fwupd-1.5.8/data/fwupd.shutdown.in --- fwupd-1.4.5/data/fwupd.shutdown.in 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/data/fwupd.shutdown.in 2021-03-31 20:08:32.000000000 +0000 @@ -4,4 +4,8 @@ [ -f @localstatedir@/lib/fwupd/pending.db ] || exit 0 # activate firmware when we have a read-only filesysten -@bindir@/fwupdtool activate +if !@bindir@/fwupdtool activate; then + ret=$? + [ "$ret" -eq "2" ] && exit 0 + exit $ret +fi diff -Nru fwupd-1.4.5/data/installed-tests/fakedevice123.bin fwupd-1.5.8/data/installed-tests/fakedevice123.bin --- fwupd-1.4.5/data/installed-tests/fakedevice123.bin 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/data/installed-tests/fakedevice123.bin 2021-03-31 20:08:32.000000000 +0000 @@ -1 +1 @@ -fakedevice123 -n +0x1020003 diff -Nru fwupd-1.4.5/data/installed-tests/fakedevice123.bin.asc fwupd-1.5.8/data/installed-tests/fakedevice123.bin.asc --- fwupd-1.4.5/data/installed-tests/fakedevice123.bin.asc 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/data/installed-tests/fakedevice123.bin.asc 2021-03-31 20:08:32.000000000 +0000 @@ -1,11 +1,11 @@ -----BEGIN PGP SIGNATURE----- -Version: GnuPG v2.0.14 (GNU/Linux) +Version: GnuPG v2.0.22 (GNU/Linux) -iQEcBAABAgAGBQJZQqynAAoJEEim2A5FOLrCVcsH/3Vn56wSeRCol0rOeXvoupg2 -qpTAmqUvlubv2vX1IDbcL/lHIIEAHAlN/4LRHUh+Om0T7bMKX1uSfmcgCyUTBxl0 -fm3TfXRhybi9VtZ5ZpwWxGsFsCNC9eOU0i8tB1zp9e9KjDPiYnluFkTRQ+Aw3u1u -tKBMTk6Z+VQlIUFrsveFYmPMGDkvn8AWbJCz6E4jc8can/lP/9djSi91mCqtEq/j -YTBz4OwfU80MRrSgoxykHgcB1RiT43ywfKlpHQzcO+rqCV7rv7LkXIEzBdWRZstk -XmboCnEKuMxtr+vXlGqU4n+upQkYur3Vs+07ut1OewQnJT3eeZbAH0mr42MVf7c= -=MQJe +iQEcBAABAgAGBQJfey1HAAoJEEim2A5FOLrCn2MIAK6BnVojGYSwHVpZm58b05Xs +rNqozg5pvfDfB0Bde1S0T/4TlDEnJNUku0Gz5IFNbR3ENT5VnJgBkE5xa8Rmv6cy +Gm30CmX+UE1E8qK4BVhUdbNN8bEmeMtzUMK2KfpwMXlIqcpSjpln76PQIxMHj+3P +600bkcppkLEKhiOo+THNhiHxPYJ+wjSSPm3paeMmUuApIvP4YFH8uQ5qkKLdLDVI +V5QOx3O5P3avmHu936GILG9EwV3TkR1eNOe33OqtrGvpoMTcsxUF0Wc/qmUD066d +c9hkTe01paQoN0HW/RMgrIaMnLFwK2mBcwySOo6TU9MIyQfDmLGN3u12nCrmRH8= +=Rq70 -----END PGP SIGNATURE----- diff -Nru fwupd-1.4.5/data/installed-tests/fakedevice123.metainfo.xml fwupd-1.5.8/data/installed-tests/fakedevice123.metainfo.xml --- fwupd-1.4.5/data/installed-tests/fakedevice123.metainfo.xml 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/data/installed-tests/fakedevice123.metainfo.xml 2021-03-31 20:08:32.000000000 +0000 @@ -1,8 +1,8 @@ - fakedevice.firmware - FakeDevice Firmware + org.fwupd.fakedevice.firmware + FakeDevice Firmware for the ACME Corp Integrated Webcam

    diff -Nru fwupd-1.4.5/data/installed-tests/fakedevice124.bin fwupd-1.5.8/data/installed-tests/fakedevice124.bin --- fwupd-1.4.5/data/installed-tests/fakedevice124.bin 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/data/installed-tests/fakedevice124.bin 2021-03-31 20:08:32.000000000 +0000 @@ -1 +1 @@ -fakedevice124 -n +0x1020004 diff -Nru fwupd-1.4.5/data/installed-tests/fakedevice124.bin.asc fwupd-1.5.8/data/installed-tests/fakedevice124.bin.asc --- fwupd-1.4.5/data/installed-tests/fakedevice124.bin.asc 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/data/installed-tests/fakedevice124.bin.asc 2021-03-31 20:08:32.000000000 +0000 @@ -1,11 +1,11 @@ -----BEGIN PGP SIGNATURE----- -Version: GnuPG v2.0.14 (GNU/Linux) +Version: GnuPG v2.0.22 (GNU/Linux) -iQEcBAABAgAGBQJZQqy9AAoJEEim2A5FOLrCRLEH/27k0IfUtfGS8T5CPTvwW8kF -Cf6EIzw+2HgjbxLdeMNHwiHCBdIR58z44O1I9Xy6gY1vF3H4kKft6oBAUFDH0Ja5 -YpQHXMZVSNdnwdg57cyC67kLOycHTSDlLXKB74tU3R4J8xntA1cY+DSYmCs2uAjq -3T3ExfjrX6PGbRhbNr8vBUQckCxcGvEZNOws2081mTosEQNpIxFyJ2tbbKLR60d0 -5O/UDjNEYfUFCGy7MycXePEIOR+rO6KuEQ3vjJnv80UKE8msFxJTM1iKwct+B2HI -JNecCsx14BGDXCiE0Xc0heunfWiBHmNS2lymrHsU2Z82VrFqP0obD2cm64PBf0Y= -=Wsq/ +iQEcBAABAgAGBQJfey2FAAoJEEim2A5FOLrCl88IAKCggwAz3qBrBfrc91sYHCq5 +OthMyftOUTQ4JpfISY38k20pwFEhsSHKdKAYDKEVO2jopw+Cr9oTyFycWK20R2lz +tUn4e1EF8zQ29OLxGbvgGlP5/4vPJ2Cv5ujkub6LtNBrOMkNJ6+bB6G8nJZRTElU +e3wi9+E9oKPBgP40A/y79pzPiFMxXl1piYjU3JNeofd3nbtmyRqb6VAs9exQ94+p +CMWWZaJ9igxSAsQiE/NxZpO8qgG3KEmsW7yXRiaIe6xHxb49+JQdjxqS8Oc/C9sX +FSiVHDPzlUegZtcRWZy2zeSNTqmu8vzNSei0xEaLCaQ6PO+pQibxS2VZI/jDLdQ= +=Gha4 -----END PGP SIGNATURE----- diff -Nru fwupd-1.4.5/data/installed-tests/fakedevice124.metainfo.xml fwupd-1.5.8/data/installed-tests/fakedevice124.metainfo.xml --- fwupd-1.4.5/data/installed-tests/fakedevice124.metainfo.xml 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/data/installed-tests/fakedevice124.metainfo.xml 2021-03-31 20:08:32.000000000 +0000 @@ -1,8 +1,8 @@ - fakedevice.firmware - FakeDevice Firmware + org.fwupd.fakedevice.firmware + FakeDevice

    Firmware for the ACME Corp Integrated Webcam

    diff -Nru fwupd-1.4.5/data/installed-tests/fwupdmgr.sh fwupd-1.5.8/data/installed-tests/fwupdmgr.sh --- fwupd-1.4.5/data/installed-tests/fwupdmgr.sh 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/data/installed-tests/fwupdmgr.sh 2021-03-31 20:08:32.000000000 +0000 @@ -1,7 +1,6 @@ #!/bin/bash exec 2>&1 -dirname=`dirname $0` device=08d460be0f1f9f128413f816022a6439e0078018 error() @@ -43,7 +42,7 @@ # --- echo "Installing test firmware..." -fwupdmgr install ${dirname}/fakedevice124.cab +fwupdmgr update $device -y rc=$?; if [[ $rc != 0 ]]; then error $rc; fi # --- @@ -56,9 +55,14 @@ fwupdmgr verify $device rc=$?; if [[ $rc != 0 ]]; then error $rc; fi +if [ -z "$CI_NETWORK" ]; then + echo "Skipping remaining tests due to CI_NETWORK not being set" + exit 0 +fi + # --- echo "Downgrading to older release (requires network access)" -fwupdmgr downgrade $device +fwupdmgr downgrade $device -y rc=$?; if [[ $rc != 0 ]]; then error $rc; fi # --- @@ -68,7 +72,7 @@ # --- echo "Updating all devices to latest release (requires network access)" -fwupdmgr --no-unreported-check --no-metadata-check --no-reboot-check update +fwupdmgr --no-unreported-check --no-metadata-check --no-reboot-check update -y rc=$?; if [[ $rc != 0 ]]; then error $rc; fi # --- diff -Nru fwupd-1.4.5/data/installed-tests/fwupd.sh fwupd-1.5.8/data/installed-tests/fwupd.sh --- fwupd-1.4.5/data/installed-tests/fwupd.sh 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/data/installed-tests/fwupd.sh 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,29 @@ +#!/bin/bash + +exec 2>&1 +dirname=`dirname $0` + +run_test() +{ + if [ -f $dirname/$1 ]; then + $dirname/$1 + rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi + fi +} + +run_test acpi-dmar-self-test +run_test acpi-facp-self-test +run_test ata-self-test +run_test nitrokey-self-test +run_test linux-swap-self-test +run_test nvme-self-test +run_test wacom-usb-self-test +run_test redfish-self-test +run_test optionrom-self-test +run_test vli-self-test +run_test uefi-dbx-self-test +run_test synaptics-prometheus-self-test +run_test dfu-self-test + +# success! +exit 0 diff -Nru fwupd-1.4.5/data/installed-tests/fwupd.test.in fwupd-1.5.8/data/installed-tests/fwupd.test.in --- fwupd-1.4.5/data/installed-tests/fwupd.test.in 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/data/installed-tests/fwupd.test.in 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,3 @@ +[Test] +Type=session +Exec=sh -c "@installedtestsbindir@/fwupd.sh" diff -Nru fwupd-1.4.5/data/installed-tests/meson.build fwupd-1.5.8/data/installed-tests/meson.build --- fwupd-1.4.5/data/installed-tests/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/data/installed-tests/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,7 +1,6 @@ -installed_test_datadir = join_paths(datadir, 'installed-tests', 'fwupd') - con2 = configuration_data() con2.set('installedtestsdir', installed_test_datadir) +con2.set('installedtestsbindir', installed_test_bindir) con2.set('bindir', bindir) configure_file( @@ -12,6 +11,14 @@ install_dir: installed_test_datadir, ) +configure_file( + input : 'fwupd.test.in', + output : 'fwupd.test', + configuration : con2, + install: true, + install_dir: installed_test_datadir, +) + install_data([ 'fwupdmgr.sh', 'fwupd-tests.xml', @@ -19,6 +26,12 @@ install_dir : installed_test_datadir, ) +install_data([ + 'fwupd.sh', + ], + install_dir : installed_test_bindir, +) + custom_target('installed-cab123', input : [ 'fakedevice123.bin', diff -Nru fwupd-1.4.5/data/installed-tests/README.md fwupd-1.5.8/data/installed-tests/README.md --- fwupd-1.4.5/data/installed-tests/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/data/installed-tests/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -9,7 +9,7 @@ Enabling ======= To enable the test suite: -1. Modify `/etc/fwupd/daemon.conf` to remove the `test` plugin from `BlacklistPlugins` +1. Modify `/etc/fwupd/daemon.conf` to remove the `test` plugin from `DisabledPlugins` ``` # sed "s,^Enabled=false,Enabled=true," -i /etc/fwupd/remotes.d/fwupd-tests.conf ``` diff -Nru fwupd-1.4.5/data/meson.build fwupd-1.5.8/data/meson.build --- fwupd-1.4.5/data/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/data/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -49,7 +49,7 @@ con2.set('localstatedir', localstatedir) con2.set('package_name', meson.project_name()) rw_directories = [] - if get_option('plugin_uefi') + if get_option('plugin_uefi_capsule') rw_directories += ['-/boot/efi', '-/efi/EFI', '-/boot/EFI'] endif diff -Nru fwupd-1.4.5/data/motd/fwupd-refresh.service.in fwupd-1.5.8/data/motd/fwupd-refresh.service.in --- fwupd-1.4.5/data/motd/fwupd-refresh.service.in 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/data/motd/fwupd-refresh.service.in 2021-03-31 20:08:32.000000000 +0000 @@ -14,4 +14,4 @@ ProtectControlGroups=yes RestrictRealtime=yes SuccessExitStatus=2 -ExecStart=@bindir@/fwupdmgr refresh --no-metadata-check +ExecStart=@bindir@/fwupdmgr refresh diff -Nru fwupd-1.4.5/data/org.freedesktop.fwupd.metainfo.xml fwupd-1.5.8/data/org.freedesktop.fwupd.metainfo.xml --- fwupd-1.4.5/data/org.freedesktop.fwupd.metainfo.xml 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/data/org.freedesktop.fwupd.metainfo.xml 2021-03-31 20:08:32.000000000 +0000 @@ -30,70 +30,263 @@ fwupdmgr + fwupdtool + fwupdtpmevlog + fwupdagent - +

    This release adds the following features:

      -
    • Add dual-image feature for VL103 backup firmware
    • -
    • Add more CCGX hybrid dock support
    • -
    • Add support for a delayed activation flow for Thunderbolt
    • -
    • Allow firmware to require specific features from front-end clients
    • -
    • Modernize the thunderbolt plugin for future hardware
    • -
    • Support LVFS::UpdateImage in GUI clients
    • +
    • Add a new internal flag to opt-in to GUID matching
    • +
    • Add D501 Baklava device support
    • +
    • Add fu_device_set_battery_level()
    • +
    • Add missing uint64 read and write helpers
    • +
    • Add Qubes wrapper source and create packages
    • +
    • Allow enabling plugins only matching a specific HwId
    • +
    • Prompt for unlock keypress if reset command is blocked
    • +
    • Remove obsolete dell-dock non-passive update flow support
    • +
    • Remove the Hughski public key
    • +
    • Show a warning when parsing invalid quirk files
    • +
    • Support for GATT characteristic signals/notifications
    • +
    • Support more than one protocol for a given device

    This release fixes the following bugs:

      -
    • Be more defensive when remotes are missing required keys
    • -
    • Check all AppStream components when verifying
    • -
    • Check for free space after cleaning up ESP
    • -
    • Fix TPM PCR0 calculation
    • -
    • Only show UpdateMessage when state is success
    • -
    • Read the modem vendor ID correctly
    • -
    • Set the runtime version to 0.0.0 for pre-1.0.0 Thelio Io firmware
    • -
    • Support compiling libqmi-glib 1.26.0 and later
    • -
    • Use the GPIOB reset for the MiniDock VL103
    • -
    • Wait for the root device to be replugged when updating the MSP430
    • +
    • Align the CCGX DMC firmware to 64 byte chunks
    • +
    • Be more strict for custom quirk keys
    • +
    • Check pixart firmware compatibility with hardware before flashing
    • +
    • Correct a thunderbolt assertion if kernel failed FW read
    • +
    • Correctly erase STM32 devices when transfer size is less than sector size
    • +
    • Detect SREC overflow to avoid adding ~4GB of 0xFF padding
    • +
    • Do not show a critical error when flashing footer-less binary files
    • +
    • Don't allow device updates while needing activation
    • +
    • Fix a regression in the elantp defined IAP start address
    • +
    • Fix a regression where activate stopped working
    • +
    • Fix firmware update of pointing device on Lenovo ThinkPad Nano
    • +
    • Fix the HSI plugin 'Disabled' state
    • +
    • Fix the quirk key name for the Lenovo HDMI with power
    • +
    • Fix writing to the GD32VF103 bootloader
    • +
    • Only call elantp->detach() when writing a firmware blob
    • +
    • Updated StarLabs GUIDs
    • +
    • Wait a few ms for the Logitech hardware to settle after detach
    - + -

    This release fixes the following regression:

    +

    This release adds the following features:

      -
    • Fix refreshing when checking for downgraded metadata
    • +
    • Add initial support for Bluez bluetooth devices
    • +
    • Add more supported pixart devices
    • +
    • Add support for the RTD21xx HDMI converter
    • +
    +

    This release fixes the following bugs:

    +
      +
    • Convert MBR types to GPT GUIDs to help find the ESP
    • +
    • Do not allow updating a synaptics-mst device with no customer ID
    • +
    • Drop unused heap pages after startup has completed
    • +
    • Ensure SBAT metadata is added correctly
    • +
    • Move the plugin build logic to the plugins themselves
    • +
    • Only allow verify-update for plugins that support CAN_VERIFY
    - +

    This release adds the following features:

      -
    • Add support for HP DMC dock devices
    • +
    • Add SBAT metadata to the fwupd EFI binary
    • +
    • Add support for GD32VF103 as found in the Longan Nano
    • +
    • Add support for RMI PS2 devices
    • +
    • Add support for the System76 Keyboard
    • +
    • Allow downloading firmware from IPFS
    • +
    • Install the UX data into a single .tar.xz file

    This release fixes the following bugs:

      -
    • Always enforce the metadata signature has a valid timestamp
    • -
    • Capture the dock SKU in metadata
    • -
    • Check the device requirements when returning from GetDetails
    • -
    • Force the prometheus minor version from 0x02 to 0x01
    • -
    • Prevent Dell dock updates to occur via synaptics-mst plugin
    • +
    • Add support for the Starlabs LabTop L4
    • +
    • Allow using an external ESP again
    • +
    • Ask the user to reboot when required if downgrading
    • +
    • Be more paranoid when parsing ASCII buffers and devices
    • +
    • Check if the fwupd BootXXXX entry exists on failure
    • +
    • Clear the pending flag if restarting the system
    • +
    • Do not allow flashing using flashrom if BLE is enabled
    • +
    • Do not allow Lenovo hardware to install multiple capsules
    • +
    • Do not parse the OptionROM image
    • +
    • Do not show Unknown [***] for every client connection
    • +
    • Fix dnload wBlockNum wraparound for ST devices
    • +
    • Fix OOM when using large ArchiveSizeMax values
    • +
    • Fix several crashes spotted by AddressSanitizer
    • +
    • Fix several places where the Goodix MOC plugin could crash
    • +
    • Include the PCR0 to the report metadata
    • +
    • Report the lockdown status from UEFI and SuperIO plugins
    • +
    • Show a console warning if the system clock is not set
    - + +

    This release adds the following features:

    +
      +
    • Add a plugin to update PixArt RF devices
    • +
    • Add new hardware to use the elantp and rts54hid plugins
    • +
    • Allow specifying more than one VendorID for a device
    • +
    • Detect the AMD TSME encryption state for HSI-4
    • +
    • Detect the AMI PK test key is not installed for HSI-1
    • +

    This release fixes the following bugs:

      -
    • Add several more ATA OUI quirks
    • -
    • Avoid communicating with DFU devices when bitManifestationTolerant is off
    • -
    • Correct the display of final calculated PCRs
    • -
    • Delay activation for Dell Thunderbolt updates
    • -
    • Do not use synaptics-rmi on the Dell K12A
    • -
    • Fix switching wacom-raw to bootloader mode
    • -
    • Switch the default of EnumerateAllDevices to false
    • -
    • Use GPIOB to reset the VL817 found in two Lenovo products
    • +
    • Fix flashing a fingerprint reader that is in use
    • +
    • Fix several critical warnings when parsing invalid firmware
    • +
    • Fix updating DFU devices that use DNLOAD_BUSY
    • +
    • Ignore the legacy UEFI OVMF dummy GUID
    • +
    • Make libfwupd more thread safe to fix a crash in gnome-software
    • +
    • Never show unprintable chars from invalid firmware in the logs
    • +
    +
    +
    + + +

    This release adds the following features:

    +
      +
    • Add Maple Ridge Thunderbolt firmware parsing support
    • +
    • Add --no-remote-check to ignore checking for download remotes
    • +
    • Allow creating FMAP and Synaptics firmware using builder.xml
    • +
    • Build a test harness that uses honggfuzz to fuzz firmware
    • +
    +

    This release fixes the following bugs:

    +
      +
    • Allow using fwupdtool as non-root for firmware commands
    • +
    • Do not trust the Block.HintSystem boolean for ESP filtering
    • +
    • Fix a memory leak when parsing Synaptics firmware
    • +
    • Fix a possible crash when reading the Goodix MOC USB request
    • +
    • Fix crashes when parsing invalid FMAP, DMC, Solokey and Synaptics images
    • +
    +
    +
    + + +

    This release adds the following features:

    +
      +
    • Allow setting the GMainContext when used for sync methods
    • +
    • Export the driver name from FuUdevDevice
    • +
    +

    This release fixes the following bugs:

    +
      +
    • Add a UEFI quirk for Star Labs Lite Mk III
    • +
    • Add the device firmare ID for serio class hardware
    • +
    • Allow the client to send legacy PKCS7 and GPG signatures
    • +
    • Do not use accidentally depend on new meson versions
    • +
    • Fix a possible critical warning due to missing retval
    • +
    • Fix the endianness for the CRC check in bcm57xx
    • +
    • Lower the CURL version required to fix RHEL
    • +
    • Make sure the correct interface number is used for QMI
    • +
    • Mark more user-visible strings as translatable
    • +
    • Restrict loading component types of firmware
    • +
    • Validate ModemManager firmware update method combinations
    • +
    +
    +
    + + +

    This release adds the following features:

    +
      +
    • Add a flag to indicate if packages are supported
    • +
    • Add a plugin for the Pinebook Pro laptop
    • +
    • Allow components to set the icon from the metadata
    • +
    • Switch from libsoup to libcurl for downloading data
    • +
    +

    This release fixes the following bugs:

    +
      +
    • Fall back to FAT32 internal partitions for detecting ESP
    • +
    • Fix detection of ColorHug version on older firmware versions
    • +
    • Fix reading BCM57XX vendor and device ids from firmware
    • +
    • Fix replugging the MSP430 device
    • +
    • Fix sync method when called from threads without a context
    • +
    • Ignore an invalid vendor-id when adding releases for display
    • +
    • Improve synaptics-mst reliability when writing data
    • +
    • Install modules-load configs in the correct directory
    • +
    • Notify the service manager when idle-quitting
    • +
    • Only download the remote metadata as required
    • +
    • Remove HSI update and attestation suffixes
    • +
    • Restore recognizing GPG and PKCS7 signature types in libfwupd
    • +
    • Set the SMBIOS chassis type to portable if a DT battery exists
    • +
    +
    +
    + + +

    This release adds the following features:

    +
      +
    • Include the amount of NVRAM size in use in the LVFS failure report
    • +
    +

    This release fixes the following bugs:

    +
      +
    • Delete unused EFI variables when deploying firmware
    • +
    • Fix probe warning for the Logitech Unifying device
    • +
    • Make bcm57xx hotplug more reliable
    • +
    • Recognize authorized thunderbolt value of 2
    • +
    • Remove the duplicate parent-child data in FwupdDevice and FuDevice
    • +
    • Show a less scary fwupdate output for devices without info
    • +
    • Show a link to discover more information about a specific plugin failure
    • +
    • Use a different Device ID for the OptionROM devices
    • +
    • Use UDisks to find out if swap devices are encrypted
    • +
    +
    +
    + + +

    This release adds the following features:

    +
      +
    • Add a compatible re-implementation of the rhboot dbxtool
    • +
    • Add async versions of the library for GUI tools
    • +
    • Add commands for interacting with the ESP to fwupdtool
    • +
    • Add firmware-extract subcommand to fwupdtool
    • +
    • Add FwupdPlugin so we can convey enumerated system errors to the end user
    • +
    • Add plugin for Goodix fingerprint sensors
    • +
    • Add plugin that can update the BCM5719 network adapter
    • +
    • Add plugin to update Elan Touchpads using HID
    • +
    • Add support for a delayed activation flow for Thunderbolt
    • +
    • Add support for ChromeOS Quiche and Gingerbread
    • +
    • Add support for Hyper hardware
    • +
    • Add support for the Host Security ID
    • +
    • Add support for ThunderBolt retimers
    • +
    • Add switch-branch command to fwupdtool and fwupdmgr
    • +
    • Allow blocking specific firmware releases by checksum
    • +
    • Allow constructing a firmware with multiple images
    • +
    • Allow firmware to require specific features from front-end clients
    • +
    • Allow updating the dbx using the LVFS, validating it is safe to apply
    • +
    • Include the HSI results and attributes in the uploaded report
    • +
    • Support loading DMI data from DT systems
    • +
    • Support LVFS::UpdateImage for GUI clients
    • +
    +

    This release fixes the following bugs:

    +
      +
    • Allow compiling the daemon without polkit support
    • +
    • Always look at all TPM eventlog supported algorithms
    • +
    • Change all instances of master/slave to initiator/target
    • +
    • Correctly order devices when using logical parents
    • +
    • Do not dedupe NVMe or VLI PD devices
    • +
    • Do not expose the VLI shared-SPI devices on the USB2 recovery device
    • +
    • Do not fix up the version on post-update mismatch
    • +
    • Download the metadata first when using 'fwupdtool refresh'
    • +
    • Drop efivar dependency
    • +
    • Drop support for ThunderBolt force power due to hardware issues
    • +
    • Fix setting BootNext correctly when multiple updates are scheduled
    • +
    • Fix the topology of the audio device on the Lenovo TR dock
    • +
    • Make return code different for get-updates with no updates
    • +
    • Make specific authorizations also imply others
    • +
    • Make TPM support more optional
    • +
    • Parse the HEX version before comparing for equality
    • +
    • Prevent dell-dock updates to occur via synaptics-mst plugin
    • +
    • Record the UEFI failure in more cases
    • +
    • Retry the HID SetReport to fix flashing the TB3 dock
    • +
    • Show an error when a plugin is missing dependencies
    • +
    • Use libxmlb bound parameters to speed up the device verification
    • +
    • Use pkttyagent to request user passwords if running without GUI
    • +
    • Use the JCat file to select the metadata file
    @@ -168,6 +361,32 @@
    + + +

    This release adds the following features:

    +
      +
    • Added completion script for fish shell
    • +
    • Inihbit all power management actions using logind when updating
    • +
    +

    This release fixes the following bugs:

    +
      +
    • Always check for PLAIN when doing vercmp() operations
    • +
    • Always return AppStream markup for remote agreements
    • +
    • Apply UEFI capsule update even with single valid capsule
    • +
    • Check the device protocol before de-duping devices
    • +
    • Copy the version and format from donor device in get-details
    • +
    • Correctly append the release to devices in `fwupdtool get-details`
    • +
    • Decrease minimum battery requirement to 10%
    • +
    • Discard the reason upgrades aren't available
    • +
    • Do not fail loading in /etc/machine-id is not available
    • +
    • Fix a critical warning when installing some firmware
    • +
    • For the `get-details` command make sure to always show devices
    • +
    • Set the MSP430 version format to pair
    • +
    • Switch off the ATA verbose logging by default
    • +
    • Use unknown for version format by default on get-details
    • +
    +
    +

    This release adds the following features:

    @@ -486,7 +705,7 @@
  • Do not fail to start the daemon if tpm2_pcrlist hangs
  • Do not fail when scheduling more than one update to be run offline
  • Do not let failing to find DBus prevent fwuptool from starting
  • -
  • Do not schedule an update on battery power if it requires AC power
  • +
  • Do not schedule an update on battery power if it requires an external power source
  • Include all device checksums in the LVFS report
  • Rename the shimx64.efi binary for known broken firmware
  • Upload the UPDATE_INFO entry for the UEFI UX capsule
  • diff -Nru fwupd-1.4.5/data/pki/GPG-KEY-Hughski-Limited fwupd-1.5.8/data/pki/GPG-KEY-Hughski-Limited --- fwupd-1.4.5/data/pki/GPG-KEY-Hughski-Limited 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/data/pki/GPG-KEY-Hughski-Limited 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- -Version: GnuPG v1 - -mQENBFUr0UoBCACsdOLuTJ81dICrSvUhyznBsL4WgEa2RUbEjJuaXwrEyPMikHE1 -Clda2YI7VbpCgIVq8Zy63CGJ4Xqs2T6pyetaXnbX8J0C+7wg2IfPv7pUyCsP7/JR -HRB2GNelCWrsGArN1cOPI0ESH4yHWKF9KCGlpsLfSHmvF7D8vcKlKQUlO4T6lxOP -SNjMSXkMsxfDDhl1mzqrwxfU4V6nnPcuMwU7tvg+39PioP4Ny1tKP4SSpBfh7qwz -XXRd505dqNLOubxmOPZ5rznVkKmW2cwahO6fr5zVA8/2TDZQ79mdbfvSJVlW06qs -C5PYmLnBjyzE5uQ4oxSIuUEiMfqrn3Qs6PhhABEBAAG0Ikh1Z2hza2kgTGltaXRl -ZCA8aW5mb0BodWdoc2tpLmNvbT6JATgEEwECACIFAlUr0UoCGwMGCwkIBwMCBhUI -AgkKCwQWAgMBAh4BAheAAAoJEK2KUo/sRIge/fUH/Rblgzh5GeB0Zp2U9W+r26iJ -t1AD5a/fKxQahz/pwMkevQCCMzI1vpX12P3HtACZOD3Zjh9RXY6Z3033YZjrRApe -FkOVfcyUF1nP/z2Ox3jE3+B8v1u0UzH/MqtF/1095mqvR7gllE288KDqu7bvd5l3 -z4IETk5qqoeCe9LYc8aob973dbocyS/gou/FLCKxoXVEe8DPRwv8qmXlXOujxdxd -FcslpYqtjj4fgUswQ/cY/a1UcAX5zCnVqFbU7oJH2uTNewKuaZ2wgPbnzvwx8JYl -VfFdPN7GZ0NMrZDLeJ0SLXer/9+qAKNH4UpQS9axXQL+VKOzsZCXuv31VDCj5Jy5 -AQ0EVSvRSgEIAMgVrZP3LmA9bx7B8l+agVh5DNXrMixX9jhZ0Yfn8+UIMMNTZziD -ZV3nXxswKPrcsqQ+KP9iUwq3V2oio46bvHiMMoZSGCaTv4yiKOliFOMYr9NAOSTZ -8mOI24dNXI9XqQ7ZA8m4uKmgHZQUIUUlx693uRI2Wmk/Y5XEBoL2+XdA5KalO+36 -27YXpdyU3GiMCOtSBLWNfBxXw6oKdNUp+8o/fYrmQnBxuGgmVlcZEmjhrIGXaCH1 -iDeWIFqaM/S+DXMF3bgqvqRZq1U2RwT2oxapAuaG/0I5JaKKpb3HqMCXfOUxpFPk -zgUYpHatUcePG/94K8N8CRjnJ+l83H5PewcAEQEAAYkBHwQYAQIACQUCVSvRSgIb -DAAKCRCtilKP7ESIHrrcCACc6UTZzVGbVq9pXSz2Bw2xQpAEAhnnedPgfXwEJMM0 -24bMUNsyJcQZAW1d5KfJYNAihOfse3oDQ/hJAycTK3GAHsPfljEQjWGn27eC8Fxu -mHpfNpxbTirChfepCNctZG818Hp2v+K4X/PjyQMQ6J5H9oinnlasVQ6wzdZifnWm -7E5OL0NV/ni9xqq4fC5y5qxNBeYVmHUF4H0E3VOuCbESAOnUDpCo998Dc68eZEmV -f3IMukvvnxM9VOZQSnp7J/kkhPB5fim2z2qrlJK9N+tBjAMugxtnAV2fIaZYTiba -SnN2hheFd9Y0nMmWbwRqFtwMG1m/tS3JlD52Rpwzk59B -=WFoi ------END PGP PUBLIC KEY BLOCK----- diff -Nru fwupd-1.4.5/data/pki/meson.build fwupd-1.5.8/data/pki/meson.build --- fwupd-1.4.5/data/pki/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/data/pki/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,4 @@ install_data([ - 'GPG-KEY-Hughski-Limited', 'GPG-KEY-Linux-Foundation-Firmware', 'GPG-KEY-Linux-Vendor-Firmware-Service', ], diff -Nru fwupd-1.4.5/data/remotes.d/lvfs.conf fwupd-1.5.8/data/remotes.d/lvfs.conf --- fwupd-1.4.5/data/remotes.d/lvfs.conf 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/data/remotes.d/lvfs.conf 2021-03-31 20:08:32.000000000 +0000 @@ -5,6 +5,8 @@ Title=Linux Vendor Firmware Service MetadataURI=https://cdn.fwupd.org/downloads/firmware.xml.gz ReportURI=https://fwupd.org/lvfs/firmware/report +SecurityReportURI=https://fwupd.org/lvfs/hsireports/upload OrderBefore=fwupd AutomaticReports=false +AutomaticSecurityReports=false ApprovalRequired=false diff -Nru fwupd-1.4.5/data/tests/daemon.conf fwupd-1.5.8/data/tests/daemon.conf --- fwupd-1.4.5/data/tests/daemon.conf 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/data/tests/daemon.conf 2021-03-31 20:08:32.000000000 +0000 @@ -1,12 +1,12 @@ [fwupd] -# Allow blacklisting specific devices by their GUID +# Allow blocking specific devices by their GUID # Uses semicolons as delimiter -BlacklistDevices= +DisabledDevices= -# Allow blacklisting specific plugins +# Allow blocking specific plugins # Uses semicolons as delimiter -BlacklistPlugins=test;invalid +DisabledPlugins=test;test_ble;invalid # Maximum archive size that can be loaded in Mb, with 0 for the default ArchiveSizeMax=0 @@ -32,3 +32,13 @@ # A list of firmware checksums that has been approved by the site admin # If unset, all firmware is approved ApprovedFirmware= + +# Allow blocking specific devices by their checksum, either SHA1 or SHA256 +# Uses semicolons as delimiter +BlockedFirmware= + +# Allowed URI schemes in the preference order; failed downloads from the first +# scheme will be retried with the next in order until no choices remain. +# +# If unset or no schemes are listed, the default will be: file,https,http,ipfs +UriSchemes= diff -Nru fwupd-1.4.5/data/tests/devicetree/base/ibm,firmware-versions/version fwupd-1.5.8/data/tests/devicetree/base/ibm,firmware-versions/version --- fwupd-1.4.5/data/tests/devicetree/base/ibm,firmware-versions/version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/data/tests/devicetree/base/ibm,firmware-versions/version 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +1.2.3-4 \ No newline at end of file diff -Nru fwupd-1.4.5/data/tests/devicetree/base/model fwupd-1.5.8/data/tests/devicetree/base/model --- fwupd-1.4.5/data/tests/devicetree/base/model 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/data/tests/devicetree/base/model 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +ColorHug \ No newline at end of file diff -Nru fwupd-1.4.5/data/tests/devicetree/base/model-name fwupd-1.5.8/data/tests/devicetree/base/model-name --- fwupd-1.4.5/data/tests/devicetree/base/model-name 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/data/tests/devicetree/base/model-name 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +To Be Filled By O.E.M. \ No newline at end of file Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/data/tests/devicetree/base/name and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/data/tests/devicetree/base/name differ diff -Nru fwupd-1.4.5/data/tests/devicetree/base/vendor fwupd-1.5.8/data/tests/devicetree/base/vendor --- fwupd-1.4.5/data/tests/devicetree/base/vendor 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/data/tests/devicetree/base/vendor 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +Hughski Limited \ No newline at end of file Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/data/tests/devicetree/base/vpd/name and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/data/tests/devicetree/base/vpd/name differ Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/data/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/name and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/data/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/name differ diff -Nru fwupd-1.4.5/data/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/part-number fwupd-1.5.8/data/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/part-number --- fwupd-1.4.5/data/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/part-number 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/data/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/part-number 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +PCB-CH001 \ No newline at end of file diff -Nru fwupd-1.4.5/data/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/vendor fwupd-1.5.8/data/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/vendor --- fwupd-1.4.5/data/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/vendor 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/data/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/vendor 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +Richard Hughes \ No newline at end of file Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/data/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/name and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/data/tests/devicetree/base/vpd/root-node-vpd@a000/enclosure@1e00/name differ Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/data/tests/devicetree/base/vpd/root-node-vpd@a000/name and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/data/tests/devicetree/base/vpd/root-node-vpd@a000/name differ diff -Nru fwupd-1.4.5/data/tests/firmware-base-uri.conf fwupd-1.5.8/data/tests/firmware-base-uri.conf --- fwupd-1.4.5/data/tests/firmware-base-uri.conf 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/data/tests/firmware-base-uri.conf 2021-03-31 20:08:32.000000000 +0000 @@ -1,6 +1,6 @@ [fwupd Remote] Enabled=true Type=download -Keyring=gpg +Keyring=jcat MetadataURI=https://s3.amazonaws.com/lvfsbucket/downloads/firmware.xml.gz FirmwareBaseURI=https://my.fancy.cdn/ Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/data/tests/firmware.dfuse and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/data/tests/firmware.dfuse differ Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/data/tests/firmware.fmap and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/data/tests/firmware.fmap differ diff -Nru fwupd-1.4.5/data/tests/firmware-nopath.conf fwupd-1.5.8/data/tests/firmware-nopath.conf --- fwupd-1.4.5/data/tests/firmware-nopath.conf 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/data/tests/firmware-nopath.conf 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ [fwupd Remote] Enabled=true Type=download -Keyring=gpg +Keyring=jcat MetadataURI=https://s3.amazonaws.com/lvfsbucket/downloads/firmware.xml.gz diff -Nru fwupd-1.4.5/data/tests/multiple-rels/firmware.metainfo.xml fwupd-1.5.8/data/tests/multiple-rels/firmware.metainfo.xml --- fwupd-1.4.5/data/tests/multiple-rels/firmware.metainfo.xml 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/data/tests/multiple-rels/firmware.metainfo.xml 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ - + com.hughski.test.firmware diff -Nru fwupd-1.4.5/data/tests/quirks.d/tests.quirk fwupd-1.5.8/data/tests/quirks.d/tests.quirk --- fwupd-1.4.5/data/tests/quirks.d/tests.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/data/tests/quirks.d/tests.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -2,16 +2,16 @@ Flags= ignore-runtime [ACME Inc.=True] -Test = awesome +Name = awesome [CORP*] -Test = town +Name = town -[DeviceInstanceId=USB\VID_0BDA&PID_1100] +[USB\VID_0BDA&PID_1100] Flags = clever Name = Hub Children = FuDevice|USB\VID_0763&PID_2806&I2C_01 -[DeviceInstanceId=USB\VID_0763&PID_2806&I2C_01] +[USB\VID_0763&PID_2806&I2C_01] Name = HDMI Flags = updatable,internal diff -Nru fwupd-1.4.5/debian/changelog fwupd-1.5.8/debian/changelog --- fwupd-1.4.5/debian/changelog 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/debian/changelog 2021-03-31 20:08:32.000000000 +0000 @@ -1,6 +1,6 @@ -fwupd (1.4.5-1pop0~1611677200~21.04~aaada71~dev) hirsute; urgency=medium +fwupd (1.5.8-0ubuntu1pop0~1617221312~21.04~a9de48d~dev) hirsute; urgency=medium * Auto Build - -- Pop OS (ISO Signing Key) Tue, 26 Jan 2021 09:06:40 -0700 + -- Pop OS (ISO Signing Key) Wed, 31 Mar 2021 14:08:32 -0600 diff -Nru fwupd-1.4.5/debian/control fwupd-1.5.8/debian/control --- fwupd-1.4.5/debian/control 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/debian/control 2021-03-31 20:08:32.000000000 +0000 @@ -23,6 +23,7 @@ libarchive-dev, libcairo-dev, libcairo-gobject2, + libcurl4-gnutls-dev, libefiboot-dev [amd64 arm64 armhf i386], libefivar-dev [amd64 arm64 armhf i386], libelf-dev, @@ -32,15 +33,15 @@ libgirepository1.0-dev, libglib2.0-dev (>= 2.45.8), libgudev-1.0-dev, - libgusb-dev (>= 0.2.9), + libgusb-dev (>= 0.3.4), libjcat-dev, libjson-glib-dev (>= 1.1.1), libmm-glib-dev, libpolkit-gobject-1-dev, libqmi-glib-dev, libsmbios-dev [i386 amd64], - libsoup2.4-dev, libsqlite3-dev, + libsystemd-dev, libtool-bin, libtss2-dev, libxmlb-dev (>= 0.1.13), @@ -102,7 +103,11 @@ shared-mime-info Recommends: python3, bolt, + dbus, + secureboot-db, + udisks2, fwupd-signed +Suggests: gir1.2-fwupd-2.0 Provides: fwupdate Conflicts: fwupdate-amd64-signed, fwupdate-i386-signed, @@ -110,6 +115,7 @@ fwupdate-armhf-signed Breaks: gir1.2-dfu-1.0 (<< 0.9.7-1), libdfu1 (<< 0.9.7-1), + fwupdate (<< 12-7), libdfu-dev (<< 0.9.7-1) Replaces: gir1.2-dfu-1.0 (<< 0.9.7-1), libdfu1 (<< 0.9.7-1), @@ -168,6 +174,10 @@ Multi-Arch: same Depends: libfwupd2 (= ${binary:Version}), gir1.2-fwupd-2.0 (= ${binary:Version}), + libcurl4-gnutls-dev, + libglib2.0-dev (>= 2.45.8), + libjcat-dev, + libjson-glib-dev (>= 1.1.1), ${misc:Depends} Breaks: fwupd-dev (<< 0.5.4-2~) Replaces: fwupd-dev (<< 0.5.4-2~) @@ -198,6 +208,17 @@ Multi-Arch: same Depends: libfwupdplugin1 (= ${binary:Version}), gir1.2-fwupdplugin-1.0 (= ${binary:Version}), + libarchive-dev, + libcurl4-gnutls-dev, + libfwupd-dev (= ${binary:Version}), + libgcab-dev, + libglib2.0-dev (>= 2.45.8), + libgudev-1.0-dev, + libgusb-dev (>= 0.3.5), + libjcat-dev, + libjson-glib-dev (>= 1.1.1), + libxmlb-dev (>= 0.1.13), + valgrind [!ia64 !riscv64 !x32 !mips !sparc64 !sh4 !ppc64 !powerpcspe !hppa !alpha !mips64el !armhf !armel !mipsel !m68k], ${misc:Depends} Section: libdevel Description: development files for libfwupdplugin diff -Nru fwupd-1.4.5/debian/control.in fwupd-1.5.8/debian/control.in --- fwupd-1.4.5/debian/control.in 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/debian/control.in 2021-03-31 20:08:32.000000000 +0000 @@ -49,7 +49,11 @@ shared-mime-info Recommends: python3, bolt, + dbus, + secureboot-db, + udisks2, fwupd-signed +Suggests: gir1.2-fwupd-2.0 Provides: fwupdate Conflicts: fwupdate-amd64-signed, fwupdate-i386-signed, @@ -57,6 +61,7 @@ fwupdate-armhf-signed Breaks: gir1.2-dfu-1.0 (<< 0.9.7-1), libdfu1 (<< 0.9.7-1), + fwupdate (<< 12-7), libdfu-dev (<< 0.9.7-1) Replaces: gir1.2-dfu-1.0 (<< 0.9.7-1), libdfu1 (<< 0.9.7-1), @@ -115,6 +120,10 @@ Multi-Arch: same Depends: libfwupd2 (= ${binary:Version}), gir1.2-fwupd-2.0 (= ${binary:Version}), + libcurl4-gnutls-dev, + libglib2.0-dev (>= 2.45.8), + libjcat-dev, + libjson-glib-dev (>= 1.1.1), ${misc:Depends} Breaks: fwupd-dev (<< 0.5.4-2~) Replaces: fwupd-dev (<< 0.5.4-2~) @@ -145,6 +154,17 @@ Multi-Arch: same Depends: libfwupdplugin1 (= ${binary:Version}), gir1.2-fwupdplugin-1.0 (= ${binary:Version}), + libarchive-dev, + libcurl4-gnutls-dev, + libfwupd-dev (= ${binary:Version}), + libgcab-dev, + libglib2.0-dev (>= 2.45.8), + libgudev-1.0-dev, + libgusb-dev (>= 0.3.5), + libjcat-dev, + libjson-glib-dev (>= 1.1.1), + libxmlb-dev (>= 0.1.13), + valgrind [!ia64 !riscv64 !x32 !mips !sparc64 !sh4 !ppc64 !powerpcspe !hppa !alpha !mips64el !armhf !armel !mipsel !m68k], ${misc:Depends} Section: libdevel Description: development files for libfwupdplugin diff -Nru fwupd-1.4.5/debian/copyright fwupd-1.5.8/debian/copyright --- fwupd-1.4.5/debian/copyright 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/debian/copyright 2021-03-31 20:08:32.000000000 +0000 @@ -3,32 +3,47 @@ Source: https://github.com/fwupd/fwupd Files: * -Copyright: 9elements Agency GmbH +Copyright: + 9elements Agency GmbH + Aleix Pol Aleksander Morgado Andrew Duggan + Benson Leung Christian J. Kellner Cypress Semiconductor Corporation. Dell Inc. Dell, Inc. + Evan Lojewski Fresco Logic Google, Inc. + H.J. Lu Intel Corporation. Intel, Inc. + Javier Martinez Canillas Jeremy Soller + Jimmy Yu Kalev Lember + Lennart Poettering Mario Limonciello - Max Ehrlich max.ehr@gmail.com + Matthias Klumpp + Max Ehrlich maxehr@gmail.com Peichen Huang Peter Jones + Philip Withnall + Philip Withnall + Realtek Corporation Realtek Semiconductor Corporation Red Hat, Inc. + Ricardo Cañuelo Richard Hughes + Ricky Wu Ryan Chang Synaptics Synaptics Inc Synaptics Inc. Synaptics Incorporated VIA Corporation + boger wang License: LGPL-2.1+ Files: *.metainfo.xml @@ -37,7 +52,7 @@ Files: debian/* Copyright: 2015 Daniel Jared Dominguez - 2015-2018 Mario Limonciello + 2015 Mario Limonciello License: LGPL-2.1+ License: LGPL-2.1+ diff -Nru fwupd-1.4.5/debian/copyright.in fwupd-1.5.8/debian/copyright.in --- fwupd-1.4.5/debian/copyright.in 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/debian/copyright.in 2021-03-31 20:08:32.000000000 +0000 @@ -9,7 +9,7 @@ Files: debian/* Copyright: 2015 Daniel Jared Dominguez - 2015-2018 Mario Limonciello + 2015 Mario Limonciello License: LGPL-2.1+ License: LGPL-2.1+ diff -Nru fwupd-1.4.5/debian/fwupd.install fwupd-1.5.8/debian/fwupd.install --- fwupd-1.4.5/debian/fwupd.install 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/debian/fwupd.install 2021-03-31 20:08:32.000000000 +0000 @@ -8,8 +8,7 @@ usr/share/polkit-1/* usr/share/locale usr/share/metainfo/* -usr/libexec/fwupd/fwupd -usr/libexec/fwupd/fwupdoffline +usr/libexec/fwupd/* usr/share/man/man1/* lib/systemd/system/* lib/systemd/system-preset/* diff -Nru fwupd-1.4.5/debian/fwupd.maintscript fwupd-1.5.8/debian/fwupd.maintscript --- fwupd-1.4.5/debian/fwupd.maintscript 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/debian/fwupd.maintscript 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,6 @@ + +rm_conffile /etc/fwupd.conf 1.0.0~ +rm_conffile /etc/fwupd/remotes.d/fwupd.conf 1.2.7~ +rm_conffile /etc/dbus-1/system.d/org.freedesktop.fwupd.conf 1.3.2~ +rm_conffile /etc/modules-load.d/fwupd-msr.conf 1.5.3~ +rm_conffile /etc/modules-load.d/fwupd-platform-integrity.conf 1.5.3~ diff -Nru fwupd-1.4.5/debian/fwupd.postinst fwupd-1.5.8/debian/fwupd.postinst --- fwupd-1.4.5/debian/fwupd.postinst 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/debian/fwupd.postinst 2021-03-31 20:08:32.000000000 +0000 @@ -8,13 +8,29 @@ /etc/fwupd.conf 1.0.0~ -- "$@" dpkg-maintscript-helper rm_conffile \ /etc/fwupd/remotes.d/fwupd.conf 1.2.7~ -- "$@" - dpkg-maintscript-helper rm_conffile \ - /etc/dbus-1/system.d/org.freedesktop.fwupd.conf 1.3.2~ -- "$@" + dpkg-maintscript-helper rm_conffile \ + /etc/dbus-1/system.d/org.freedesktop.fwupd.conf 1.3.2~ -- "$@" + dpkg-maintscript-helper rm_conffile \ + /etc/fwupd/ata.conf 1.5.5~ -- "$@" +fi + +#Perform transition from /etc/fwupd/uefi.conf to /etc/fwupd/uefi_capsule.conf +if dpkg-maintscript-helper supports mv_conffile 2>/dev/null; then + ORIGINAL=/etc/fwupd/uefi.conf + NEW=/etc/fwupd/uefi_capsule.conf + #If already upgraded this file won't exist + #If in the middle of an upgrade: + # -> If unmodified then preinst would have renamed to /etc/fwupd/uefi.conf.dpkg-remove + # -> If modified, we need to do an in-place upgrade with sed + if [ -f $ORIGINAL ]; then + sed "s,\[uefi\],\[uefi_capsule\]," -i $ORIGINAL + fi + dpkg-maintscript-helper mv_conffile $ORIGINAL $NEW 1.5.5~ -- "$@" fi # Clean up from fwupdate->fwupd transition # This can be removed after bullseye and focal are released -EFIDIR=$(dpkg-vendor --query vendor | awk '{ print tolower($$0) }') +EFIDIR=$(awk '/^ID=/ {gsub(/"/,""); split($$0,a,"="); print tolower(a[2])}' /etc/os-release) if [ "${DPKG_MAINTSCRIPT_ARCH}" = "amd64" ]; then EFI_NAME=x64 elif [ "${DPKG_MAINTSCRIPT_ARCH}" = "i386" ]; then diff -Nru fwupd-1.4.5/debian/fwupd.postrm fwupd-1.5.8/debian/fwupd.postrm --- fwupd-1.4.5/debian/fwupd.postrm 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/debian/fwupd.postrm 2021-03-31 20:08:32.000000000 +0000 @@ -15,4 +15,13 @@ /etc/fwupd/remotes.d/fwupd.conf 1.2.7~ -- "$@" dpkg-maintscript-helper rm_conffile \ /etc/dbus-1/system.d/org.freedesktop.fwupd.conf 1.3.2~ -- "$@" + dpkg-maintscript-helper rm_conffile \ + /etc/fwupd/ata.conf 1.5.5~ -- "$@" +fi + +#Perform transition from /etc/fwupd/uefi.conf to /etc/fwupd/uefi_capsule.conf +if dpkg-maintscript-helper supports mv_conffile 2>/dev/null; then + ORIGINAL=/etc/fwupd/uefi.conf + NEW=/etc/fwupd/uefi_capsule.conf + dpkg-maintscript-helper mv_conffile $ORIGINAL $NEW 1.5.5~ -- "$@" fi diff -Nru fwupd-1.4.5/debian/fwupd.preinst fwupd-1.5.8/debian/fwupd.preinst --- fwupd-1.4.5/debian/fwupd.preinst 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/debian/fwupd.preinst 2021-03-31 20:08:32.000000000 +0000 @@ -6,10 +6,19 @@ if dpkg-maintscript-helper supports rm_conffile 2>/dev/null; then dpkg-maintscript-helper rm_conffile \ /etc/fwupd.conf 1.0.0~ -- "$@" - dpkg-maintscript-helper rm_conffile \ - /etc/fwupd/remotes.d/fwupd.conf 1.2.7~ -- "$@" - dpkg-maintscript-helper rm_conffile \ - /etc/dbus-1/system.d/org.freedesktop.fwupd.conf 1.3.2~ -- "$@" + dpkg-maintscript-helper rm_conffile \ + /etc/fwupd/remotes.d/fwupd.conf 1.2.7~ -- "$@" + dpkg-maintscript-helper rm_conffile \ + /etc/dbus-1/system.d/org.freedesktop.fwupd.conf 1.3.2~ -- "$@" + dpkg-maintscript-helper rm_conffile \ + /etc/fwupd/ata.conf 1.5.5~ -- "$@" +fi + +#Perform transition from /etc/fwupd/uefi.conf to /etc/fwupd/uefi_capsule.conf +if dpkg-maintscript-helper supports mv_conffile 2>/dev/null; then + ORIGINAL=/etc/fwupd/uefi.conf + NEW=/etc/fwupd/uefi_capsule.conf + dpkg-maintscript-helper mv_conffile $ORIGINAL $NEW 1.5.5~ -- "$@" fi # 1.3.2 had fwupd-refresh.service and fwupd.service both claiming diff -Nru fwupd-1.4.5/debian/fwupd-tests.install fwupd-1.5.8/debian/fwupd-tests.install --- fwupd-1.4.5/debian/fwupd-tests.install 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/debian/fwupd-tests.install 2021-03-31 20:08:32.000000000 +0000 @@ -3,6 +3,8 @@ #find them. for more information see: #https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=872458 usr/share/installed-tests/* +usr/libexec/installed-tests/fwupd/fwupd.sh +usr/libexec/installed-tests/fwupd/*-self-test usr/lib/*/fwupd-plugins-3/libfu_plugin_test.so usr/lib/*/fwupd-plugins-3/libfu_plugin_invalid.so debian/lintian/fwupd-tests usr/share/lintian/overrides diff -Nru fwupd-1.4.5/debian/fwupd-tests.postinst fwupd-1.5.8/debian/fwupd-tests.postinst --- fwupd-1.4.5/debian/fwupd-tests.postinst 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/debian/fwupd-tests.postinst 2021-03-31 20:08:32.000000000 +0000 @@ -7,7 +7,7 @@ if [ "$1" = configure ] && [ -z "$2" ]; then if [ -f /etc/fwupd/daemon.conf ]; then if [ "$CI" = "true" ]; then - sed "s,^BlacklistPlugins=test;invalid,BlacklistPlugins=," -i /etc/fwupd/daemon.conf + sed "s,^DisabledPlugins=.*,DisabledPlugins=," -i /etc/fwupd/daemon.conf else echo "To enable test suite, modify /etc/fwupd/daemon.conf" fi diff -Nru fwupd-1.4.5/debian/fwupd-tests.postrm fwupd-1.5.8/debian/fwupd-tests.postrm --- fwupd-1.4.5/debian/fwupd-tests.postrm 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/debian/fwupd-tests.postrm 2021-03-31 20:08:32.000000000 +0000 @@ -6,7 +6,7 @@ if [ "$1" = remove -o "$1" = purge ]; then if [ -f /etc/fwupd/daemon.conf ]; then if [ "$CI" = "true" ]; then - sed "s,^BlacklistPlugins=,BlacklistPlugins=test;invalid," -i /etc/fwupd/daemon.conf + sed "s,^DisabledPlugins=,DisabledPlugins=test;invalid," -i /etc/fwupd/daemon.conf else echo "To disable test suite, modify /etc/fwupd/daemon.conf" fi diff -Nru fwupd-1.4.5/debian/.gitignore fwupd-1.5.8/debian/.gitignore --- fwupd-1.4.5/debian/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/debian/.gitignore 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,39 @@ +.debhelper/ +debhelper-build-stamp +fwupd-amd64-signed-template.debhelper.log +fwupd-amd64-signed-template/ +fwupd-doc.debhelper.log +fwupd-doc/ +fwupd-tests.debhelper.log +fwupd-tests/ +fwupd.debhelper.log +fwupd.postrm.debhelper +fwupd/ +gir1.2-fwupd-2.0.debhelper.log +gir1.2-fwupd-2.0/ +gir1.2-fwupdplugin-1.0.debhelper.log +gir1.2-fwupdplugin-1.0/ +libfwupd-dev.debhelper.log +libfwupd-dev/ +libfwupd2.debhelper.log +libfwupd2.substvars +libfwupd2/ +libfwupdplugin-dev.debhelper.log +libfwupdplugin-dev/ +libfwupdplugin1.debhelper.log +libfwupdplugin1.substvars +libfwupdplugin1/ +tmp/ +files +fwupd-amd64-signed-template.substvars +fwupd-doc.substvars +fwupd-images/ +fwupd-tests.substvars +fwupd.postinst.debhelper +fwupd.preinst.debhelper +fwupd.prerm.debhelper +fwupd.substvars +gir1.2-fwupd-2.0.substvars +gir1.2-fwupdplugin-1.0.substvars +libfwupd-dev.substvars +libfwupdplugin-dev.substvars diff -Nru fwupd-1.4.5/debian/libfwupd2.symbols fwupd-1.5.8/debian/libfwupd2.symbols --- fwupd-1.4.5/debian/libfwupd2.symbols 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/debian/libfwupd2.symbols 2021-03-31 20:08:32.000000000 +0000 @@ -39,6 +39,13 @@ LIBFWUPD_1.4.0@LIBFWUPD_1.4.0 1.4.0 LIBFWUPD_1.4.1@LIBFWUPD_1.4.1 1.4.1 LIBFWUPD_1.4.5@LIBFWUPD_1.4.5 1.4.5 + LIBFWUPD_1.4.6@LIBFWUPD_1.4.6 1.4.6 + LIBFWUPD_1.5.0@LIBFWUPD_1.5.0 1.5.0 + LIBFWUPD_1.5.1@LIBFWUPD_1.5.1 1.5.1 + LIBFWUPD_1.5.2@LIBFWUPD_1.5.2 1.5.2 + LIBFWUPD_1.5.3@LIBFWUPD_1.5.3 1.5.3 + LIBFWUPD_1.5.5@LIBFWUPD_1.5.5 1.5.5 + LIBFWUPD_1.5.6@LIBFWUPD_1.5.6 1.5.6 fwupd_build_history_report_json@LIBFWUPD_1.0.4 1.0.4 fwupd_build_machine_id@LIBFWUPD_1.0.4 1.0.4 fwupd_build_user_agent@LIBFWUPD_1.0.3 1.0.3 @@ -47,61 +54,149 @@ fwupd_checksum_get_by_kind@LIBFWUPD_0.9.4 1.0.0 fwupd_checksum_guess_kind@LIBFWUPD_0.9.3 1.0.0 fwupd_client_activate@LIBFWUPD_1.2.6 1.2.6 + fwupd_client_activate_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_activate_finish@LIBFWUPD_1.5.0 1.5.0 fwupd_client_clear_results@LIBFWUPD_0.7.0 1.0.0 + fwupd_client_clear_results_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_clear_results_finish@LIBFWUPD_1.5.0 1.5.0 fwupd_client_connect@LIBFWUPD_0.7.1 1.0.0 + fwupd_client_connect_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_connect_finish@LIBFWUPD_1.5.0 1.5.0 fwupd_client_download_bytes@LIBFWUPD_1.4.5 1.4.5 + fwupd_client_download_bytes_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_download_bytes_finish@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_download_file@LIBFWUPD_1.5.2 1.5.2 fwupd_client_ensure_networking@LIBFWUPD_1.4.5 1.4.5 fwupd_client_get_approved_firmware@LIBFWUPD_1.2.6 1.2.6 + fwupd_client_get_approved_firmware_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_get_approved_firmware_finish@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_get_blocked_firmware@LIBFWUPD_1.4.6 1.4.6 + fwupd_client_get_blocked_firmware_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_get_blocked_firmware_finish@LIBFWUPD_1.5.0 1.5.0 fwupd_client_get_daemon_interactive@LIBFWUPD_1.3.4 1.3.4 fwupd_client_get_daemon_version@LIBFWUPD_0.9.6 1.0.0 fwupd_client_get_details@LIBFWUPD_1.0.0 1.0.0 + fwupd_client_get_details_bytes@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_get_details_bytes_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_get_details_bytes_finish@LIBFWUPD_1.5.0 1.5.0 fwupd_client_get_device_by_id@LIBFWUPD_0.9.3 1.0.0 + fwupd_client_get_device_by_id_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_get_device_by_id_finish@LIBFWUPD_1.5.0 1.5.0 fwupd_client_get_devices@LIBFWUPD_0.9.2 1.0.0 + fwupd_client_get_devices_async@LIBFWUPD_1.5.0 1.5.0 fwupd_client_get_devices_by_guid@LIBFWUPD_1.4.1 1.4.1 + fwupd_client_get_devices_by_guid_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_get_devices_by_guid_finish@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_get_devices_finish@LIBFWUPD_1.5.0 1.5.0 fwupd_client_get_downgrades@LIBFWUPD_0.9.8 1.0.0 + fwupd_client_get_downgrades_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_get_downgrades_finish@LIBFWUPD_1.5.0 1.5.0 fwupd_client_get_history@LIBFWUPD_1.0.4 1.0.4 + fwupd_client_get_history_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_get_history_finish@LIBFWUPD_1.5.0 1.5.0 fwupd_client_get_host_machine_id@LIBFWUPD_1.3.2 1.3.2 fwupd_client_get_host_product@LIBFWUPD_1.3.1 1.3.1 + fwupd_client_get_host_security_attrs@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_get_host_security_attrs_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_get_host_security_attrs_finish@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_get_host_security_id@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_get_main_context@LIBFWUPD_1.5.3 1.5.3 fwupd_client_get_percentage@LIBFWUPD_0.7.3 1.0.0 + fwupd_client_get_plugins@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_get_plugins_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_get_plugins_finish@LIBFWUPD_1.5.0 1.5.0 fwupd_client_get_releases@LIBFWUPD_0.9.3 1.0.0 + fwupd_client_get_releases_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_get_releases_finish@LIBFWUPD_1.5.0 1.5.0 fwupd_client_get_remote_by_id@LIBFWUPD_0.9.3 1.0.0 + fwupd_client_get_remote_by_id_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_get_remote_by_id_finish@LIBFWUPD_1.5.0 1.5.0 fwupd_client_get_remotes@LIBFWUPD_0.9.3 1.0.0 + fwupd_client_get_remotes_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_get_remotes_finish@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_get_report_metadata@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_get_report_metadata_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_get_report_metadata_finish@LIBFWUPD_1.5.0 1.5.0 fwupd_client_get_results@LIBFWUPD_0.7.0 1.0.0 + fwupd_client_get_results_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_get_results_finish@LIBFWUPD_1.5.0 1.5.0 fwupd_client_get_status@LIBFWUPD_0.7.3 1.0.0 fwupd_client_get_tainted@LIBFWUPD_1.2.4 1.2.4 fwupd_client_get_type@LIBFWUPD_0.7.0 1.0.0 fwupd_client_get_upgrades@LIBFWUPD_0.9.8 1.0.0 + fwupd_client_get_upgrades_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_get_upgrades_finish@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_get_user_agent@LIBFWUPD_1.5.2 1.5.2 fwupd_client_install@LIBFWUPD_0.7.0 1.0.0 + fwupd_client_install_async@LIBFWUPD_1.5.0 1.5.0 fwupd_client_install_bytes@LIBFWUPD_1.4.5 1.4.5 + fwupd_client_install_bytes_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_install_bytes_finish@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_install_finish@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_install_release2@LIBFWUPD_1.5.6 1.5.6 + fwupd_client_install_release2_async@LIBFWUPD_1.5.6 1.5.6 fwupd_client_install_release@LIBFWUPD_1.4.5 1.4.5 + fwupd_client_install_release_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_install_release_finish@LIBFWUPD_1.5.0 1.5.0 fwupd_client_modify_config@LIBFWUPD_1.2.8 1.2.8 + fwupd_client_modify_config_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_modify_config_finish@LIBFWUPD_1.5.0 1.5.0 fwupd_client_modify_device@LIBFWUPD_1.0.4 1.0.4 + fwupd_client_modify_device_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_modify_device_finish@LIBFWUPD_1.5.0 1.5.0 fwupd_client_modify_remote@LIBFWUPD_0.9.8 1.0.0 + fwupd_client_modify_remote_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_modify_remote_finish@LIBFWUPD_1.5.0 1.5.0 fwupd_client_new@LIBFWUPD_0.7.0 1.0.0 fwupd_client_refresh_remote@LIBFWUPD_1.4.5 1.4.5 + fwupd_client_refresh_remote_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_refresh_remote_finish@LIBFWUPD_1.5.0 1.5.0 fwupd_client_self_sign@LIBFWUPD_1.2.6 1.2.6 + fwupd_client_self_sign_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_self_sign_finish@LIBFWUPD_1.5.0 1.5.0 fwupd_client_set_approved_firmware@LIBFWUPD_1.2.6 1.2.6 + fwupd_client_set_approved_firmware_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_set_approved_firmware_finish@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_set_blocked_firmware@LIBFWUPD_1.4.6 1.4.6 + fwupd_client_set_blocked_firmware_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_set_blocked_firmware_finish@LIBFWUPD_1.5.0 1.5.0 fwupd_client_set_feature_flags@LIBFWUPD_1.4.5 1.4.5 + fwupd_client_set_feature_flags_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_set_feature_flags_finish@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_set_main_context@LIBFWUPD_1.5.3 1.5.3 fwupd_client_set_user_agent@LIBFWUPD_1.4.5 1.4.5 fwupd_client_set_user_agent_for_package@LIBFWUPD_1.4.5 1.4.5 fwupd_client_unlock@LIBFWUPD_0.7.0 1.0.0 + fwupd_client_unlock_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_unlock_finish@LIBFWUPD_1.5.0 1.5.0 fwupd_client_update_metadata@LIBFWUPD_1.0.0 1.0.0 fwupd_client_update_metadata_bytes@LIBFWUPD_1.4.5 1.4.5 + fwupd_client_update_metadata_bytes_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_update_metadata_bytes_finish@LIBFWUPD_1.5.0 1.5.0 fwupd_client_upload_bytes@LIBFWUPD_1.4.5 1.4.5 + fwupd_client_upload_bytes_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_upload_bytes_finish@LIBFWUPD_1.5.0 1.5.0 fwupd_client_verify@LIBFWUPD_0.7.0 1.0.0 + fwupd_client_verify_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_verify_finish@LIBFWUPD_1.5.0 1.5.0 fwupd_client_verify_update@LIBFWUPD_0.8.0 1.0.0 + fwupd_client_verify_update_async@LIBFWUPD_1.5.0 1.5.0 + fwupd_client_verify_update_finish@LIBFWUPD_1.5.0 1.5.0 fwupd_device_add_checksum@LIBFWUPD_0.9.3 1.0.0 + fwupd_device_add_child@LIBFWUPD_1.5.1 1.5.1 fwupd_device_add_flag@LIBFWUPD_0.9.3 1.0.0 fwupd_device_add_guid@LIBFWUPD_0.9.3 1.0.0 fwupd_device_add_icon@LIBFWUPD_0.9.8 1.0.0 fwupd_device_add_instance_id@LIBFWUPD_1.2.5 1.2.5 fwupd_device_add_release@LIBFWUPD_0.9.8 1.0.0 + fwupd_device_add_vendor_id@LIBFWUPD_1.5.5 1.5.5 fwupd_device_array_ensure_parents@LIBFWUPD_1.3.7 1.3.7 fwupd_device_array_from_variant@LIBFWUPD_1.2.10 1.2.10 fwupd_device_compare@LIBFWUPD_1.1.1 1.1.1 fwupd_device_flag_from_string@LIBFWUPD_0.7.0 1.0.0 fwupd_device_flag_to_string@LIBFWUPD_0.7.0 1.0.0 fwupd_device_from_variant@LIBFWUPD_1.0.0 1.0.0 + fwupd_device_get_branch@LIBFWUPD_1.5.0 1.5.0 fwupd_device_get_checksums@LIBFWUPD_0.9.3 1.0.0 fwupd_device_get_children@LIBFWUPD_1.3.7 1.3.7 fwupd_device_get_created@LIBFWUPD_0.9.3 1.0.0 @@ -132,6 +227,7 @@ fwupd_device_get_update_state@LIBFWUPD_0.9.8 1.0.0 fwupd_device_get_vendor@LIBFWUPD_0.9.3 1.0.0 fwupd_device_get_vendor_id@LIBFWUPD_0.9.4 1.0.0 + fwupd_device_get_vendor_ids@LIBFWUPD_1.5.5 1.5.5 fwupd_device_get_version@LIBFWUPD_0.9.3 1.0.0 fwupd_device_get_version_bootloader@LIBFWUPD_0.9.3 1.0.0 fwupd_device_get_version_bootloader_raw@LIBFWUPD_1.4.0 1.4.0 @@ -142,10 +238,12 @@ fwupd_device_has_flag@LIBFWUPD_0.9.3 1.0.0 fwupd_device_has_guid@LIBFWUPD_0.9.3 1.0.0 fwupd_device_has_instance_id@LIBFWUPD_1.2.5 1.2.5 + fwupd_device_has_vendor_id@LIBFWUPD_1.5.5 1.5.5 fwupd_device_id_is_valid@LIBFWUPD_1.4.1 1.4.1 fwupd_device_incorporate@LIBFWUPD_1.1.0 1.1.0 fwupd_device_new@LIBFWUPD_0.9.3 1.0.0 fwupd_device_remove_flag@LIBFWUPD_0.9.3 1.0.0 + fwupd_device_set_branch@LIBFWUPD_1.5.0 1.5.0 fwupd_device_set_created@LIBFWUPD_0.9.3 1.0.0 fwupd_device_set_description@LIBFWUPD_0.9.3 1.0.0 fwupd_device_set_flags@LIBFWUPD_0.9.3 1.0.0 @@ -191,10 +289,27 @@ fwupd_guid_to_string@LIBFWUPD_1.2.5 1.2.5 fwupd_keyring_kind_from_string@LIBFWUPD_0.9.7 1.0.0 fwupd_keyring_kind_to_string@LIBFWUPD_0.9.7 1.0.0 + fwupd_plugin_add_flag@LIBFWUPD_1.5.0 1.5.0 + fwupd_plugin_array_from_variant@LIBFWUPD_1.5.0 1.5.0 + fwupd_plugin_flag_from_string@LIBFWUPD_1.5.0 1.5.0 + fwupd_plugin_flag_to_string@LIBFWUPD_1.5.0 1.5.0 + fwupd_plugin_from_variant@LIBFWUPD_1.5.0 1.5.0 + fwupd_plugin_get_flags@LIBFWUPD_1.5.0 1.5.0 + fwupd_plugin_get_name@LIBFWUPD_1.5.0 1.5.0 + fwupd_plugin_get_type@LIBFWUPD_1.5.0 1.5.0 + fwupd_plugin_has_flag@LIBFWUPD_1.5.0 1.5.0 + fwupd_plugin_new@LIBFWUPD_1.5.0 1.5.0 + fwupd_plugin_remove_flag@LIBFWUPD_1.5.0 1.5.0 + fwupd_plugin_set_flags@LIBFWUPD_1.5.0 1.5.0 + fwupd_plugin_set_name@LIBFWUPD_1.5.0 1.5.0 + fwupd_plugin_to_json@LIBFWUPD_1.5.0 1.5.0 + fwupd_plugin_to_string@LIBFWUPD_1.5.0 1.5.0 + fwupd_plugin_to_variant@LIBFWUPD_1.5.0 1.5.0 fwupd_release_add_category@LIBFWUPD_1.2.7 1.2.7 fwupd_release_add_checksum@LIBFWUPD_0.9.3 1.0.0 fwupd_release_add_flag@LIBFWUPD_1.2.6 1.2.6 fwupd_release_add_issue@LIBFWUPD_1.3.2 1.3.2 + fwupd_release_add_location@LIBFWUPD_1.5.6 1.5.6 fwupd_release_add_metadata@LIBFWUPD_1.0.4 1.0.4 fwupd_release_add_metadata_item@LIBFWUPD_1.0.4 1.0.4 fwupd_release_array_from_variant@LIBFWUPD_1.2.10 1.2.10 @@ -202,6 +317,7 @@ fwupd_release_flag_to_string@LIBFWUPD_1.2.6 1.2.6 fwupd_release_from_variant@LIBFWUPD_1.0.0 1.0.0 fwupd_release_get_appstream_id@LIBFWUPD_0.9.3 1.0.0 + fwupd_release_get_branch@LIBFWUPD_1.5.0 1.5.0 fwupd_release_get_categories@LIBFWUPD_1.2.7 1.2.7 fwupd_release_get_checksums@LIBFWUPD_0.9.3 1.0.0 fwupd_release_get_created@LIBFWUPD_1.4.0 1.4.0 @@ -215,6 +331,7 @@ fwupd_release_get_install_duration@LIBFWUPD_1.2.1 1.2.4 fwupd_release_get_issues@LIBFWUPD_1.3.2 1.3.2 fwupd_release_get_license@LIBFWUPD_0.9.3 1.0.0 + fwupd_release_get_locations@LIBFWUPD_1.5.6 1.5.6 fwupd_release_get_metadata@LIBFWUPD_1.0.4 1.0.4 fwupd_release_get_metadata_item@LIBFWUPD_1.0.4 1.0.4 fwupd_release_get_name@LIBFWUPD_0.9.3 1.0.0 @@ -238,6 +355,7 @@ fwupd_release_new@LIBFWUPD_0.9.3 1.0.0 fwupd_release_remove_flag@LIBFWUPD_1.2.6 1.2.6 fwupd_release_set_appstream_id@LIBFWUPD_0.9.3 1.0.0 + fwupd_release_set_branch@LIBFWUPD_1.5.0 1.5.0 fwupd_release_set_created@LIBFWUPD_1.4.0 1.4.0 fwupd_release_set_description@LIBFWUPD_0.9.3 1.0.0 fwupd_release_set_detach_caption@LIBFWUPD_1.3.3 1.3.3 @@ -274,6 +392,7 @@ fwupd_remote_get_agreement@LIBFWUPD_1.0.7 1.0.7 fwupd_remote_get_approval_required@LIBFWUPD_1.2.6 1.2.6 fwupd_remote_get_automatic_reports@LIBFWUPD_1.3.3 1.3.3 + fwupd_remote_get_automatic_security_reports@LIBFWUPD_1.5.0 1.5.0 fwupd_remote_get_checksum@LIBFWUPD_1.0.0 1.0.0 fwupd_remote_get_enabled@LIBFWUPD_0.9.3 1.0.0 fwupd_remote_get_filename_cache@LIBFWUPD_0.9.6 1.0.0 @@ -291,6 +410,7 @@ fwupd_remote_get_priority@LIBFWUPD_0.9.5 1.0.0 fwupd_remote_get_remotes_dir@LIBFWUPD_1.3.1 1.3.1 fwupd_remote_get_report_uri@LIBFWUPD_1.0.4 1.0.4 + fwupd_remote_get_security_report_uri@LIBFWUPD_1.5.0 1.5.0 fwupd_remote_get_title@LIBFWUPD_0.9.8 1.0.0 fwupd_remote_get_type@LIBFWUPD_0.9.3 1.0.0 fwupd_remote_get_username@LIBFWUPD_0.9.5 1.0.0 @@ -301,10 +421,42 @@ fwupd_remote_load_signature_bytes@LIBFWUPD_1.4.5 1.4.5 fwupd_remote_new@LIBFWUPD_0.9.3 1.0.0 fwupd_remote_set_agreement@LIBFWUPD_1.0.7 1.0.7 + fwupd_remote_set_keyring_kind@LIBFWUPD_1.5.3 1.5.3 fwupd_remote_set_mtime@LIBFWUPD_0.9.5 1.0.0 fwupd_remote_set_priority@LIBFWUPD_0.9.5 1.0.0 fwupd_remote_set_remotes_dir@LIBFWUPD_1.3.1 1.3.1 fwupd_remote_to_variant@LIBFWUPD_1.0.0 1.0.0 + fwupd_security_attr_add_flag@LIBFWUPD_1.5.0 1.5.0 + fwupd_security_attr_add_metadata@LIBFWUPD_1.5.0 1.5.0 + fwupd_security_attr_add_obsolete@LIBFWUPD_1.5.0 1.5.0 + fwupd_security_attr_array_from_variant@LIBFWUPD_1.5.0 1.5.0 + fwupd_security_attr_flag_to_string@LIBFWUPD_1.5.0 1.5.0 + fwupd_security_attr_flag_to_suffix@LIBFWUPD_1.5.0 1.5.0 + fwupd_security_attr_from_variant@LIBFWUPD_1.5.0 1.5.0 + fwupd_security_attr_get_appstream_id@LIBFWUPD_1.5.0 1.5.0 + fwupd_security_attr_get_flags@LIBFWUPD_1.5.0 1.5.0 + fwupd_security_attr_get_level@LIBFWUPD_1.5.0 1.5.0 + fwupd_security_attr_get_metadata@LIBFWUPD_1.5.0 1.5.0 + fwupd_security_attr_get_name@LIBFWUPD_1.5.0 1.5.0 + fwupd_security_attr_get_obsoletes@LIBFWUPD_1.5.0 1.5.0 + fwupd_security_attr_get_plugin@LIBFWUPD_1.5.0 1.5.0 + fwupd_security_attr_get_result@LIBFWUPD_1.5.0 1.5.0 + fwupd_security_attr_get_type@LIBFWUPD_1.5.0 1.5.0 + fwupd_security_attr_get_url@LIBFWUPD_1.5.0 1.5.0 + fwupd_security_attr_has_flag@LIBFWUPD_1.5.0 1.5.0 + fwupd_security_attr_has_obsolete@LIBFWUPD_1.5.0 1.5.0 + fwupd_security_attr_new@LIBFWUPD_1.5.0 1.5.0 + fwupd_security_attr_result_to_string@LIBFWUPD_1.5.0 1.5.0 + fwupd_security_attr_set_appstream_id@LIBFWUPD_1.5.0 1.5.0 + fwupd_security_attr_set_flags@LIBFWUPD_1.5.0 1.5.0 + fwupd_security_attr_set_level@LIBFWUPD_1.5.0 1.5.0 + fwupd_security_attr_set_name@LIBFWUPD_1.5.0 1.5.0 + fwupd_security_attr_set_plugin@LIBFWUPD_1.5.0 1.5.0 + fwupd_security_attr_set_result@LIBFWUPD_1.5.0 1.5.0 + fwupd_security_attr_set_url@LIBFWUPD_1.5.0 1.5.0 + fwupd_security_attr_to_json@LIBFWUPD_1.5.0 1.5.0 + fwupd_security_attr_to_string@LIBFWUPD_1.5.0 1.5.0 + fwupd_security_attr_to_variant@LIBFWUPD_1.5.0 1.5.0 fwupd_status_from_string@LIBFWUPD_0.1.1 1.0.0 fwupd_status_to_string@LIBFWUPD_0.1.1 1.0.0 fwupd_trust_flag_from_string@LIBFWUPD_0.7.0 1.0.0 diff -Nru fwupd-1.4.5/debian/libfwupdplugin1.symbols fwupd-1.5.8/debian/libfwupdplugin1.symbols --- fwupd-1.4.5/debian/libfwupdplugin1.symbols 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/debian/libfwupdplugin1.symbols 2021-03-31 20:08:32.000000000 +0000 @@ -41,42 +41,88 @@ LIBFWUPDPLUGIN_1.4.0@LIBFWUPDPLUGIN_1.4.0 1.4.0 LIBFWUPDPLUGIN_1.4.1@LIBFWUPDPLUGIN_1.4.1 1.4.1 LIBFWUPDPLUGIN_1.4.5@LIBFWUPDPLUGIN_1.4.5 1.4.5 + LIBFWUPDPLUGIN_1.4.6@LIBFWUPDPLUGIN_1.4.6 1.4.6 + LIBFWUPDPLUGIN_1.4.7@LIBFWUPDPLUGIN_1.4.7 1.4.7 + LIBFWUPDPLUGIN_1.5.0@LIBFWUPDPLUGIN_1.5.0 1.5.0 + LIBFWUPDPLUGIN_1.5.1@LIBFWUPDPLUGIN_1.5.1 1.5.1 + LIBFWUPDPLUGIN_1.5.2@LIBFWUPDPLUGIN_1.5.2 1.5.2 + LIBFWUPDPLUGIN_1.5.3@LIBFWUPDPLUGIN_1.5.3 1.5.3 + LIBFWUPDPLUGIN_1.5.4@LIBFWUPDPLUGIN_1.5.4 1.5.4 + LIBFWUPDPLUGIN_1.5.5@LIBFWUPDPLUGIN_1.5.5 1.5.5 + LIBFWUPDPLUGIN_1.5.6@LIBFWUPDPLUGIN_1.5.6 1.5.6 + LIBFWUPDPLUGIN_1.5.7@LIBFWUPDPLUGIN_1.5.7 1.5.7 fu_archive_get_type@LIBFWUPDPLUGIN_1.2.2 1.2.2 fu_archive_iterate@LIBFWUPDPLUGIN_1.3.4 1.3.4 fu_archive_lookup_by_fn@LIBFWUPDPLUGIN_1.2.2 1.2.2 fu_archive_new@LIBFWUPDPLUGIN_1.2.2 1.2.2 + fu_bluez_device_get_type@LIBFWUPDPLUGIN_1.5.7 1.5.7 + fu_bluez_device_read@LIBFWUPDPLUGIN_1.5.7 1.5.7 + fu_bluez_device_read_string@LIBFWUPDPLUGIN_1.5.7 1.5.7 + fu_bluez_device_write@LIBFWUPDPLUGIN_1.5.7 1.5.7 fu_byte_array_append_uint16@LIBFWUPDPLUGIN_1.3.1 1.3.1 fu_byte_array_append_uint32@LIBFWUPDPLUGIN_1.3.1 1.3.1 fu_byte_array_append_uint8@LIBFWUPDPLUGIN_1.3.1 1.3.1 + fu_byte_array_set_size@LIBFWUPDPLUGIN_1.5.0 1.5.0 fu_cabinet_get_silo@LIBFWUPDPLUGIN_1.4.0 1.4.0 fu_cabinet_get_type@LIBFWUPDPLUGIN_1.4.0 1.4.0 fu_cabinet_new@LIBFWUPDPLUGIN_1.4.0 1.4.0 fu_cabinet_parse@LIBFWUPDPLUGIN_1.4.0 1.4.0 fu_cabinet_set_jcat_context@LIBFWUPDPLUGIN_1.4.0 1.4.0 fu_cabinet_set_size_max@LIBFWUPDPLUGIN_1.4.0 1.4.0 + fu_chunk_array_mutable_new@LIBFWUPDPLUGIN_1.5.6 1.5.6 fu_chunk_array_new@LIBFWUPDPLUGIN_1.1.2 1.1.2 fu_chunk_array_new_from_bytes@LIBFWUPDPLUGIN_1.1.2 1.1.2 fu_chunk_array_to_string@LIBFWUPDPLUGIN_1.0.1 1.0.1 + fu_chunk_bytes_new@LIBFWUPDPLUGIN_1.5.6 1.5.6 + fu_chunk_get_address@LIBFWUPDPLUGIN_1.5.6 1.5.6 + fu_chunk_get_bytes@LIBFWUPDPLUGIN_1.5.6 1.5.6 + fu_chunk_get_data@LIBFWUPDPLUGIN_1.5.6 1.5.6 + fu_chunk_get_data_out@LIBFWUPDPLUGIN_1.5.6 1.5.6 + fu_chunk_get_data_sz@LIBFWUPDPLUGIN_1.5.6 1.5.6 + fu_chunk_get_idx@LIBFWUPDPLUGIN_1.5.6 1.5.6 + fu_chunk_get_page@LIBFWUPDPLUGIN_1.5.6 1.5.6 + fu_chunk_get_type@LIBFWUPDPLUGIN_1.5.6 1.5.6 fu_chunk_new@LIBFWUPDPLUGIN_1.1.2 1.1.2 + fu_chunk_set_address@LIBFWUPDPLUGIN_1.5.6 1.5.6 + fu_chunk_set_bytes@LIBFWUPDPLUGIN_1.5.6 1.5.6 + fu_chunk_set_idx@LIBFWUPDPLUGIN_1.5.6 1.5.6 + fu_chunk_set_page@LIBFWUPDPLUGIN_1.5.6 1.5.6 + fu_chunk_to_string@LIBFWUPDPLUGIN_1.1.2 1.4.6 fu_common_bytes_align@LIBFWUPDPLUGIN_1.2.4 1.2.4 fu_common_bytes_compare@LIBFWUPDPLUGIN_1.2.6 1.2.6 fu_common_bytes_compare_raw@LIBFWUPDPLUGIN_1.3.2 1.3.2 fu_common_bytes_is_empty@LIBFWUPDPLUGIN_1.2.6 1.2.6 + fu_common_bytes_new_offset@LIBFWUPDPLUGIN_1.5.4 1.5.4 fu_common_bytes_pad@LIBFWUPDPLUGIN_1.3.1 1.3.1 fu_common_cab_build_silo@LIBFWUPDPLUGIN_1.2.0 1.2.0 + fu_common_cpuid@LIBFWUPDPLUGIN_1.5.0 1.5.0 + fu_common_crc16@LIBFWUPDPLUGIN_1.5.0 1.5.0 + fu_common_crc32@LIBFWUPDPLUGIN_1.5.0 1.5.0 + fu_common_crc32_full@LIBFWUPDPLUGIN_1.5.0 1.5.0 + fu_common_crc8@LIBFWUPDPLUGIN_1.5.0 1.5.0 fu_common_dump_bytes@LIBFWUPDPLUGIN_1.2.2 1.2.2 fu_common_dump_full@LIBFWUPDPLUGIN_1.2.4 1.2.4 fu_common_dump_raw@LIBFWUPDPLUGIN_1.2.2 1.2.2 fu_common_error_array_get_best@LIBFWUPDPLUGIN_1.0.8 1.0.8 fu_common_extract_archive@LIBFWUPDPLUGIN_0.9.7 0.9.7 + fu_common_filename_glob@LIBFWUPDPLUGIN_1.5.0 1.5.0 fu_common_find_program_in_path@LIBFWUPDPLUGIN_1.1.2 1.1.2 fu_common_firmware_builder@LIBFWUPDPLUGIN_0.9.7 0.9.7 fu_common_fnmatch@LIBFWUPDPLUGIN_1.3.5 1.3.5 fu_common_get_contents_bytes@LIBFWUPDPLUGIN_0.9.7 0.9.7 fu_common_get_contents_fd@LIBFWUPDPLUGIN_0.9.5 0.9.5 + fu_common_get_cpu_vendor@LIBFWUPDPLUGIN_1.5.5 1.5.5 + fu_common_get_esp_default@LIBFWUPDPLUGIN_1.4.6 1.4.6 + fu_common_get_esp_for_path@LIBFWUPDPLUGIN_1.4.6 1.4.6 fu_common_get_files_recursive@LIBFWUPDPLUGIN_1.0.6 1.0.6 + fu_common_get_memory_size@LIBFWUPDPLUGIN_1.5.6 1.5.6 fu_common_get_path@LIBFWUPDPLUGIN_1.0.8 1.0.8 + fu_common_get_volume_by_device@LIBFWUPDPLUGIN_1.5.1 1.5.1 + fu_common_get_volume_by_devnum@LIBFWUPDPLUGIN_1.5.1 1.5.1 + fu_common_get_volumes_by_kind@LIBFWUPDPLUGIN_1.4.6 1.4.6 fu_common_guid_is_plausible@LIBFWUPDPLUGIN_1.2.5 1.2.5 + fu_common_is_cpu_intel@LIBFWUPDPLUGIN_1.5.0 1.5.0 + fu_common_is_live_media@LIBFWUPDPLUGIN_1.4.6 1.4.6 fu_common_kernel_locked_down@LIBFWUPDPLUGIN_1.3.8 1.3.8 fu_common_mkdir_parent@LIBFWUPDPLUGIN_0.9.7 0.9.7 fu_common_read_uint16@LIBFWUPDPLUGIN_1.0.3 1.0.3 @@ -93,10 +139,13 @@ fu_common_string_append_kv@LIBFWUPDPLUGIN_1.2.4 1.2.4 fu_common_string_append_kx@LIBFWUPDPLUGIN_1.2.4 1.2.4 fu_common_string_replace@LIBFWUPDPLUGIN_1.2.0 1.2.0 + fu_common_strjoin_array@LIBFWUPDPLUGIN_1.5.6 1.5.6 fu_common_strnsplit@LIBFWUPDPLUGIN_1.3.1 1.3.1 + fu_common_strsafe@LIBFWUPDPLUGIN_1.5.5 1.5.5 fu_common_strstrip@LIBFWUPDPLUGIN_1.1.2 1.1.2 fu_common_strtoull@LIBFWUPDPLUGIN_1.1.2 1.1.2 fu_common_strwidth@LIBFWUPDPLUGIN_1.3.2 1.3.2 + fu_common_uri_get_scheme@LIBFWUPDPLUGIN_1.5.6 1.5.6 fu_common_vercmp@LIBFWUPDPLUGIN_0.3.5 0.3.5 fu_common_vercmp_full@LIBFWUPDPLUGIN_1.3.9 1.3.9 fu_common_version_ensure_semver@LIBFWUPDPLUGIN_1.2.9 1.2.9 @@ -116,12 +165,16 @@ fu_device_add_guid@LIBFWUPDPLUGIN_0.7.2 0.7.2 fu_device_add_instance_id@LIBFWUPDPLUGIN_1.2.5 1.2.5 fu_device_add_instance_id_full@LIBFWUPDPLUGIN_1.2.9 1.2.9 + fu_device_add_internal_flag@LIBFWUPDPLUGIN_1.5.5 1.5.5 fu_device_add_parent_guid@LIBFWUPDPLUGIN_1.0.8 1.0.8 + fu_device_add_possible_plugin@LIBFWUPDPLUGIN_1.5.1 1.5.1 fu_device_attach@LIBFWUPDPLUGIN_1.0.8 1.0.8 + fu_device_bind_driver@LIBFWUPDPLUGIN_1.5.0 1.5.0 fu_device_cleanup@LIBFWUPDPLUGIN_1.3.3 1.3.3 fu_device_close@LIBFWUPDPLUGIN_1.1.2 1.1.2 fu_device_convert_instance_ids@LIBFWUPDPLUGIN_1.2.5 1.2.5 fu_device_detach@LIBFWUPDPLUGIN_1.0.8 1.0.8 + fu_device_dump_firmware@LIBFWUPDPLUGIN_1.5.0 1.5.0 fu_device_ensure_id@LIBFWUPDPLUGIN_1.1.2 1.1.2 fu_device_get_alternate@LIBFWUPDPLUGIN_0.7.2 0.7.2 fu_device_get_alternate_id@LIBFWUPDPLUGIN_1.1.0 1.1.0 @@ -154,10 +207,13 @@ fu_device_get_type@LIBFWUPDPLUGIN_0.1.0 0.1.0 fu_device_has_custom_flag@LIBFWUPDPLUGIN_1.1.0 1.1.0 fu_device_has_guid@LIBFWUPDPLUGIN_1.2.2 1.2.2 + fu_device_has_internal_flag@LIBFWUPDPLUGIN_1.5.5 1.5.5 fu_device_has_parent_guid@LIBFWUPDPLUGIN_1.0.8 1.0.8 fu_device_incorporate@LIBFWUPDPLUGIN_1.1.0 1.1.0 fu_device_incorporate_flag@LIBFWUPDPLUGIN_1.3.5 1.3.5 fu_device_incorporate_from_component@LIBFWUPDPLUGIN_1.2.4 1.2.4 + fu_device_internal_flag_from_string@LIBFWUPDPLUGIN_1.5.5 1.5.5 + fu_device_internal_flag_to_string@LIBFWUPDPLUGIN_1.5.5 1.5.5 fu_device_locker_close@LIBFWUPDPLUGIN_1.4.0 1.4.0 fu_device_locker_get_type@LIBFWUPDPLUGIN_1.0.0 1.0.0 fu_device_locker_new@LIBFWUPDPLUGIN_1.0.0 1.0.0 @@ -171,10 +227,14 @@ fu_device_probe_invalidate@LIBFWUPDPLUGIN_1.1.2 1.1.2 fu_device_read_firmware@LIBFWUPDPLUGIN_1.0.8 1.0.8 fu_device_reload@LIBFWUPDPLUGIN_1.3.3 1.3.3 + fu_device_remove_internal_flag@LIBFWUPDPLUGIN_1.5.5 1.5.5 fu_device_remove_metadata@LIBFWUPDPLUGIN_1.3.3 1.3.3 + fu_device_report_metadata_post@LIBFWUPDPLUGIN_1.5.0 1.5.0 + fu_device_report_metadata_pre@LIBFWUPDPLUGIN_1.5.0 1.5.0 fu_device_rescan@LIBFWUPDPLUGIN_1.3.1 1.3.1 fu_device_retry@LIBFWUPDPLUGIN_1.4.0 1.4.0 fu_device_retry_add_recovery@LIBFWUPDPLUGIN_1.4.0 1.4.0 + fu_device_retry_full@LIBFWUPDPLUGIN_1.5.5 1.5.5 fu_device_retry_set_delay@LIBFWUPDPLUGIN_1.4.0 1.4.0 fu_device_set_alternate@LIBFWUPDPLUGIN_0.7.2 0.7.2 fu_device_set_alternate_id@LIBFWUPDPLUGIN_1.1.0 1.1.0 @@ -207,7 +267,9 @@ fu_device_set_version_format@LIBFWUPDPLUGIN_1.4.0 1.4.0 fu_device_set_version_lowest@LIBFWUPDPLUGIN_1.4.0 1.4.0 fu_device_setup@LIBFWUPDPLUGIN_1.1.2 1.1.2 + fu_device_sleep_with_progress@LIBFWUPDPLUGIN_1.5.0 1.5.0 fu_device_to_string@LIBFWUPDPLUGIN_0.9.8 0.9.8 + fu_device_unbind_driver@LIBFWUPDPLUGIN_1.5.0 1.5.0 fu_device_write_firmware@LIBFWUPDPLUGIN_1.0.8 1.0.8 fu_dfu_firmware_get_pid@LIBFWUPDPLUGIN_1.3.3 1.3.3 fu_dfu_firmware_get_release@LIBFWUPDPLUGIN_1.3.3 1.3.3 @@ -219,14 +281,33 @@ fu_dfu_firmware_set_release@LIBFWUPDPLUGIN_1.3.3 1.3.3 fu_dfu_firmware_set_version@LIBFWUPDPLUGIN_1.3.3 1.3.3 fu_dfu_firmware_set_vid@LIBFWUPDPLUGIN_1.3.3 1.3.3 + fu_dfuse_firmware_get_type@LIBFWUPDPLUGIN_1.5.6 1.5.6 + fu_dfuse_firmware_new@LIBFWUPDPLUGIN_1.5.6 1.5.6 + fu_efi_signature_get_kind@LIBFWUPDPLUGIN_1.5.5 1.5.5 + fu_efi_signature_get_owner@LIBFWUPDPLUGIN_1.5.5 1.5.5 + fu_efi_signature_get_type@LIBFWUPDPLUGIN_1.5.5 1.5.5 + fu_efi_signature_kind_to_string@LIBFWUPDPLUGIN_1.5.5 1.5.5 + fu_efi_signature_list_get_type@LIBFWUPDPLUGIN_1.5.5 1.5.5 + fu_efi_signature_list_new@LIBFWUPDPLUGIN_1.5.5 1.5.5 fu_efivar_delete@LIBFWUPDPLUGIN_1.4.0 1.4.0 fu_efivar_delete_with_glob@LIBFWUPDPLUGIN_1.4.0 1.4.0 fu_efivar_exists@LIBFWUPDPLUGIN_1.4.0 1.4.0 fu_efivar_get_data@LIBFWUPDPLUGIN_1.4.0 1.4.0 + fu_efivar_get_data_bytes@LIBFWUPDPLUGIN_1.5.0 1.5.0 + fu_efivar_get_monitor@LIBFWUPDPLUGIN_1.5.5 1.5.5 + fu_efivar_get_names@LIBFWUPDPLUGIN_1.4.7 1.4.7 fu_efivar_secure_boot_enabled@LIBFWUPDPLUGIN_1.4.0 1.4.0 + fu_efivar_secure_boot_enabled_full@LIBFWUPDPLUGIN_1.5.0 1.5.0 fu_efivar_set_data@LIBFWUPDPLUGIN_1.4.0 1.4.0 + fu_efivar_set_data_bytes@LIBFWUPDPLUGIN_1.5.0 1.5.0 + fu_efivar_space_used@LIBFWUPDPLUGIN_1.5.1 1.5.1 fu_efivar_supported@LIBFWUPDPLUGIN_1.4.0 1.4.0 + fu_firmware_add_flag@LIBFWUPDPLUGIN_1.5.0 1.5.0 fu_firmware_add_image@LIBFWUPDPLUGIN_1.3.1 1.3.1 + fu_firmware_build@LIBFWUPDPLUGIN_1.5.0 1.5.0 + fu_firmware_flag_from_string@LIBFWUPDPLUGIN_1.5.0 1.5.0 + fu_firmware_flag_to_string@LIBFWUPDPLUGIN_1.5.0 1.5.0 + fu_firmware_get_image_by_checksum@LIBFWUPDPLUGIN_1.5.5 1.5.5 fu_firmware_get_image_by_id@LIBFWUPDPLUGIN_1.3.1 1.3.1 fu_firmware_get_image_by_id_bytes@LIBFWUPDPLUGIN_1.3.1 1.3.1 fu_firmware_get_image_by_idx@LIBFWUPDPLUGIN_1.3.1 1.3.1 @@ -236,43 +317,70 @@ fu_firmware_get_images@LIBFWUPDPLUGIN_1.3.1 1.3.1 fu_firmware_get_type@LIBFWUPDPLUGIN_1.3.1 1.3.1 fu_firmware_get_version@LIBFWUPDPLUGIN_1.3.3 1.3.3 + fu_firmware_get_version_raw@LIBFWUPDPLUGIN_1.5.7 1.5.7 + fu_firmware_has_flag@LIBFWUPDPLUGIN_1.5.0 1.5.0 + fu_firmware_image_add_chunk@LIBFWUPDPLUGIN_1.5.6 1.5.6 + fu_firmware_image_build@LIBFWUPDPLUGIN_1.5.0 1.5.0 fu_firmware_image_get_addr@LIBFWUPDPLUGIN_1.3.1 1.3.1 + fu_firmware_image_get_bytes@LIBFWUPDPLUGIN_1.5.0 1.5.0 + fu_firmware_image_get_checksum@LIBFWUPDPLUGIN_1.5.5 1.5.5 + fu_firmware_image_get_chunks@LIBFWUPDPLUGIN_1.5.6 1.5.6 + fu_firmware_image_get_filename@LIBFWUPDPLUGIN_1.5.0 1.5.0 fu_firmware_image_get_id@LIBFWUPDPLUGIN_1.3.1 1.3.1 fu_firmware_image_get_idx@LIBFWUPDPLUGIN_1.3.1 1.3.1 + fu_firmware_image_get_offset@LIBFWUPDPLUGIN_1.5.0 1.5.0 fu_firmware_image_get_type@LIBFWUPDPLUGIN_1.3.1 1.3.1 fu_firmware_image_get_version@LIBFWUPDPLUGIN_1.3.4 1.3.4 fu_firmware_image_new@LIBFWUPDPLUGIN_1.3.1 1.3.1 + fu_firmware_image_parse@LIBFWUPDPLUGIN_1.5.0 1.5.0 fu_firmware_image_set_addr@LIBFWUPDPLUGIN_1.3.1 1.3.1 fu_firmware_image_set_bytes@LIBFWUPDPLUGIN_1.3.1 1.3.1 + fu_firmware_image_set_filename@LIBFWUPDPLUGIN_1.5.0 1.5.0 fu_firmware_image_set_id@LIBFWUPDPLUGIN_1.3.1 1.3.1 fu_firmware_image_set_idx@LIBFWUPDPLUGIN_1.3.1 1.3.1 + fu_firmware_image_set_offset@LIBFWUPDPLUGIN_1.5.0 1.5.0 fu_firmware_image_set_version@LIBFWUPDPLUGIN_1.3.4 1.3.4 fu_firmware_image_to_string@LIBFWUPDPLUGIN_1.3.1 1.3.1 fu_firmware_image_write@LIBFWUPDPLUGIN_1.3.3 1.3.3 fu_firmware_image_write_chunk@LIBFWUPDPLUGIN_1.3.1 1.3.1 fu_firmware_new@LIBFWUPDPLUGIN_1.3.1 1.3.1 fu_firmware_new_from_bytes@LIBFWUPDPLUGIN_1.3.1 1.3.1 + fu_firmware_new_from_gtypes@LIBFWUPDPLUGIN_1.5.6 1.5.6 fu_firmware_parse@LIBFWUPDPLUGIN_1.3.1 1.3.1 fu_firmware_parse_file@LIBFWUPDPLUGIN_1.3.3 1.3.3 fu_firmware_parse_full@LIBFWUPDPLUGIN_1.3.1 1.3.1 + fu_firmware_remove_image@LIBFWUPDPLUGIN_1.5.0 1.5.0 + fu_firmware_remove_image_by_id@LIBFWUPDPLUGIN_1.5.0 1.5.0 + fu_firmware_remove_image_by_idx@LIBFWUPDPLUGIN_1.5.0 1.5.0 fu_firmware_set_version@LIBFWUPDPLUGIN_1.3.3 1.3.3 + fu_firmware_set_version_raw@LIBFWUPDPLUGIN_1.5.7 1.5.7 fu_firmware_strparse_uint16@LIBFWUPDPLUGIN_1.3.1 1.3.1 + fu_firmware_strparse_uint16_safe@LIBFWUPDPLUGIN_1.5.6 1.5.6 fu_firmware_strparse_uint24@LIBFWUPDPLUGIN_1.3.1 1.3.1 + fu_firmware_strparse_uint24_safe@LIBFWUPDPLUGIN_1.5.6 1.5.6 fu_firmware_strparse_uint32@LIBFWUPDPLUGIN_1.3.1 1.3.1 + fu_firmware_strparse_uint32_safe@LIBFWUPDPLUGIN_1.5.6 1.5.6 fu_firmware_strparse_uint4@LIBFWUPDPLUGIN_1.3.1 1.3.1 + fu_firmware_strparse_uint4_safe@LIBFWUPDPLUGIN_1.5.6 1.5.6 fu_firmware_strparse_uint8@LIBFWUPDPLUGIN_1.3.1 1.3.1 + fu_firmware_strparse_uint8_safe@LIBFWUPDPLUGIN_1.5.6 1.5.6 fu_firmware_to_string@LIBFWUPDPLUGIN_1.3.1 1.3.1 fu_firmware_tokenize@LIBFWUPDPLUGIN_1.3.2 1.3.2 fu_firmware_write@LIBFWUPDPLUGIN_1.3.1 1.3.1 fu_firmware_write_file@LIBFWUPDPLUGIN_1.3.3 1.3.3 + fu_fmap_firmware_get_type@LIBFWUPDPLUGIN_1.5.0 1.5.0 + fu_fmap_firmware_new@LIBFWUPDPLUGIN_1.5.0 1.5.0 + fu_hid_device_add_flag@LIBFWUPDPLUGIN_1.5.2 1.5.2 fu_hid_device_get_interface@LIBFWUPDPLUGIN_1.4.0 1.4.0 fu_hid_device_get_report@LIBFWUPDPLUGIN_1.4.0 1.4.0 fu_hid_device_get_type@LIBFWUPDPLUGIN_1.4.0 1.4.0 fu_hid_device_new@LIBFWUPDPLUGIN_1.4.0 1.4.0 fu_hid_device_set_interface@LIBFWUPDPLUGIN_1.4.0 1.4.0 fu_hid_device_set_report@LIBFWUPDPLUGIN_1.4.0 1.4.0 + fu_hwids_add_smbios_override@LIBFWUPDPLUGIN_1.5.6 1.5.6 fu_hwids_get_guid@LIBFWUPDPLUGIN_0.9.3 0.9.3 fu_hwids_get_guids@LIBFWUPDPLUGIN_0.9.3 0.9.3 + fu_hwids_get_keys@LIBFWUPDPLUGIN_1.5.6 1.5.6 fu_hwids_get_replace_keys@LIBFWUPDPLUGIN_0.9.3 0.9.3 fu_hwids_get_replace_values@LIBFWUPDPLUGIN_0.9.3 0.9.3 fu_hwids_get_type@LIBFWUPDPLUGIN_0.9.3 0.9.3 @@ -295,6 +403,7 @@ fu_io_channel_write_bytes@LIBFWUPDPLUGIN_1.2.2 1.2.2 fu_io_channel_write_raw@LIBFWUPDPLUGIN_1.2.2 1.2.2 fu_memcpy_safe@LIBFWUPDPLUGIN_1.3.1 1.3.1 + fu_memdup_safe@LIBFWUPDPLUGIN_1.5.6 1.5.6 fu_plugin_add_compile_version@LIBFWUPDPLUGIN_1.0.7 1.0.7 fu_plugin_add_firmware_gtype@LIBFWUPDPLUGIN_1.3.3 1.3.3 fu_plugin_add_report_metadata@LIBFWUPDPLUGIN_1.0.4 1.0.4 @@ -313,6 +422,7 @@ fu_plugin_get_config_value@LIBFWUPDPLUGIN_1.0.6 1.0.6 fu_plugin_get_config_value_boolean@LIBFWUPDPLUGIN_1.4.0 1.4.0 fu_plugin_get_data@LIBFWUPDPLUGIN_0.8.0 0.8.0 + fu_plugin_get_devices@LIBFWUPDPLUGIN_1.5.6 1.5.6 fu_plugin_get_dmi_value@LIBFWUPDPLUGIN_0.9.7 0.9.7 fu_plugin_get_enabled@LIBFWUPDPLUGIN_0.8.0 0.8.0 fu_plugin_get_hwid_replace_value@LIBFWUPDPLUGIN_1.3.3 1.3.3 @@ -339,12 +449,16 @@ fu_plugin_order_compare@LIBFWUPDPLUGIN_1.0.8 1.0.8 fu_plugin_request_recoldplug@LIBFWUPDPLUGIN_0.8.0 0.8.0 fu_plugin_runner_activate@LIBFWUPDPLUGIN_1.2.6 1.2.6 + fu_plugin_runner_add_security_attrs@LIBFWUPDPLUGIN_1.5.0 1.5.0 + fu_plugin_runner_backend_device_added@LIBFWUPDPLUGIN_1.5.6 1.5.6 + fu_plugin_runner_backend_device_changed@LIBFWUPDPLUGIN_1.5.6 1.5.6 fu_plugin_runner_clear_results@LIBFWUPDPLUGIN_0.8.0 0.8.0 fu_plugin_runner_coldplug@LIBFWUPDPLUGIN_0.8.0 0.8.0 fu_plugin_runner_coldplug_cleanup@LIBFWUPDPLUGIN_0.8.0 0.8.0 fu_plugin_runner_coldplug_prepare@LIBFWUPDPLUGIN_0.8.0 0.8.0 fu_plugin_runner_composite_cleanup@LIBFWUPDPLUGIN_1.0.9 1.0.9 fu_plugin_runner_composite_prepare@LIBFWUPDPLUGIN_1.0.9 1.0.9 + fu_plugin_runner_device_added@LIBFWUPDPLUGIN_1.5.0 1.5.0 fu_plugin_runner_device_created@LIBFWUPDPLUGIN_1.4.0 1.4.0 fu_plugin_runner_device_register@LIBFWUPDPLUGIN_0.9.7 0.9.7 fu_plugin_runner_device_removed@LIBFWUPDPLUGIN_1.1.2 1.1.2 @@ -362,6 +476,7 @@ fu_plugin_runner_update_reload@LIBFWUPDPLUGIN_1.1.2 1.1.2 fu_plugin_runner_usb_device_added@LIBFWUPDPLUGIN_1.0.2 1.0.2 fu_plugin_runner_verify@LIBFWUPDPLUGIN_0.8.0 0.8.0 + fu_plugin_security_changed@LIBFWUPDPLUGIN_1.5.0 1.5.0 fu_plugin_set_build_hash@LIBFWUPDPLUGIN_1.2.4 1.2.4 fu_plugin_set_coldplug_delay@LIBFWUPDPLUGIN_0.8.0 0.8.0 fu_plugin_set_compile_versions@LIBFWUPDPLUGIN_1.0.7 1.0.7 @@ -381,7 +496,16 @@ fu_quirks_lookup_by_id@LIBFWUPDPLUGIN_1.0.1 1.0.1 fu_quirks_lookup_by_id_iter@LIBFWUPDPLUGIN_1.3.3 1.3.3 fu_quirks_new@LIBFWUPDPLUGIN_1.0.1 1.0.1 + fu_security_attrs_append@LIBFWUPDPLUGIN_1.5.0 1.5.0 + fu_security_attrs_calculate_hsi@LIBFWUPDPLUGIN_1.5.0 1.5.0 + fu_security_attrs_depsolve@LIBFWUPDPLUGIN_1.5.0 1.5.0 + fu_security_attrs_get_all@LIBFWUPDPLUGIN_1.5.0 1.5.0 + fu_security_attrs_get_type@LIBFWUPDPLUGIN_1.5.0 1.5.0 + fu_security_attrs_new@LIBFWUPDPLUGIN_1.5.0 1.5.0 + fu_security_attrs_remove_all@LIBFWUPDPLUGIN_1.5.0 1.5.0 + fu_security_attrs_to_variant@LIBFWUPDPLUGIN_1.5.0 1.5.0 fu_smbios_get_data@LIBFWUPDPLUGIN_1.0.0 1.0.0 + fu_smbios_get_integer@LIBFWUPDPLUGIN_1.5.0 1.5.0 fu_smbios_get_string@LIBFWUPDPLUGIN_1.0.0 1.0.0 fu_smbios_get_type@LIBFWUPDPLUGIN_1.0.0 1.0.0 fu_smbios_new@LIBFWUPDPLUGIN_1.0.0 1.0.0 @@ -397,12 +521,16 @@ fu_udev_device_get_dev@LIBFWUPDPLUGIN_1.1.2 1.1.2 fu_udev_device_get_device_file@LIBFWUPDPLUGIN_1.3.1 1.3.1 fu_udev_device_get_devtype@LIBFWUPDPLUGIN_1.4.5 1.4.5 + fu_udev_device_get_driver@LIBFWUPDPLUGIN_1.5.3 1.5.3 fu_udev_device_get_fd@LIBFWUPDPLUGIN_1.3.3 1.3.3 fu_udev_device_get_model@LIBFWUPDPLUGIN_1.1.2 1.1.2 + fu_udev_device_get_number@LIBFWUPDPLUGIN_1.5.0 1.5.0 fu_udev_device_get_parent_name@LIBFWUPDPLUGIN_1.4.5 1.4.5 fu_udev_device_get_revision@LIBFWUPDPLUGIN_1.1.2 1.1.2 fu_udev_device_get_slot_depth@LIBFWUPDPLUGIN_1.2.4 1.2.4 fu_udev_device_get_subsystem@LIBFWUPDPLUGIN_1.1.2 1.1.2 + fu_udev_device_get_subsystem_model@LIBFWUPDPLUGIN_1.5.0 1.5.0 + fu_udev_device_get_subsystem_vendor@LIBFWUPDPLUGIN_1.5.0 1.5.0 fu_udev_device_get_sysfs_attr@LIBFWUPDPLUGIN_1.4.5 1.4.5 fu_udev_device_get_sysfs_path@LIBFWUPDPLUGIN_1.1.2 1.1.2 fu_udev_device_get_type@LIBFWUPDPLUGIN_1.1.2 1.1.2 @@ -428,3 +556,14 @@ fu_usb_device_is_open@LIBFWUPDPLUGIN_1.0.3 1.0.3 fu_usb_device_new@LIBFWUPDPLUGIN_1.0.2 1.0.2 fu_usb_device_set_dev@LIBFWUPDPLUGIN_1.0.2 1.0.2 + fu_volume_check_free_space@LIBFWUPDPLUGIN_1.4.6 1.4.6 + fu_volume_get_id@LIBFWUPDPLUGIN_1.4.6 1.4.6 + fu_volume_get_id_type@LIBFWUPDPLUGIN_1.5.2 1.5.2 + fu_volume_get_mount_point@LIBFWUPDPLUGIN_1.4.6 1.4.6 + fu_volume_get_type@LIBFWUPDPLUGIN_1.4.6 1.4.6 + fu_volume_is_encrypted@LIBFWUPDPLUGIN_1.5.1 1.5.1 + fu_volume_is_internal@LIBFWUPDPLUGIN_1.5.2 1.5.2 + fu_volume_is_mounted@LIBFWUPDPLUGIN_1.4.6 1.4.6 + fu_volume_locker@LIBFWUPDPLUGIN_1.4.6 1.4.6 + fu_volume_mount@LIBFWUPDPLUGIN_1.4.6 1.4.6 + fu_volume_unmount@LIBFWUPDPLUGIN_1.4.6 1.4.6 diff -Nru fwupd-1.4.5/debian/lintian/fwupd fwupd-1.5.8/debian/lintian/fwupd --- fwupd-1.4.5/debian/lintian/fwupd 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/debian/lintian/fwupd 2021-03-31 20:08:32.000000000 +0000 @@ -9,3 +9,7 @@ fwupd: executable-not-elf-or-script usr/libexec/fwupd/efi/*.efi fwupd: portable-executable-missing-security-features usr/libexec/fwupd/efi/*.efi SafeSEH fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_modem_manager.so +fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_pci_bcr.so +fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_pci_mei.so +fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_iommu.so +fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_msr.so diff -Nru fwupd-1.4.5/debian/patches/0001-Tweak-the-SBAT-output-for-a-vendor-string.patch fwupd-1.5.8/debian/patches/0001-Tweak-the-SBAT-output-for-a-vendor-string.patch --- fwupd-1.4.5/debian/patches/0001-Tweak-the-SBAT-output-for-a-vendor-string.patch 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/debian/patches/0001-Tweak-the-SBAT-output-for-a-vendor-string.patch 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,29 @@ +From d99074c3741ca9d30802d419d997bb90e24ea96a Mon Sep 17 00:00:00 2001 +From: Steve McIntyre <93sam@debian.org> +Date: Fri, 26 Mar 2021 15:06:08 +0000 +Subject: [PATCH] Tweak the SBAT output for a vendor string + +The format is meant to be "." with a period as a +separator. + +Signed-off-by: Steve McIntyre <93sam@debian.org> +--- + plugins/uefi-capsule/efi/generate_sbat.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/plugins/uefi-capsule/efi/generate_sbat.py b/plugins/uefi-capsule/efi/generate_sbat.py +index 18f7c4c7..1f12ca11 100755 +--- a/plugins/uefi-capsule/efi/generate_sbat.py ++++ b/plugins/uefi-capsule/efi/generate_sbat.py +@@ -51,7 +51,7 @@ def _generate_sbat(args): + + # distro specifics, falling back to the project defaults + sfd.write( +- "{0}-{1},{2},{3},{4},{5},{6}\n".format( ++ "{0}.{1},{2},{3},{4},{5},{6}\n".format( + args.project_name, + args.sbat_distro_id, + args.sbat_distro_generation or args.sbat_generation, +-- +2.25.1 + diff -Nru fwupd-1.4.5/debian/patches/series fwupd-1.5.8/debian/patches/series --- fwupd-1.4.5/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/debian/patches/series 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +0001-Tweak-the-SBAT-output-for-a-vendor-string.patch diff -Nru fwupd-1.4.5/debian/rules fwupd-1.5.8/debian/rules --- fwupd-1.4.5/debian/rules 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/debian/rules 2021-03-31 20:08:32.000000000 +0000 @@ -6,28 +6,61 @@ export DEB_LDFLAGS_MAINT_STRIP=-Wl,-Bsymbolic-functions #GPGME needs this for proper building on 32 bit archs -ifeq "$(DEB_HOST_ARCH_BITS)" "32" +ifeq ($(DEB_HOST_ARCH_BITS),32) export DEB_CFLAGS_MAINT_APPEND = -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE endif +CONFARGS = + ifneq ($(CI),) - export CI=--werror --wrap-mode=default + CONFARGS += --werror --wrap-mode=default endif -regenerate_control: - OS=debian-x86_64 ./contrib/ci/generate_debian.py - SB_STYLE := debian deb_version := $(shell dpkg-parsechangelog --show-field Version) ifeq (yes,$(shell dpkg-vendor --derives-from Ubuntu && echo yes)) SB_STYLE := ubuntu tar_name := fwupd_$(deb_version)_$(DEB_HOST_ARCH).tar.gz - export FLASHROM=-Dplugin_flashrom=false + CONFARGS += -Dplugin_flashrom=false + CONFARGS += -Defi_sbat_distro_id=ubuntu + CONFARGS += -Defi_sbat_distro_summary=Ubuntu + CONFARGS += -Defi_sbat_distro_pkgname=fwupd + CONFARGS += -Defi_sbat_distro_version=$(deb_version) + CONFARGS += -Defi_sbat_distro_url="https://launchpad.net/ubuntu/+source/fwupd" else TMPLDIR := debian/fwupd-$(DEB_HOST_ARCH)-signed-template/usr/share/code-signing/fwupd-$(DEB_HOST_ARCH)-signed-template - export FLASHROM=-Dplugin_flashrom=true + ifneq ($(DEB_HOST_ARCH_CPU),ia64) + CONFARGS += -Dplugin_flashrom=true + else + CONFARGS += -Dplugin_flashrom=false + endif + CONFARGS += -Defi_sbat_distro_id=debian + CONFARGS += -Defi_sbat_distro_summary=Debian + CONFARGS += -Defi_sbat_distro_pkgname=fwupd + CONFARGS += -Defi_sbat_distro_version=$(deb_version) + CONFARGS += -Defi_sbat_distro_url="https://tracker.debian.org/pkg/fwupd" +endif + +ifeq (yes,$(shell pkg-config --exists libsmbios_c && echo yes)) + CONFARGS += -Dplugin_dell=true +else + CONFARGS += -Dplugin_dell=false +endif + +ifeq (yes,$(shell pkg-config --exists efivar && echo yes)) + CONFARGS += -Dplugin_uefi_capsule=true +else + CONFARGS += -Dplugin_uefi_capsule=false endif +ifneq ($(filter $(DEB_HOST_ARCH_CPU),i386 amd64),) + CONFARGS += -Dplugin_msr=true +else + CONFARGS += -Dplugin_msr=false +endif + +CONFARGS += -Dplugin_dummy=true -Dgtkdoc=true -Dsupported_build=true + %: dh $@ --with gir @@ -39,30 +72,22 @@ endif override_dh_auto_configure: - if pkg-config --exists libsmbios_c; then \ - export DELL="-Dplugin_dell=true"; \ - else \ - export DELL="-Dplugin_dell=false"; \ - fi; \ - if pkg-config --exists efivar; then \ - export UEFI="-Dplugin_uefi=true -Dplugin_redfish=true -Dplugin_nvme=true"; \ - else \ - export UEFI="-Dplugin_uefi=false -Dplugin_redfish=false -Dplugin_nvme=false"; \ - fi; \ - dh_auto_configure -- $$UEFI $$DELL $$FLASHROM $$CI -Dplugin_dummy=true -Dgtkdoc=true + dh_auto_configure -- $(CONFARGS) override_dh_install: find debian/tmp/usr -type f -name "*a" -print | xargs rm -f - sed -i 's,wheel,sudo,' ./debian/tmp/usr/share/polkit-1/rules.d/org.freedesktop.fwupd.rules + sed -i 's,wheel,sudo,' debian/tmp/usr/share/polkit-1/rules.d/org.freedesktop.fwupd.rules dh_install #install the EFI binaries if needed - if [ -d debian/tmp/usr/libexec/fwupd/efi/ ]; then \ - dh_install -pfwupd usr/libexec/fwupd/efi ;\ - fi + [ ! -d debian/tmp/usr/libexec/fwupd/efi/ ] || dh_install -pfwupd usr/libexec/fwupd/efi + #install MSR conf if needed (depending on distro) + [ ! -d debian/tmp/usr/lib/modules-load.d ] || dh_install -pfwupd usr/lib/modules-load.d + [ ! -d debian/tmp/lib/modules-load.d ] || dh_install -pfwupd lib/modules-load.d dh_missing -a --fail-missing #this is placed in fwupd-tests rm -f debian/fwupd/usr/lib/*/fwupd-plugins-3/libfu_plugin_test.so + rm -f debian/fwupd/usr/lib/*/fwupd-plugins-3/libfu_plugin_test_ble.so rm -f debian/fwupd/usr/lib/*/fwupd-plugins-3/libfu_plugin_invalid.so rm -f debian/fwupd/etc/fwupd/remotes.d/fwupd-tests.conf @@ -73,32 +98,32 @@ cp debian/README.Debian $(TMPLDIR)/source-template/debian find $(TMPLDIR)/source-template/debian -type f | xargs sed -i "s,SIGNARCH,$(DEB_HOST_ARCH)," find $(TMPLDIR)/source-template/debian -type f | xargs sed -i "s,SIGNVERSION,$(deb_version)," - for file in $$(find $(TMPLDIR)/source-template/debian -type f -name *SIGNARCH*); do file1=$$(echo $$file | sed "s,SIGNARCH,$(DEB_HOST_ARCH),"); mv -v $$file $$file1; done + set -e; for file in $$(find $(TMPLDIR)/source-template/debian -type f -name '*SIGNARCH*'); do \ + file1=$$(echo $$file | sed "s,SIGNARCH,$(DEB_HOST_ARCH),"); \ + mv -v $$file $$file1; \ + done install -m 0755 debian/fwupd.postinst $(TMPLDIR)/source-template/debian/fwupd-$(DEB_HOST_ARCH)-signed.postinst install -m 0755 debian/fwupd.postrm $(TMPLDIR)/source-template/debian/fwupd-$(DEB_HOST_ARCH)-signed.postrm - ./debian/gen_signing_changelog $(TMPLDIR)/source-template/debian fwupd $(DEB_HOST_ARCH) - ./debian/gen_signing_json $(TMPLDIR) fwupd ${DEB_HOST_ARCH} + debian/gen_signing_changelog $(TMPLDIR)/source-template/debian fwupd $(DEB_HOST_ARCH) + debian/gen_signing_json $(TMPLDIR) fwupd ${DEB_HOST_ARCH} endif override_dh_strip_nondeterminism: dh_strip_nondeterminism -Xfirmware-example.xml.gz +ifneq (yes,$(shell command -v valgrind >/dev/null 2>&1 && echo yes)) override_dh_auto_test: - if [ -x /usr/bin/valgrind ] ; then \ - dh_auto_test; \ - fi + : +endif override_dh_builddeb: dh_builddeb ifeq (ubuntu,$(SB_STYLE)) - if [ -d debian/tmp/usr/libexec/fwupd/efi/ ]; then \ - mkdir -p debian/fwupd-images/$(deb_version) ;\ - cp debian/tmp/usr/libexec/fwupd/efi/fwupd*.efi debian/fwupd-images/$(deb_version) ;\ - echo $(deb_version) > debian/fwupd-images/$(deb_version)/version ;\ - tar -C debian/fwupd-images -czvf ../$(tar_name) . ;\ - dpkg-distaddfile $(tar_name) raw-uefi - ;\ + set -e; if [ -d debian/tmp/usr/libexec/fwupd/efi/ ]; then \ + mkdir -p debian/fwupd-images/$(deb_version); \ + cp debian/tmp/usr/libexec/fwupd/efi/fwupd*.efi debian/fwupd-images/$(deb_version); \ + echo $(deb_version) > debian/fwupd-images/$(deb_version)/version; \ + tar -C debian/fwupd-images -czvf ../$(tar_name) .; \ + dpkg-distaddfile $(tar_name) raw-uefi -; \ fi endif - -override_dh_shlibdeps: - dh_shlibdeps $$DHSLIBS diff -Nru fwupd-1.4.5/debian/signing-template/control fwupd-1.5.8/debian/signing-template/control --- fwupd-1.4.5/debian/signing-template/control 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/debian/signing-template/control 2021-03-31 20:08:32.000000000 +0000 @@ -1,7 +1,9 @@ Source: fwupd-SIGNARCH-signed Priority: optional Maintainer: Debian EFI -Uploaders: Daniel Jared Dominguez , Steve McIntyre <93sam@debian.org>, Mario Limonciello +Uploaders: Steve McIntyre <93sam@debian.org>, + Matthias Klumpp , + Mario Limonciello Build-Depends: debhelper (>= 9.0.0), sbsigntool [amd64 arm64 armhf i386], fwupd (= SIGNVERSION) [SIGNARCH] Standards-Version: 4.1.3 Section: libs diff -Nru fwupd-1.4.5/debian/tests/ci fwupd-1.5.8/debian/tests/ci --- fwupd-1.4.5/debian/tests/ci 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/debian/tests/ci 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ #!/bin/sh set -e -sed "s,^BlacklistPlugins=.*,BlacklistPlugins=," -i /etc/fwupd/daemon.conf +sed "s,^DisabledPlugins=.*,DisabledPlugins=," -i /etc/fwupd/daemon.conf sed "s,^VerboseDomains=.*,VerboseDomains=*," -i /etc/fwupd/daemon.conf gnome-desktop-testing-runner fwupd diff -Nru fwupd-1.4.5/debian/tests/control fwupd-1.5.8/debian/tests/control --- fwupd-1.4.5/debian/tests/control 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/debian/tests/control 2021-03-31 20:08:32.000000000 +0000 @@ -1,2 +1,6 @@ Tests: ci Restrictions: needs-root + +Tests: libfwupd-dev +Depends: build-essential, libfwupd-dev, pkg-config +Restrictions: allow-stderr, superficial diff -Nru fwupd-1.4.5/debian/tests/libfwupd-dev fwupd-1.5.8/debian/tests/libfwupd-dev --- fwupd-1.4.5/debian/tests/libfwupd-dev 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/debian/tests/libfwupd-dev 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,38 @@ +#!/bin/sh +# Copyright 2020 Collabora Ltd. +# Copyright 2021 Simon McVittie +# SPDX-License-Identifier: LGPL-2.1-or-later + +set -eux + +WORKDIR="$(mktemp -d)" +trap 'cd /; rm -fr "$WORKDIR"' 0 INT QUIT ABRT PIPE TERM + +if [ -n "${DEB_HOST_GNU_TYPE:-}" ]; then + CROSS_COMPILE="$DEB_HOST_GNU_TYPE-" +else + CROSS_COMPILE= +fi + +CC="${CROSS_COMPILE}gcc" +PKG_CONFIG="${CROSS_COMPILE}pkg-config" + +cd "$WORKDIR" + +cat > trivial.c <<'EOF' +#undef NDEBUG +#include + +#include + +int main (void) +{ + assert (fwupd_error_to_string (FWUPD_ERROR_NOTHING_TO_DO) != NULL); + return 0; +} +EOF + +# Deliberately word-splitting pkg-config's output: +# shellcheck disable=SC2046 +"${CC}" -otrivial trivial.c $("${PKG_CONFIG}" --cflags --libs fwupd) +./trivial diff -Nru fwupd-1.4.5/docs/fwupd-docs.xml fwupd-1.5.8/docs/fwupd-docs.xml --- fwupd-1.4.5/docs/fwupd-docs.xml 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/docs/fwupd-docs.xml 2021-03-31 20:08:32.000000000 +0000 @@ -26,8 +26,10 @@ + + @@ -51,6 +53,8 @@ + + @@ -67,405 +71,10 @@ - - Plugin Tutorial - -
    - Introduction - - At the heart of fwupd is a plugin loader that gets run at startup, - when devices get hotplugged and when updates are done. - The idea is we have lots of small plugins that each do one thing, and - are ordered by dependencies against each other at runtime. - Using plugins we can add support for new hardware or new policies - without making big changes all over the source tree. - - - There are broadly 3 types of plugin methods: - - - - - Mechanism: Upload binary data - into a specific hardware device. - - - - - Policy: Control the system when - updates are happening, e.g. preventing the user from powering-off. - - - - - Helpers: Providing more - metadata about devices, for instance handling device quirks. - - - - - In general, building things out-of-tree isn't something that we think is - a very good idea; the API and ABI internal to fwupd is still - changing and there's a huge benefit to getting plugins upstream where - they can undergo review and be ported as the API adapts. - For this reason we don't install the plugin headers onto the system, - although you can of course just install the .so binary file - manually. - - - - A plugin only needs to define the vfuncs that are required, and the - plugin name is taken automatically from the suffix of the - .so file. - - - A sample plugin - -/* - * Copyright (C) 2017 Richard Hughes - */ - -#include <fu-plugin.h> -#include <fu-plugin-vfuncs.h> - -struct FuPluginData { - gpointer proxy; -}; - -void -fu_plugin_initialize (FuPlugin *plugin) -{ - fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_BEFORE, "dfu"); - fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); -} - -void -fu_plugin_destroy (FuPlugin *plugin) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - destroy_proxy (data->proxy); -} - -gboolean -fu_plugin_startup (FuPlugin *plugin, GError **error) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - data->proxy = create_proxy (); - if (data->proxy == NULL) { - g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, - "failed to create proxy"); - return FALSE; - } - return TRUE; -} - - - - - We have to define when our plugin is run in reference to other plugins, - in this case, making sure we run before the dfu plugin. - For most plugins it does not matter in what order they are run and - this information is not required. - -
    - -
    - Creating an abstract device - - This section shows how you would create a device which is exported - to the daemon and thus can be queried and updated by the client software. - The example here is all hardcoded, and a true plugin would have to - derive the details about the FuDevice from the hardware, - for example reading data from sysfs or /dev. - - - Example adding a custom device - -#include <fu-plugin.h> - -gboolean -fu_plugin_coldplug (FuPlugin *plugin, GError **error) -{ - g_autoptr(FuDevice) dev = NULL; - fu_device_set_id (dev, "dummy-1:2:3"); - fu_device_add_guid (dev, "2d47f29b-83a2-4f31-a2e8-63474f4d4c2e"); - fu_device_set_version (dev, "1.2.3"); - fu_device_get_version_lowest (dev, "1.2.2"); - fu_device_get_version_bootloader (dev, "0.1.2"); - fu_device_add_icon (dev, "computer"); - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); - fu_plugin_device_add (plugin, dev); - return TRUE; -} - - - - This shows a lot of the plugin architecture in action. Some notable points: - - - - - The device ID (dummy-1:2:3) has to be unique on the - system between all plugins, so including the plugin name as a - prefix is probably a good idea. - - - - - The GUID value can be generated automatically using - fu_device_add_guid(dev,"some-identifier") but is quoted - here explicitly. - The GUID value has to match the provides value in the - .metainfo.xml file for the firmware update to succeed. - - - - - Setting a display name and an icon is a good idea in case the - GUI software needs to display the device to the user. - Icons can be specified using a full path, although icon theme names - should be preferred for most devices. - - - - - The FWUPD_DEVICE_FLAG_UPDATABLE flag tells the client - code that the device is in a state where it can be updated. - If the device needs to be in a special mode (e.g. a bootloader) then - the FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER flag can also be - used. - If the update should only be allowed when there is AC power available - to the computer (i.e. not on battery) then - FWUPD_DEVICE_FLAG_REQUIRE_AC should be used as well. - There are other flags and the API documentation should be used when - choosing what flags to use for each kind of device. - - - - - Setting the lowest allows client software to refuse downgrading - the device to specific versions. - This is required in case the upgrade migrates some kind of data-store - so as to be incompatible with previous versions. - Similarly, setting the version of the bootloader (if known) allows - the firmware to depend on a specific bootloader version, for instance - allowing signed firmware to only be installable on hardware with - a bootloader new enough to deploy it - - - -
    - -
    - Mechanism Plugins - - Although it would be a wonderful world if we could update all hardware - using a standard shared protocol this is not the universe we live in. - Using a mechanism like DFU or UpdateCapsule means that fwupd will just - work without requiring any special code, but for the real world we need - to support vendor-specific update protocols with layers of backwards - compatibility. - - - When a plugin has created a device that is FWUPD_DEVICE_FLAG_UPDATABLE - we can ask the daemon to update the device with a suitable - .cab file. - When this is done the daemon checks the update for compatibility with - the device, and then calls the vfuncs to update the device. - - - - Updating a device - -gboolean -fu_plugin_update (FuPlugin *plugin, - FuDevice *dev, - GBytes *blob_fw, - FwupdInstallFlags flags, - GError **error) -{ - gsize sz = 0; - guint8 *buf = g_bytes_get_data (blob_fw, &sz); - /* write 'buf' of size 'sz' to the hardware */ - return TRUE; -} - - - - It's important to note that the blob_fw is the binary - firmware file (e.g. .dfu) and not - the .cab binary data. - - - If FWUPD_INSTALL_FLAG_FORCE is used then the usual checks - done by the flashing process can be relaxed (e.g. checking for quirks), - but please don't brick the users hardware even if they ask you to. - -
    - -
    - Policy Helpers - - For some hardware, we might want to do an action before or after - the actual firmware is squirted into the device. - This could be something as simple as checking the system battery - level is over a certain threshold, or it could be as complicated as - ensuring a vendor-specific GPIO is asserted when specific types - of hardware are updated. - - - - Running before a device update - -gboolean -fu_plugin_update_prepare (FuPlugin *plugin, FuDevice *device, GError **error) -{ - if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_REQUIRE_AC && !on_ac_power ()) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_AC_POWER_REQUIRED, - "Cannot install update " - "when not on AC power"); - return FALSE; - } - return TRUE; -} - - - - Running after a device update - -gboolean -fu_plugin_update_cleanup (FuPlugin *plugin, FuDevice *device, GError **error) -{ - return g_file_set_contents ("/var/lib/fwupd/something", - fu_device_get_id (device), -1, error); -} - - -
    - -
    - Detaching to bootloader mode - - Some hardware can only be updated in a special bootloader mode, which - for most devices can be switched to automatically. - In some cases the user to do something manually, for instance - re-inserting the hardware with a secret button pressed. - - - Before the device update is performed the fwupd daemon runs an optional - update_detach() vfunc which switches the device to - bootloader mode. - After the update (or if the update fails) an the daemon runs an - optional update_attach() vfunc which should switch the - hardware back to runtime mode. - Finally an optional update_reload() vfunc is run to - get the new firmware version from the hardware. - - - The optional vfuncs are only run - on the plugin currently registered to handle the device ID, although - the registered plugin can change during the attach and detach phases. - - - - Running before a device update - -gboolean -fu_plugin_update_detach (FuPlugin *plugin, FuDevice *device, GError **error) -{ - if (hardware_in_bootloader) - return TRUE; - return _device_detach(device, error); -} - - - - Running after a device update - -gboolean -fu_plugin_update_attach (FuPlugin *plugin, FuDevice *device, GError **error) -{ - if (!hardware_in_bootloader) - return TRUE; - return _device_attach(device, error); -} - - - - Running after a device update on success - -gboolean -fu_plugin_update_reload (FuPlugin *plugin, FuDevice *device, GError **error) -{ - g_autofree gchar *version = _get_version(plugin, device, error); - if (version == NULL) - return FALSE; - fu_device_set_version(device, version); - return TRUE; -} - - -
    - -
    - The Plugin Object Cache - - The fwupd daemon provides a per-plugin cache which allows objects - to be added, removed and queried using a specified key. - Objects added to the cache must be GObjects to enable the - cache objects to be properly refcounted. - -
    - -
    - Debugging a Plugin - - If the fwupd daemon is started with --plugin-verbose=$plugin - then the environment variable FWUPD_$PLUGIN_VERBOSE is - set process-wide. - This allows plugins to detect when they should output detailed debugging - information that would normally be too verbose to keep in the journal. - For example, using --plugin-verbose=logitech_hidpp would set - FWUPD_LOGITECH_HID_VERBOSE=1. - -
    - -
    - Using existing code to develop a plugin - - It is not usually possible to share a plugin codebase with - firmware update programs designed for other operating systems. - Matching the same rationale as the Linux kernel, trying to use one - code base between projects with a compatibility shim layer in-between - is real headache to maintain. - - - The general consensus is that trying to use a abstraction layer for - hardware is a very bad idea as you're not able to take advantage of the - platform specific helpers -- for instance quirk files and the custom - GType device creation. - The time the vendor saves by creating a shim layer and - importing existing source code into fwupd will be overtaken 100x by - upstream maintenance costs longer term, which isn't fair. - - - In a similar way, using C++ rather than GObject C means expanding the - test matrix to include clang in C++ mode and GNU g++ too. - It's also doubled the runtime requirements to now include both the C - standard library as well as the C++ standard library and increases the - dependency surface. - - - Most rewritten fwupd plugins at up to x10 smaller than the standalone - code as they can take advantage of helpers provided by fwupd rather - than re-implementing error handling, device quirking and data chunking. - -
    - -
    -
    + + API Index diff -Nru fwupd-1.4.5/docs/hsi.xml fwupd-1.5.8/docs/hsi.xml --- fwupd-1.4.5/docs/hsi.xml 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/docs/hsi.xml 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,893 @@ + + + + Host Security ID Specification + + + This specification is still in active development: it is incomplete, + subject to change, and may have errors; use this at your own risk. + It is based on publicly available information. + + + + + + + + + Introduction + + Not all system vendors prioritize building a secure platform. + The truth is that security costs money. + Vendors have to choose between saving a few cents on a bill-of-materials + by sharing a SPI chip, or correctly implementing BootGuard. + Discovering security vulnerabilities often takes an external researcher + filing a disclosure. + These disclosures are often technical in nature and difficult for an + average consumer to decipher. + + + The Linux Vendor Firmware Service (LVFS) could provide some + easy-to-understand information to + people buying hardware. + The service already knows a huge amount of information about machines + from signed reports uploaded to the LVFS and from analyzing firmware binaries. + However this information alone does not explain firmware security to the + user in a way they can actually interpret. + + + + + Other Tools + + Traditionally, figuring out the true security of your hardware and firmware + requires sifting through the marketing documentation provided by the + OEM and in many cases just “trusting” they did it right. + Tools such as Chipsec can check the hardware configuration, but they do + not work out of the box and use technical jargon that an average user + cannot interpret. + Unfortunately, running a tool like Chipsec requires that you actively + turn off some security layers such as UEFI Secure Boot, and allow 3rd + party unsigned kernel modules to be loaded. + + + + + Verifying Host Firmware Security + + To start out some core protections must be assigned a relative importance. + Then an evaluation must be done to determine how each vendor is conforming + to the model. + For instance, a user might say that for home use any hardware the bare + minimum security level (HSI:1) is good enough. + For a work laptop the company IT department might restrict the choice of + models to anything meeting the criteria of level HSI:2 or + above. + A journalist or a security researcher would only buy level HSI:3 + and above. + The reality is that HSI:4 is going to be more expensive + than some unbranded hardware that is rated HSI:0. + + + To be trusted, this rating information should be distributed in a + centralized agnostic database such as the LVFS. + + + Of course, tools need to detect implementation errors, and to verify that + the model that is measured does indeed match the HSI level advertised by + the LVFS. + Some existing compliance solutions place the burden on the OEM to define + what firmware security has been implemented, which is easy to get wrong + and in some cases impossible to verify. + + + For this reason HSI will only measure security protections that can be + verified by the end user without requiring any extra hardware to be + connected, additional software to be installed, or disabling any existing + security layers to measure. + + + The HSI specification is primarily designed for laptop and desktop + hardware, although some tests may still make sense + on server or embedded hardware. + It is not expected that non-consumer hardware will publish an HSI number. + + + + + Runtime Behavior + + Orthogonal to the security features provided by the firmware there are + other security considerations related to the firmware which may require + internet access to discover or that runtime OS changes directly affect + the security of the firmware. + It would not make sense to have have updates on the LVFS + as a requirement for a specific security level as this would mean + offline the platform might be a higher level initially but as soon as + it is brought online it is downgraded which would be really confusing to + users. + The core security level will not change at + Operating System runtime, but the suffix may. + + + + + HSI:0 (Insecure) + + The lowest security level with little or no detected firmware protections. + This is the default security level if no tests can be run or some tests + in the next security level have failed. + + + + + HSI:1 (Critical) + + This security level corresponds to the most basic of security protections + considered essential by security professionals. + Any failures at this level would have critical security impact and could + likely be used to compromise the system firmware without physical access. + + + + + HSI:3 (Theoretical) + + This security level corresponds to firmware security issues that pose a + theoretical concern or where any exploit would be difficult or + impractical to use. + At this level various technologies may be employed to protect the boot + process from modification by an attacker with local access to the machine. + + + + + HSI:4 (System Protection) + + This security level corresponds to out-of-band protection of the system + firmware perhaps including recovery. + + + + + HSI:5 (System Attestation) + + This security level corresponds to out-of-band attestation of the system + firmware. + There are currently no tests implemented for HSI:5 and so this security + level cannot yet be obtained. + + + + + HSI Runtime Suffix <code>!</code> + + A runtime security issue detected. + + + + + UEFI + Secure Boot has been turned off. v1.5.0 + + + + + The kernel is + tainted due to a non-free module or critical firmware issue. v1.5.0 + + + + + The kernel is not + locked down. v1.5.0 + + + + + Unencrypted + swap partition. v1.5.0 + + + + + The installed fwupd is running with + custom or modified plugins. v1.5.0 + + + + + + + Tests included in fwupd + + The set of tests is currently x86 UEFI-centric, but will be expanded + in the future for various ARM or RISC-V firmware protections as required. + Where the requirement is architecture or processor specific it has been noted. + + + + + UEFI SecureBoot + + UEFI Secure boot is a verification mechanism for ensuring that code + launched by firmware is trusted. + + + Secure Boot requires that each binary loaded at boot is validated + against trusted certifictes. + + + + + For HSI-1 SecureBoot must be available for use on UEFI systems. + v1.5.0 + + + + + + See also: + + + + UEFI Wiki Entry + + + + + + + + + UEFI PK + + UEFI defines a platform key for the system. + This should not be a test key, e.g. ``DO NOT TRUST - AMI Test PK`` + + + + + For HSI-1 a test key must not be enrolled. + v1.5.0 + + + + + + See also: + + + + UEFI Testing Wiki Entry + + + + + + + + + BIOS Write Enable (BWE) + + Intel hardware provides this mechanism to protect the SPI ROM chip + located on the motherboard from being overwritten by the operating system. + + + + + For HSI-1 the ``BIOSWE`` bit must be unset. v1.5.0 + + + + + + See also: + + + + Intel C200 Datasheet + + + + + + + + + BIOS Lock Enable (BLE) + + If the lock bit is set then System Management Interrupts (SMIs) are + raised when setting BIOS Write Enable. + The BLE` bit must be enabled in the PCH otherwise + BIOSWE can easily be unset. + + + + + For HSI-1 this should be set. v1.5.0 + + + + + + See also: + + + + Intel C200 Datasheet + + + + + + + + + SMM Bios Write Protect (SMM_BWP) + + This bit set defines when the BIOS region can be written by the host. + The SMM_BWP bit must be set to make the BIOS region + non-writable unless all processors are in system management mode. + + + + + For HSI-1 this should be set v1.5.0 + + + + + + See also: + + + + Intel C200 Datasheet + + + + + + + + + TPM 2.0 Present + + A TPM securely stores platform specific secrets that can only be divulged + to trusted consumers in a secure environment. + + + + + For HSI-1 this should be available for use by the OS or applications v1.5.0 + + + + + + See also: + + + + Wikipedia TPM Article + + + + + + + + + ME not in manufacturing mode + + There have been some unfortunate cases of the ME being distributed in + manufacturing mode. + In manufacturing mode many features from the ME can be interacted with + that decrease the platform’s security. + + + + + For HSI-1 this should be unset v1.5.0 + + + + + + See also: + + + + ME Manufacturing Mode: obscured dangers + + + + + Intel security advisory SA-00086 + + + + + + + + + ME Flash Descriptor Override + + The Flash Descriptor Security Override Strap is not accessible to end + users on consumer boards and Intel stresses that this is for debugging only. + + + + + For HSI-1 this should be unset v1.5.0 + + + + + + See also: + + + + Chromium documentation for Intel ME + + + + + + + + + CSME Version + + Converged Security and Manageability Engine is a standalone management + module that can manage and control some local devices without the host + CPU involvement. + The CSME lives in the PCH and can only be updated by the OEM vendor. + The version of the CSME module can be checked to detect the most common + and serious vulnerabilities. + + + + + For HSI-1 this should not be vulnerable to CVE-2017-5705, CVE-2017-5708, + CVE-2017-5711, CVE-2017-5712, CVE-2017-5711, CVE-2017-5712, CVE-2017-5706, + CVE-2017-5709, CVE-2017-5707 or CVE-2017-5710 v1.5.0 + + + + + + See also: + + + + Intel CSME Security Review Cumulative Update + + + + + + + + + Intel DCI + + Newer Intel CPUs support debugging over USB3 via a proprietary Direct + Connection Interface (DCI) with the use of off-the-shelf hardware. + DCI should always be disabled and locked on production hardware. + + + + + For HSI-1 this should be disabled. v1.5.0 + + + + + For HSI-2 this should be locked. v1.5.0 + + + + + + See also: + + + + Intel Direct Connect Interface + + + + + Chipsec 4xxlp register definitions + + + + + RISC-V EDK PCH register definitions + + + + + + + + + PCR0 TPM Event Log Reconstruction + + The TPM event log records which events are registered for the PCR0 hash. + When reconstructed the event log values should always match the TPM PCR0. + If extra events are included in the event log, or some are missing, + the reconstitution will fail. + + + + + For HSI-2 this should match the TPM-provided PCR0 v1.5.0 + + + + + + See also: + + + + Linux Kernel TPM Documentation + + + + + + + + Pre-boot DMA protection + + The IOMMU on modern systems is used to mitigate against DMA attacks. + All I/O for devices capable of DMA is mapped into a private virtual + memory region. + The ACPI DMAR table is used to set up pre-boot DMA protection which + eliminates some firmware attacks. + + + + + For HSI-2 this should be available v1.5.0 + + + + + + See also: + + + + Wikipedia IOMMU article + + + + + + + + + Intel BootGuard + + BootGuard is a processor feature that prevents the machine from running + firmware images not released by the system manufacturer. + It forms a root-of-trust by fusing in cryptographic keys into the processor + itself that are used to verify the Authenticated Code Modules found in + the SPI flash. + + + + + For HSI-1 verified boot must be enabled with ACM protection. v1.5.0 + + + + + For HSI-2 the error enforcement policy must be set to “immediate shutdown”. v1.5.0 + + + + + + See also: + + + + Coreboot documentation + + + + + + + + + Suspend to RAM disabled + + Suspend to Ram (S3) keeps the raw contents of the DRAM refreshed when + the system is asleep. + This means that the memory modules can be physically removed and the + contents recovered, or a cold boot attack can be performed with a USB device. + + + + + For HSI-3 the firmware should be configured to prefer using suspend + to idle instead of suspend to ram or to not offer suspend to + RAM. v1.5.0 + + + + + + See also: + + + + Wikipedia article on cold boot attacks + + + + + + + + + Intel CET Available + + Control enforcement technology is available on new Intel platforms and + prevents exploits from hijacking the control-flow transfer instructions + for both forward-edge (indirect call/jmp) and back-edge transfer (ret). + + + + + For HSI-3 this should be available and enabled v1.5.0 + + + + + + See also: + + + + Intel CET Technology Preview + + + + + + + + + DRAM memory encryption + + TME (Intel) or TSME (AMD) is used by the firmware on supported SOCs to + encrypt all data on external memory buses. + It mitigates against an attacker being able to capture memory data while + the system is running or to capture memory by removing a DRAM chip. + + + + + For HSI-4 this should be supported and enabled v1.5.0 + + + + + + See also: + + + + Intel TME Press Release + + + + + WikiChip SME Overview + + + + + + + + Supervisor Mode Access Prevention + + Without Supervisor Mode Access Prevention, the supervisor code usually + has full read and write access to user-space memory mappings. + This can make exploits easier to write, as it allows the kernel to + access user-space memory when it did not intend to. + + + + + For HSI-4 the SMAP and SMEP features should be available on the CPU. v1.5.0 + + + + + + See also: + + + + Wikipedia SMAP Article + + + + + + + + + Kernel DMA protection + + The IOMMU on modern systems is used to mitigate against DMA attacks. + All I/O for devices capable of DMA is mapped into a private virtual + memory region. + Common implementations are Intel VT-d and AMD-Vi. + + + + + For HSI-2 this should be available for use. v1.5.0 + + + + + + See also: + + + + Wikipedia IOMMU article + + + + + + + + + Suspend-to-Idle + + The platform should be set up with Suspend-to-Idle as the default S3 + sleep state. + + + + + For HSI-3 this should be set v1.5.0 + + + + + + + Conclusion + + Any system with a Host Security ID of 0 can easily be + modified from userspace. + PCs with confidential documents should have a HSI:3 or + higher level of protection. + In a graphical tool that would show details about the computer (such as + GNOME Control Center’s details tab) the OS could display a field + indicating Host Security ID. + The ID should be shown with an alert color if the security is not at + least HSI:1 or the suffix is !. + + + On Linux fwupd is used to enumerate and update firmware. + It exports a property HostSecurityId and a + GetHostSecurityAttrs() method. + The attributes are supposed to represent the system as a whole + but individual (internal) devices are able to make a claim that they + worsened the state of the security of the system. + Certain attributes can “obsolete” other attributes. + An example is BIOSGuard will set obsoletes to org.intel.prx. + + + A plugin method gets called on each plugin which adds attributes directly + from the hardware or kernel. + Several attributes may be dependent upon the kernel performing measurements + and it will take time for these to be upstreamed. + In some cases security level measurements will only be possible on systems + with a newer kernel. + + + The long term goal is to increase the HSI:x level of systems + being sold to consumers. + By making some of the HSI:x attributes part of the LVFS + uploaded report we can allow users to compare vendors and models before + purchasing hardware. + + + + + Intentional Omissions + + + Intel SGX + + This is not widely used as it has several high severity security issues. + + + + Intel MPX + + MPX support was removed from GCC and the Linux kernel in 2019 and it is + now considered obsolete. + + + + + Further Work + + More internal and external devices should be factored into the security + equation. + For now the focus for further tests should be around internal device + firmware as it is what can be most directly controlled by fwupd and the + hardware manufacturer. + + + Security conscious manufacturers are actively participating in the + development of future initiatives in the Trusted Computing Group (TCG). + As those become ratified standards that are available in hardware, + there are opportunities for synergy with this specification. + + + + + diff -Nru fwupd-1.4.5/docs/meson.build fwupd-1.5.8/docs/meson.build --- fwupd-1.4.5/docs/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/docs/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -5,6 +5,11 @@ join_paths(meson.source_root(), 'libfwupdplugin'), join_paths(meson.build_root(), 'libfwupd'), join_paths(meson.build_root(), 'libfwupdplugin'), + join_paths(meson.current_source_dir()), + ], + content_files : [ + 'tutorial.xml', + 'hsi.xml', ], main_xml : 'fwupd-docs.xml', install : true diff -Nru fwupd-1.4.5/docs/tutorial.xml fwupd-1.5.8/docs/tutorial.xml --- fwupd-1.4.5/docs/tutorial.xml 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/docs/tutorial.xml 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,402 @@ + + + + Plugin Tutorial + +
    + Introduction + + At the heart of fwupd is a plugin loader that gets run at startup, + when devices get hotplugged and when updates are done. + The idea is we have lots of small plugins that each do one thing, and + are ordered by dependencies against each other at runtime. + Using plugins we can add support for new hardware or new policies + without making big changes all over the source tree. + + + There are broadly 3 types of plugin methods: + + + + + Mechanism: Upload binary data + into a specific hardware device. + + + + + Policy: Control the system when + updates are happening, e.g. preventing the user from powering-off. + + + + + Helpers: Providing more + metadata about devices, for instance handling device quirks. + + + + + In general, building things out-of-tree isn't something that we think is + a very good idea; the API and ABI internal to fwupd is still + changing and there's a huge benefit to getting plugins upstream where + they can undergo review and be ported as the API adapts. + For this reason we don't install the plugin headers onto the system, + although you can of course just install the .so binary file + manually. + + + + A plugin only needs to define the vfuncs that are required, and the + plugin name is taken automatically from the suffix of the + .so file. + + + A sample plugin + +/* +* Copyright (C) 2017 Richard Hughes +*/ + +#include <fu-plugin.h> +#include <fu-plugin-vfuncs.h> + +struct FuPluginData { +gpointer proxy; +}; + +void +fu_plugin_initialize (FuPlugin *plugin) +{ +fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_BEFORE, "dfu"); +fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); +} + +void +fu_plugin_destroy (FuPlugin *plugin) +{ +FuPluginData *data = fu_plugin_get_data (plugin); +destroy_proxy (data->proxy); +} + +gboolean +fu_plugin_startup (FuPlugin *plugin, GError **error) +{ +FuPluginData *data = fu_plugin_get_data (plugin); +data->proxy = create_proxy (); +if (data->proxy == NULL) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, + "failed to create proxy"); + return FALSE; +} +return TRUE; +} + + + + + We have to define when our plugin is run in reference to other plugins, + in this case, making sure we run before the dfu plugin. + For most plugins it does not matter in what order they are run and + this information is not required. + +
    + +
    + Creating an abstract device + + This section shows how you would create a device which is exported + to the daemon and thus can be queried and updated by the client software. + The example here is all hardcoded, and a true plugin would have to + derive the details about the FuDevice from the hardware, + for example reading data from sysfs or /dev. + + + Example adding a custom device + +#include <fu-plugin.h> + +gboolean +fu_plugin_coldplug (FuPlugin *plugin, GError **error) +{ +g_autoptr(FuDevice) dev = NULL; +fu_device_set_id (dev, "dummy-1:2:3"); +fu_device_add_guid (dev, "2d47f29b-83a2-4f31-a2e8-63474f4d4c2e"); +fu_device_set_version (dev, "1.2.3"); +fu_device_get_version_lowest (dev, "1.2.2"); +fu_device_get_version_bootloader (dev, "0.1.2"); +fu_device_add_icon (dev, "computer"); +fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); +fu_plugin_device_add (plugin, dev); +return TRUE; +} + + + + This shows a lot of the plugin architecture in action. Some notable points: + + + + + The device ID (dummy-1:2:3) has to be unique on the + system between all plugins, so including the plugin name as a + prefix is probably a good idea. + + + + + The GUID value can be generated automatically using + fu_device_add_guid(dev,"some-identifier") but is quoted + here explicitly. + The GUID value has to match the provides value in the + .metainfo.xml file for the firmware update to succeed. + + + + + Setting a display name and an icon is a good idea in case the + GUI software needs to display the device to the user. + Icons can be specified using a full path, although icon theme names + should be preferred for most devices. + + + + + The FWUPD_DEVICE_FLAG_UPDATABLE flag tells the client + code that the device is in a state where it can be updated. + If the device needs to be in a special mode (e.g. a bootloader) then + the FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER flag can also be + used. + If the update should only be allowed when there is AC power available + to the computer (i.e. not on battery) then + FWUPD_DEVICE_FLAG_REQUIRE_AC should be used as well. + There are other flags and the API documentation should be used when + choosing what flags to use for each kind of device. + + + + + Setting the lowest allows client software to refuse downgrading + the device to specific versions. + This is required in case the upgrade migrates some kind of data-store + so as to be incompatible with previous versions. + Similarly, setting the version of the bootloader (if known) allows + the firmware to depend on a specific bootloader version, for instance + allowing signed firmware to only be installable on hardware with + a bootloader new enough to deploy it + + + +
    + +
    + Mechanism Plugins + + Although it would be a wonderful world if we could update all hardware + using a standard shared protocol this is not the universe we live in. + Using a mechanism like DFU or UpdateCapsule means that fwupd will just + work without requiring any special code, but for the real world we need + to support vendor-specific update protocols with layers of backwards + compatibility. + + + When a plugin has created a device that is FWUPD_DEVICE_FLAG_UPDATABLE + we can ask the daemon to update the device with a suitable + .cab file. + When this is done the daemon checks the update for compatibility with + the device, and then calls the vfuncs to update the device. + + + + Updating a device + +gboolean +fu_plugin_update (FuPlugin *plugin, + FuDevice *dev, + GBytes *blob_fw, + FwupdInstallFlags flags, + GError **error) +{ +gsize sz = 0; +guint8 *buf = g_bytes_get_data (blob_fw, &sz); +/* write 'buf' of size 'sz' to the hardware */ +return TRUE; +} + + + + It's important to note that the blob_fw is the binary + firmware file (e.g. .dfu) and not + the .cab binary data. + + + If FWUPD_INSTALL_FLAG_FORCE is used then the usual checks + done by the flashing process can be relaxed (e.g. checking for quirks), + but please don't brick the users hardware even if they ask you to. + +
    + +
    + Policy Helpers + + For some hardware, we might want to do an action before or after + the actual firmware is squirted into the device. + This could be something as simple as checking the system battery + level is over a certain threshold, or it could be as complicated as + ensuring a vendor-specific GPIO is asserted when specific types + of hardware are updated. + + + + Running before a device update + +gboolean +fu_plugin_update_prepare (FuPlugin *plugin, FuDevice *device, GError **error) +{ +if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_REQUIRE_AC && !on_ac_power ()) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_AC_POWER_REQUIRED, + "Cannot install update " + "when not on AC power"); + return FALSE; +} +return TRUE; +} + + + + Running after a device update + +gboolean +fu_plugin_update_cleanup (FuPlugin *plugin, FuDevice *device, GError **error) +{ +return g_file_set_contents ("/var/lib/fwupd/something", + fu_device_get_id (device), -1, error); +} + + +
    + +
    + Detaching to bootloader mode + + Some hardware can only be updated in a special bootloader mode, which + for most devices can be switched to automatically. + In some cases the user to do something manually, for instance + re-inserting the hardware with a secret button pressed. + + + Before the device update is performed the fwupd daemon runs an optional + update_detach() vfunc which switches the device to + bootloader mode. + After the update (or if the update fails) an the daemon runs an + optional update_attach() vfunc which should switch the + hardware back to runtime mode. + Finally an optional update_reload() vfunc is run to + get the new firmware version from the hardware. + + + The optional vfuncs are only run + on the plugin currently registered to handle the device ID, although + the registered plugin can change during the attach and detach phases. + + + + Running before a device update + +gboolean +fu_plugin_update_detach (FuPlugin *plugin, FuDevice *device, GError **error) +{ +if (hardware_in_bootloader) + return TRUE; +return _device_detach(device, error); +} + + + + Running after a device update + +gboolean +fu_plugin_update_attach (FuPlugin *plugin, FuDevice *device, GError **error) +{ +if (!hardware_in_bootloader) + return TRUE; +return _device_attach(device, error); +} + + + + Running after a device update on success + +gboolean +fu_plugin_update_reload (FuPlugin *plugin, FuDevice *device, GError **error) +{ +g_autofree gchar *version = _get_version(plugin, device, error); +if (version == NULL) + return FALSE; +fu_device_set_version(device, version); +return TRUE; +} + + +
    + +
    + The Plugin Object Cache + + The fwupd daemon provides a per-plugin cache which allows objects + to be added, removed and queried using a specified key. + Objects added to the cache must be GObjects to enable the + cache objects to be properly refcounted. + +
    + +
    + Debugging a Plugin + + If the fwupd daemon is started with --plugin-verbose=$plugin + then the environment variable FWUPD_$PLUGIN_VERBOSE is + set process-wide. + This allows plugins to detect when they should output detailed debugging + information that would normally be too verbose to keep in the journal. + For example, using --plugin-verbose=logitech_hidpp would set + FWUPD_LOGITECH_HID_VERBOSE=1. + +
    + +
    + Using existing code to develop a plugin + + It is not usually possible to share a plugin codebase with + firmware update programs designed for other operating systems. + Matching the same rationale as the Linux kernel, trying to use one + code base between projects with a compatibility shim layer in-between + is real headache to maintain. + + + The general consensus is that trying to use a abstraction layer for + hardware is a very bad idea as you're not able to take advantage of the + platform specific helpers -- for instance quirk files and the custom + GType device creation. + The time the vendor saves by creating a shim layer and + importing existing source code into fwupd will be overtaken 100x by + upstream maintenance costs longer term, which isn't fair. + + + In a similar way, using C++ rather than GObject C means expanding the + test matrix to include clang in C++ mode and GNU g++ too. + It's also doubled the runtime requirements to now include both the C + standard library as well as the C++ standard library and increases the + dependency surface. + + + Most rewritten fwupd plugins at up to x10 smaller than the standalone + code as they can take advantage of helpers provided by fwupd rather + than re-implementing error handling, device quirking and data chunking. + +
    + +
    +
    diff -Nru fwupd-1.4.5/.editorconfig fwupd-1.5.8/.editorconfig --- fwupd-1.4.5/.editorconfig 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/.editorconfig 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,14 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf + +[*.py] +indent_style = space +indent_size = 4 + +[*.{c|h}] +indent_style = tab +indent_size = 8 + diff -Nru fwupd-1.4.5/.github/ISSUE_TEMPLATE/bug-report-uefi.md fwupd-1.5.8/.github/ISSUE_TEMPLATE/bug-report-uefi.md --- fwupd-1.4.5/.github/ISSUE_TEMPLATE/bug-report-uefi.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/.github/ISSUE_TEMPLATE/bug-report-uefi.md 2021-03-31 20:08:32.000000000 +0000 @@ -53,3 +53,4 @@ - Is this a regression? - Are you using an NVMe disk? - Is secure boot enabled? +- Is this a Lenovo system with 'Boot Order Lock' turned on in the BIOS? diff -Nru fwupd-1.4.5/.github/ISSUE_TEMPLATE/bug-report-wd19.md fwupd-1.5.8/.github/ISSUE_TEMPLATE/bug-report-wd19.md --- fwupd-1.4.5/.github/ISSUE_TEMPLATE/bug-report-wd19.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/.github/ISSUE_TEMPLATE/bug-report-wd19.md 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,64 @@ +--- +name: Bug report (Dell WD19) +about: Create a report to help us improve +title: 'Dell WD19 upgrade issue' +labels: bug +assignees: 'superm1' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + + +**Steps to Reproduce** +Steps to reproduce the behavior. + + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**fwupd version information** +Please provide the version of the daemon and client. +```shell +$ fwupdmgr --version +``` + +Please note how you installed it (`apt`, `dnf`, `pacman`, source, etc): + +**fwupd device information** +Please provide the output of the external fwupd devices recognized in your system. + +```shell +$ fwupdmgr get-devices --filter=~internal +``` + +**Dock SKU** +Please mention which module is installed in your WD19. + +- [ ] WD19 (Single-C) +- [ ] WD19TB (Thunderbolt) +- [ ] WD19DC (Dual-C) + +**Peripherals connected to the dock** +Please describe all devices connected to the dock. Be as specific as possible, +including USB devices, hubs, monitors, and downstream type-C devices. + +**Verbose daemon logs** +First enable daemon verbose logs collection. +```shell +fwupdmgr modify-config "VerboseDomains" "*" +``` + +Then try to reproduce the issue. Even if it doesn't reproduce, please attach the +daemon verbose logs collected from the system journal. +```shell +journalctl -b -u fwupd.service +``` + +**Additional questions** +- Operating system and version: +- Have you tried unplugging the dock or any peripherals from your machine? +- Have you tried to power cycle the dock from the AC adapter? +- Is this a regression? + diff -Nru fwupd-1.4.5/.github/pull_request_template.md fwupd-1.5.8/.github/pull_request_template.md --- fwupd-1.4.5/.github/pull_request_template.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/.github/pull_request_template.md 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ Type of pull request: -- [ ] New plugin (Please include [new plugin checklist](https://github.com/hughsie/fwupd/wiki/New-plugin-checklist)) +- [ ] New plugin (Please include [new plugin checklist](https://github.com/fwupd/fwupd/wiki/New-plugin-checklist)) - [ ] Code fix - [ ] Feature - [ ] Documentation diff -Nru fwupd-1.4.5/.github/workflows/create_containers.yml fwupd-1.5.8/.github/workflows/create_containers.yml --- fwupd-1.4.5/.github/workflows/create_containers.yml 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/.github/workflows/create_containers.yml 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,36 @@ +name: Create containers +on: + schedule: + - cron: '0 0 * * *' + +jobs: + push_to_registry: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + os: [fedora, debian-x86_64, arch, debian-i386] + + steps: + - name: Check out the repo + uses: actions/checkout@v2 + # TODO(#122): Remove step when https://github.com/actions/virtual-environments/issues/2658 fixed + - name: update runc # https://github.com/actions/virtual-environments/issues/2698#issuecomment-779262068 + if: startsWith(matrix.os, 'arch') + run: | + sudo apt-get install --assume-yes libseccomp-dev + git clone https://github.com/opencontainers/runc + cd runc && git checkout v1.0.0-rc93 && make -j`nproc` && sudo make install + cd .. && rm --recursive runc + - name: "Generate Dockerfile" + env: + OS: ${{ matrix.os }} + run: ./contrib/ci/generate_docker.py + - name: Push to GitHub Packages + uses: docker/build-push-action@v1 + with: + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + registry: docker.pkg.github.com + repository: fwupd/fwupd/fwupd-${{matrix.os}} + tags: latest diff -Nru fwupd-1.4.5/.github/workflows/main.yml fwupd-1.5.8/.github/workflows/main.yml --- fwupd-1.4.5/.github/workflows/main.yml 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/.github/workflows/main.yml 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,61 @@ +name: Continuous Integration +on: + push: + branches: [ 1_5_X ] + pull_request: + branches: [ 1_5_X ] + +jobs: + abi: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Refresh dependencies + run: sudo apt update + - name: Install dependencies + run: ./contrib/ci/generate_dependencies.py | sudo xargs apt install -y + - name: Check ABI + run: ./contrib/ci/check-abi $(git describe --abbrev=0 --tags) $(git rev-parse HEAD) + + build: + runs-on: ubuntu-latest + strategy: + matrix: + os: [fedora, debian-x86_64, arch, debian-i386] + steps: + - uses: actions/checkout@v2 + - name: Docker login + run: docker login docker.pkg.github.com -u $GITHUB_ACTOR -p $GITHUB_TOKEN + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + - name: Build in container + env: + CI_NETWORK: true + CI: true + run: | + echo $GITHUB_WORKSPACE + docker run --privileged -e CI=true -t -v $GITHUB_WORKSPACE:/github/workspace docker.pkg.github.com/fwupd/fwupd/fwupd-${{matrix.os}}:latest + + fuzzing: + runs-on: ubuntu-latest + steps: + - name: Build Fuzzers + id: build + uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master + with: + oss-fuzz-project-name: 'fwupd' + dry-run: false + - name: Run Fuzzers + uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master + with: + oss-fuzz-project-name: 'fwupd' + fuzz-seconds: 300 + dry-run: false + - name: Upload Crash + uses: actions/upload-artifact@v1 + if: failure() && steps.build.outcome == 'success' + with: + name: artifacts + path: ./out/artifacts diff -Nru fwupd-1.4.5/.gitignore fwupd-1.5.8/.gitignore --- fwupd-1.4.5/.gitignore 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/.gitignore 2021-03-31 20:08:32.000000000 +0000 @@ -1,4 +1,5 @@ /build +/build-win32 /dist /.vscode /build-dir @@ -21,3 +22,14 @@ /*.xz /*.gz __pycache__ +plugins/acpi-dmar/tests/ +plugins/acpi-facp/tests/ +plugins/ata/tests/ +plugins/dfu/tests/ +plugins/nvme/tests/ +plugins/synaptics-mst/tests/ +plugins/synaptics-prometheus/tests/ +plugins/tpm-eventlog/tests/ +plugins/uefi-dbx/tests/ +.buildconfig +.ossfuzz diff -Nru fwupd-1.4.5/.lgtm.yml fwupd-1.5.8/.lgtm.yml --- fwupd-1.4.5/.lgtm.yml 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/.lgtm.yml 2021-03-31 20:08:32.000000000 +0000 @@ -13,6 +13,7 @@ - python3-setuptools - python3-wheel - python3-cairo + - python3-gi-cairo - libssl-dev after_prepare: - python3 -m pip install --user "meson >= 0.52.0" diff -Nru fwupd-1.4.5/libfwupd/fwupd-client.c fwupd-1.5.8/libfwupd/fwupd-client.c --- fwupd-1.4.5/libfwupd/fwupd-client.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupd/fwupd-client.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2018 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -8,7 +8,10 @@ #include #include -#include +#include +#ifdef HAVE_LIBCURL +#include +#endif #ifdef HAVE_GIO_UNIX #include #endif @@ -18,15 +21,20 @@ #include #include -#include "fwupd-client.h" +#include "fwupd-client-private.h" +#include "fwupd-client-sync.h" #include "fwupd-common-private.h" #include "fwupd-deprecated.h" #include "fwupd-enums.h" #include "fwupd-error.h" #include "fwupd-device-private.h" +#include "fwupd-plugin-private.h" +#include "fwupd-security-attr-private.h" #include "fwupd-release-private.h" #include "fwupd-remote-private.h" +typedef GObject *(*FwupdClientObjectNewFunc) (void); + /** * SECTION:fwupd-client * @short_description: a way of interfacing with the daemon @@ -39,19 +47,36 @@ static void fwupd_client_finalize (GObject *object); typedef struct { + GMainContext *main_ctx; FwupdStatus status; gboolean tainted; gboolean interactive; guint percentage; + GMutex idle_mutex; /* for @idle_id and @idle_sources */ + guint idle_id; + GPtrArray *idle_sources; /* element-type FwupdClientContextHelper */ gchar *daemon_version; gchar *host_product; gchar *host_machine_id; - GDBusConnection *conn; + gchar *host_security_id; + GMutex proxy_mutex; /* for @proxy */ GDBusProxy *proxy; - SoupSession *soup_session; gchar *user_agent; +#ifdef SOUP_SESSION_COMPAT + GObject *soup_session; + GModule *soup_module; /* we leak this */ +#endif } FwupdClientPrivate; +#ifdef HAVE_LIBCURL +typedef struct { + GPtrArray *urls; + CURL *curl; + curl_mime *mime; + struct curl_slist *headers; +} FwupdCurlHelper; +#endif + enum { SIGNAL_CHANGED, SIGNAL_STATUS_CHANGED, @@ -67,9 +92,10 @@ PROP_PERCENTAGE, PROP_DAEMON_VERSION, PROP_TAINTED, - PROP_SOUP_SESSION, + PROP_SOUP_SESSION, /* compat ABI, do not use! */ PROP_HOST_PRODUCT, PROP_HOST_MACHINE_ID, + PROP_HOST_SECURITY_ID, PROP_INTERACTIVE, PROP_LAST }; @@ -79,98 +105,233 @@ G_DEFINE_TYPE_WITH_PRIVATE (FwupdClient, fwupd_client, G_TYPE_OBJECT) #define GET_PRIVATE(o) (fwupd_client_get_instance_private (o)) +#ifdef HAVE_LIBCURL_7_62_0 +G_DEFINE_AUTOPTR_CLEANUP_FUNC(CURLU, curl_url_cleanup) +#endif + +#ifdef HAVE_LIBCURL +static void +fwupd_client_curl_helper_free (FwupdCurlHelper *helper) +{ + if (helper->curl != NULL) + curl_easy_cleanup (helper->curl); + if (helper->mime != NULL) + curl_mime_free (helper->mime); + if (helper->headers != NULL) + curl_slist_free_all (helper->headers); + if (helper->urls != NULL) + g_ptr_array_unref (helper->urls); + g_free (helper); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(FwupdCurlHelper, fwupd_client_curl_helper_free) +#endif + typedef struct { - gboolean ret; - GError *error; - GMainLoop *loop; - GVariant *val; - GDBusMessage *message; -} FwupdClientHelper; - -static void -fwupd_client_helper_free (FwupdClientHelper *helper) -{ - if (helper->message != NULL) - g_object_unref (helper->message); - if (helper->val != NULL) - g_variant_unref (helper->val); - if (helper->error != NULL) - g_error_free (helper->error); - g_main_loop_unref (helper->loop); + FwupdClient *self; + gchar *property_name; + guint signal_id; + FwupdDevice *device; +} FwupdClientContextHelper; + +static void +fwupd_client_context_helper_free (FwupdClientContextHelper *helper) +{ + g_clear_object (&helper->device); + g_object_unref (helper->self); + g_free (helper->property_name); g_free (helper); } -static FwupdClientHelper * -fwupd_client_helper_new (void) +/* always executed in the main context given by priv->main_ctx */ +static void +fwupd_client_context_object_notify (FwupdClient *self, const gchar *property_name) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + + g_return_if_fail (g_main_context_is_owner (priv->main_ctx)); + + /* property */ + g_object_notify (G_OBJECT (self), property_name); + + /* legacy signal name */ + if (g_strcmp0 (property_name, "status") == 0) + g_signal_emit (self, signals[SIGNAL_STATUS_CHANGED], 0, priv->status); +} + +/* emits all pending context helpers in the correct GMainContext */ +static gboolean +fwupd_client_context_idle_cb (gpointer user_data) +{ + FwupdClient *self = FWUPD_CLIENT (user_data); + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&priv->idle_mutex); + + g_assert (locker != NULL); + + for (guint i = 0; i < priv->idle_sources->len; i++) { + FwupdClientContextHelper *helper = g_ptr_array_index (priv->idle_sources, i); + + /* property */ + if (helper->property_name != NULL) + fwupd_client_context_object_notify (self, helper->property_name); + + /* device signal */ + if (helper->signal_id !=0 && helper->device != NULL) + g_signal_emit (self, signals[helper->signal_id], 0, helper->device); + } + + /* all done */ + g_ptr_array_set_size (priv->idle_sources, 0); + priv->idle_id = 0; + return G_SOURCE_REMOVE; +} + +static void +fwupd_client_context_helper (FwupdClient *self, FwupdClientContextHelper *helper) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&priv->idle_mutex); + + g_assert (locker != NULL); + + /* no source already attached to the context */ + if (priv->idle_id == 0) { + g_autoptr(GSource) source = g_idle_source_new (); + g_source_set_callback (source, fwupd_client_context_idle_cb, self, NULL); + priv->idle_id = g_source_attach (g_steal_pointer (&source), priv->main_ctx); + } + + /* run in the correct GMainContext and thread */ + g_ptr_array_add (priv->idle_sources, helper); +} + +/* run callback in the correct thread */ +static void +fwupd_client_object_notify (FwupdClient *self, const gchar *property_name) { - FwupdClientHelper *helper; - helper = g_new0 (FwupdClientHelper, 1); - helper->loop = g_main_loop_new (NULL, FALSE); - return helper; + FwupdClientPrivate *priv = GET_PRIVATE (self); + FwupdClientContextHelper *helper = NULL; + + /* shortcut */ + if (g_main_context_is_owner (priv->main_ctx)) { + fwupd_client_context_object_notify (self, property_name); + return; + } + + /* run in the correct GMainContext and thread */ + helper = g_new0 (FwupdClientContextHelper, 1); + helper->self = g_object_ref (self); + helper->property_name = g_strdup (property_name); + fwupd_client_context_helper (self, helper); } -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-function" -G_DEFINE_AUTOPTR_CLEANUP_FUNC(FwupdClientHelper, fwupd_client_helper_free) -#pragma clang diagnostic pop +/* run callback in the correct thread */ +static void +fwupd_client_signal_emit_device (FwupdClient *self, guint signal_id, FwupdDevice *device) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + FwupdClientContextHelper *helper = NULL; + + /* shortcut */ + if (g_main_context_is_owner (priv->main_ctx)) { + g_signal_emit (self, signals[signal_id], 0, device); + return; + } + + /* run in the correct GMainContext and thread */ + helper = g_new0 (FwupdClientContextHelper, 1); + helper->self = g_object_ref (self); + helper->signal_id = signal_id; + helper->device = g_object_ref (device); + fwupd_client_context_helper (self, helper); +} static void -fwupd_client_set_host_product (FwupdClient *client, const gchar *host_product) +fwupd_client_set_host_product (FwupdClient *self, const gchar *host_product) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); + + /* not changed */ + if (g_strcmp0 (priv->host_product, host_product) == 0) + return; + g_free (priv->host_product); priv->host_product = g_strdup (host_product); - g_object_notify (G_OBJECT (client), "host-product"); + fwupd_client_object_notify (self, "host-product"); } static void -fwupd_client_set_host_machine_id (FwupdClient *client, const gchar *host_machine_id) +fwupd_client_set_host_machine_id (FwupdClient *self, const gchar *host_machine_id) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); + + /* not changed */ + if (g_strcmp0 (priv->host_machine_id, host_machine_id) == 0) + return; + g_free (priv->host_machine_id); priv->host_machine_id = g_strdup (host_machine_id); - g_object_notify (G_OBJECT (client), "host-machine-id"); + fwupd_client_object_notify (self, "host-machine-id"); +} + +static void +fwupd_client_set_host_security_id (FwupdClient *self, const gchar *host_security_id) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + + /* not changed */ + if (g_strcmp0 (priv->host_security_id, host_security_id) == 0) + return; + + g_free (priv->host_security_id); + priv->host_security_id = g_strdup (host_security_id); + fwupd_client_object_notify (self, "host-security-id"); } static void -fwupd_client_set_daemon_version (FwupdClient *client, const gchar *daemon_version) +fwupd_client_set_daemon_version (FwupdClient *self, const gchar *daemon_version) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); + + /* not changed */ + if (g_strcmp0 (priv->daemon_version, daemon_version) == 0) + return; + g_free (priv->daemon_version); priv->daemon_version = g_strdup (daemon_version); - g_object_notify (G_OBJECT (client), "daemon-version"); + fwupd_client_object_notify (self, "daemon-version"); } static void -fwupd_client_set_status (FwupdClient *client, FwupdStatus status) +fwupd_client_set_status (FwupdClient *self, FwupdStatus status) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); if (priv->status == status) return; priv->status = status; g_debug ("Emitting ::status-changed() [%s]", fwupd_status_to_string (priv->status)); - g_signal_emit (client, signals[SIGNAL_STATUS_CHANGED], 0, priv->status); - g_object_notify (G_OBJECT (client), "status"); + fwupd_client_object_notify (self, "status"); } static void -fwupd_client_set_percentage (FwupdClient *client, guint percentage) +fwupd_client_set_percentage (FwupdClient *self, guint percentage) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); if (priv->percentage == percentage) return; priv->percentage = percentage; - g_object_notify (G_OBJECT (client), "percentage"); + fwupd_client_object_notify (self, "percentage"); } static void fwupd_client_properties_changed_cb (GDBusProxy *proxy, GVariant *changed_properties, GStrv invalidated_properties, - FwupdClient *client) + FwupdClient *self) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); g_autoptr(GVariantDict) dict = NULL; /* print to the console */ @@ -179,14 +340,14 @@ g_autoptr(GVariant) val = NULL; val = g_dbus_proxy_get_cached_property (proxy, "Status"); if (val != NULL) - fwupd_client_set_status (client, g_variant_get_uint32 (val)); + fwupd_client_set_status (self, g_variant_get_uint32 (val)); } if (g_variant_dict_contains (dict, "Tainted")) { g_autoptr(GVariant) val = NULL; val = g_dbus_proxy_get_cached_property (proxy, "Tainted"); if (val != NULL) { priv->tainted = g_variant_get_boolean (val); - g_object_notify (G_OBJECT (client), "tainted"); + fwupd_client_object_notify (self, "tainted"); } } if (g_variant_dict_contains (dict, "Interactive")) { @@ -194,32 +355,38 @@ val = g_dbus_proxy_get_cached_property (proxy, "Interactive"); if (val != NULL) { priv->interactive = g_variant_get_boolean (val); - g_object_notify (G_OBJECT (client), "interactive"); + fwupd_client_object_notify (self, "interactive"); } } if (g_variant_dict_contains (dict, "Percentage")) { g_autoptr(GVariant) val = NULL; val = g_dbus_proxy_get_cached_property (proxy, "Percentage"); if (val != NULL) - fwupd_client_set_percentage (client, g_variant_get_uint32 (val)); + fwupd_client_set_percentage (self, g_variant_get_uint32 (val)); } if (g_variant_dict_contains (dict, "DaemonVersion")) { g_autoptr(GVariant) val = NULL; val = g_dbus_proxy_get_cached_property (proxy, "DaemonVersion"); if (val != NULL) - fwupd_client_set_daemon_version (client, g_variant_get_string (val, NULL)); + fwupd_client_set_daemon_version (self, g_variant_get_string (val, NULL)); } if (g_variant_dict_contains (dict, "HostProduct")) { g_autoptr(GVariant) val = NULL; val = g_dbus_proxy_get_cached_property (proxy, "HostProduct"); if (val != NULL) - fwupd_client_set_host_product (client, g_variant_get_string (val, NULL)); + fwupd_client_set_host_product (self, g_variant_get_string (val, NULL)); } if (g_variant_dict_contains (dict, "HostMachineId")) { g_autoptr(GVariant) val = NULL; val = g_dbus_proxy_get_cached_property (proxy, "HostMachineId"); if (val != NULL) - fwupd_client_set_host_machine_id (client, g_variant_get_string (val, NULL)); + fwupd_client_set_host_machine_id (self, g_variant_get_string (val, NULL)); + } + if (g_variant_dict_contains (dict, "HostSecurityId")) { + g_autoptr(GVariant) val = NULL; + val = g_dbus_proxy_get_cached_property (proxy, "HostSecurityId"); + if (val != NULL) + fwupd_client_set_host_security_id (self, g_variant_get_string (val, NULL)); } } @@ -228,41 +395,81 @@ const gchar *sender_name, const gchar *signal_name, GVariant *parameters, - FwupdClient *client) + FwupdClient *self) { g_autoptr(FwupdDevice) dev = NULL; if (g_strcmp0 (signal_name, "Changed") == 0) { g_debug ("Emitting ::changed()"); - g_signal_emit (client, signals[SIGNAL_CHANGED], 0); + g_signal_emit (self, signals[SIGNAL_CHANGED], 0); return; } if (g_strcmp0 (signal_name, "DeviceAdded") == 0) { dev = fwupd_device_from_variant (parameters); g_debug ("Emitting ::device-added(%s)", fwupd_device_get_id (dev)); - g_signal_emit (client, signals[SIGNAL_DEVICE_ADDED], 0, dev); + fwupd_client_signal_emit_device (self, SIGNAL_DEVICE_ADDED, dev); return; } if (g_strcmp0 (signal_name, "DeviceRemoved") == 0) { dev = fwupd_device_from_variant (parameters); - g_signal_emit (client, signals[SIGNAL_DEVICE_REMOVED], 0, dev); g_debug ("Emitting ::device-removed(%s)", fwupd_device_get_id (dev)); + fwupd_client_signal_emit_device (self, SIGNAL_DEVICE_REMOVED, dev); return; } if (g_strcmp0 (signal_name, "DeviceChanged") == 0) { dev = fwupd_device_from_variant (parameters); - g_signal_emit (client, signals[SIGNAL_DEVICE_CHANGED], 0, dev); g_debug ("Emitting ::device-changed(%s)", fwupd_device_get_id (dev)); + fwupd_client_signal_emit_device (self, SIGNAL_DEVICE_CHANGED, dev); return; } g_debug ("Unknown signal name '%s' from %s", signal_name, sender_name); } /** + * fwupd_client_get_main_context: + * @self: A #FwupdClient + * + * Gets the internal #GMainContext to use for synchronous methods. + * By default the value is set a new #GMainContext. + * + * Return value: (transfer full): the #GMainContext + * + * Since: 1.5.3 + **/ +GMainContext * +fwupd_client_get_main_context (FwupdClient *self) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + if (priv->main_ctx != NULL) + return g_main_context_ref (priv->main_ctx); + return g_main_context_new (); +} + +/** + * fwupd_client_set_main_context: + * @self: A #FwupdClient + * @main_ctx: (nullable): #GMainContext or %NULL to use the global default main context + * + * Sets the internal #GMainContext to use for returning progress signals. + * + * Since: 1.5.3 + **/ +void +fwupd_client_set_main_context (FwupdClient *self, GMainContext *main_ctx) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + if (main_ctx == priv->main_ctx) + return; + g_clear_pointer (&priv->main_ctx, g_main_context_unref); + if (main_ctx != NULL) + priv->main_ctx = g_main_context_ref (main_ctx); +} + +/** * fwupd_client_ensure_networking: - * @client: A #FwupdClient + * @self: A #FwupdClient * @error: the #GError, or %NULL * * Sets up the client networking support ready for use. Most other download and @@ -274,15 +481,12 @@ * Since: 1.4.5 **/ gboolean -fwupd_client_ensure_networking (FwupdClient *client, GError **error) +fwupd_client_ensure_networking (FwupdClient *self, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - const gchar *http_proxy; - g_autoptr(SoupSession) session = NULL; + FwupdClientPrivate *priv = GET_PRIVATE (self); - /* already exists */ - if (priv->soup_session != NULL) - return TRUE; + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* check the user agent is sane */ if (priv->user_agent == NULL) { @@ -299,22 +503,71 @@ "user agent unsuitable; fwupd version required"); return FALSE; } +#ifdef SOUP_SESSION_COMPAT + if (priv->soup_session != NULL) { + g_object_set (priv->soup_session, + "user-agent", priv->user_agent, + NULL); + } +#endif + return TRUE; +} + +#ifdef HAVE_LIBCURL +static int +fwupd_client_progress_callback_cb (void *clientp, + curl_off_t dltotal, + curl_off_t dlnow, + curl_off_t ultotal, + curl_off_t ulnow) +{ + FwupdClient *self = FWUPD_CLIENT (clientp); + + /* calculate percentage */ + if (dltotal > 0 && dlnow >= 0 && dlnow <= dltotal) { + guint percentage = (guint) ((100 * dlnow) / dltotal); + g_debug ("download progress: %u%%", percentage); + fwupd_client_set_percentage (self, percentage); + } else if (ultotal > 0 && ulnow >= 0 && ulnow <= ultotal) { + guint percentage = (guint) ((100 * ulnow) / ultotal); + g_debug ("upload progress: %u%%", percentage); + fwupd_client_set_percentage (self, percentage); + } + + return 0; +} + +static FwupdCurlHelper * +fwupd_client_curl_new (FwupdClient *self, GError **error) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + const gchar *http_proxy; + g_autoptr(FwupdCurlHelper) helper = g_new0 (FwupdCurlHelper, 1); - /* create the soup session */ - session = soup_session_new_with_options (SOUP_SESSION_USER_AGENT, priv->user_agent, - SOUP_SESSION_TIMEOUT, 60, - NULL); - if (session == NULL) { + /* check the user agent is sane */ + if (!fwupd_client_ensure_networking (self, error)) + return NULL; + + /* create the session */ + helper->curl = curl_easy_init (); + if (helper->curl == NULL) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "failed to setup networking"); - return FALSE; + return NULL; } + if (g_getenv ("FWUPD_CURL_VERBOSE") != NULL) + curl_easy_setopt (helper->curl, CURLOPT_VERBOSE, 1L); + curl_easy_setopt (helper->curl, CURLOPT_XFERINFOFUNCTION, fwupd_client_progress_callback_cb); + curl_easy_setopt (helper->curl, CURLOPT_XFERINFODATA, self); + curl_easy_setopt (helper->curl, CURLOPT_USERAGENT, priv->user_agent); + curl_easy_setopt (helper->curl, CURLOPT_CONNECTTIMEOUT, 60L); + curl_easy_setopt (helper->curl, CURLOPT_NOPROGRESS, 0L); /* relax the SSL checks for broken corporate proxies */ if (g_getenv ("DISABLE_SSL_STRICT") != NULL) - g_object_set (session, SOUP_SESSION_SSL_STRICT, FALSE, NULL); + curl_easy_setopt (helper->curl, CURLOPT_SSL_VERIFYPEER, 0L); /* set the proxy */ http_proxy = g_getenv ("https_proxy"); @@ -324,90 +577,143 @@ http_proxy = g_getenv ("http_proxy"); if (http_proxy == NULL) http_proxy = g_getenv ("HTTP_PROXY"); - if (http_proxy != NULL && strlen (http_proxy) > 0) { - g_autoptr(SoupURI) proxy_uri = soup_uri_new (http_proxy); - if (proxy_uri == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "invalid proxy URI: %s", http_proxy); - return FALSE; - } - g_object_set (session, SOUP_SESSION_PROXY_URI, proxy_uri, NULL); - } + if (http_proxy != NULL && strlen (http_proxy) > 0) + curl_easy_setopt (helper->curl, CURLOPT_PROXY, http_proxy); /* this disables the double-compression of the firmware.xml.gz file */ - soup_session_remove_feature_by_type (session, SOUP_TYPE_CONTENT_DECODER); - priv->soup_session = g_steal_pointer (&session); - return TRUE; + curl_easy_setopt (helper->curl, CURLOPT_HTTP_CONTENT_DECODING, 0L); + return g_steal_pointer (&helper); } +#endif -/** - * fwupd_client_connect: - * @client: A #FwupdClient - * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL - * - * Sets up the client ready for use. Most other methods call this - * for you, and do you only need to call this if you are just watching - * the client. - * - * Returns: %TRUE for success - * - * Since: 0.7.1 - **/ -gboolean -fwupd_client_connect (FwupdClient *client, GCancellable *cancellable, GError **error) -{ - FwupdClientPrivate *priv = GET_PRIVATE (client); +static void +fwupd_client_connect_get_proxy_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + FwupdClient *self = g_task_get_source_object (task); + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GDBusProxy) proxy = NULL; + g_autoptr(GError) error = NULL; g_autoptr(GVariant) val = NULL; g_autoptr(GVariant) val2 = NULL; + g_autoptr(GVariant) val3 = NULL; + g_autoptr(GVariant) val4 = NULL; + g_autoptr(GVariant) val5 = NULL; + g_autoptr(GVariant) val6 = NULL; + g_autoptr(GVariant) val7 = NULL; + g_autoptr(GMutexLocker) locker = NULL; + + proxy = g_dbus_proxy_new_finish (res, &error); + if (proxy == NULL) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* nothing to do */ - if (priv->proxy != NULL) - return TRUE; - - /* connect to the daemon */ - priv->conn = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); - if (priv->conn == NULL) { - g_prefix_error (error, "Failed to connect to system D-Bus: "); - return FALSE; + /* another thread did this for us */ + locker = g_mutex_locker_new (&priv->proxy_mutex); + if (priv->proxy != NULL) { + g_task_return_boolean (task, TRUE); + return; } - priv->proxy = g_dbus_proxy_new_sync (priv->conn, - G_DBUS_PROXY_FLAGS_NONE, - NULL, - FWUPD_DBUS_SERVICE, - FWUPD_DBUS_PATH, - FWUPD_DBUS_INTERFACE, - NULL, - error); - if (priv->proxy == NULL) - return FALSE; + priv->proxy = g_steal_pointer (&proxy); + + /* connect signals, etc. */ g_signal_connect (priv->proxy, "g-properties-changed", - G_CALLBACK (fwupd_client_properties_changed_cb), client); + G_CALLBACK (fwupd_client_properties_changed_cb), self); g_signal_connect (priv->proxy, "g-signal", - G_CALLBACK (fwupd_client_signal_cb), client); + G_CALLBACK (fwupd_client_signal_cb), self); val = g_dbus_proxy_get_cached_property (priv->proxy, "DaemonVersion"); if (val != NULL) - fwupd_client_set_daemon_version (client, g_variant_get_string (val, NULL)); + fwupd_client_set_daemon_version (self, g_variant_get_string (val, NULL)); val2 = g_dbus_proxy_get_cached_property (priv->proxy, "Tainted"); if (val2 != NULL) priv->tainted = g_variant_get_boolean (val2); - val2 = g_dbus_proxy_get_cached_property (priv->proxy, "Interactive"); - if (val2 != NULL) - priv->interactive = g_variant_get_boolean (val2); - val = g_dbus_proxy_get_cached_property (priv->proxy, "HostProduct"); - if (val != NULL) - fwupd_client_set_host_product (client, g_variant_get_string (val, NULL)); - val = g_dbus_proxy_get_cached_property (priv->proxy, "HostMachineId"); - if (val != NULL) - fwupd_client_set_host_machine_id (client, g_variant_get_string (val, NULL)); + val3 = g_dbus_proxy_get_cached_property (priv->proxy, "Status"); + if (val3 != NULL) + fwupd_client_set_status (self, g_variant_get_uint32 (val3)); + val4 = g_dbus_proxy_get_cached_property (priv->proxy, "Interactive"); + if (val4 != NULL) + priv->interactive = g_variant_get_boolean (val4); + val5 = g_dbus_proxy_get_cached_property (priv->proxy, "HostProduct"); + if (val5 != NULL) + fwupd_client_set_host_product (self, g_variant_get_string (val5, NULL)); + val6 = g_dbus_proxy_get_cached_property (priv->proxy, "HostMachineId"); + if (val6 != NULL) + fwupd_client_set_host_machine_id (self, g_variant_get_string (val6, NULL)); + val7 = g_dbus_proxy_get_cached_property (priv->proxy, "HostSecurityId"); + if (val7 != NULL) + fwupd_client_set_host_security_id (self, g_variant_get_string (val7, NULL)); - return TRUE; + /* success */ + g_task_return_boolean (task, TRUE); +} + +/** + * fwupd_client_connect_async: + * @self: A #FwupdClient + * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * + * Sets up the client ready for use. This is probably the first method you call + * when wanting to use libfwupd in an asynchronous manner. + * + * Other methods such as fwupd_client_get_devices_async() should only be called + * after fwupd_client_connect_finish() has been called without an error. + * + * Since: 1.5.0 + **/ +void +fwupd_client_connect_async (FwupdClient *self, GCancellable *cancellable, + GAsyncReadyCallback callback, gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = g_task_new (self, cancellable, callback, callback_data); + g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&priv->proxy_mutex); + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + g_assert (locker != NULL); + + /* nothing to do */ + if (priv->proxy != NULL) { + g_task_return_boolean (task, TRUE); + return; + } + + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + FWUPD_DBUS_SERVICE, + FWUPD_DBUS_PATH, + FWUPD_DBUS_INTERFACE, + cancellable, + fwupd_client_connect_get_proxy_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_connect_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_connect_async(). + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fwupd_client_connect_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); } static void @@ -443,712 +749,1452 @@ g_dbus_error_strip_remote_error (error); } +static void +fwupd_client_get_host_security_attrs_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_pointer (task, + fwupd_security_attr_array_from_variant (val), + (GDestroyNotify) g_ptr_array_unref); +} + /** - * fwupd_client_get_devices: - * @client: A #FwupdClient + * fwupd_client_get_host_security_attrs_async: + * @self: A #FwupdClient * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * - * Gets all the devices registered with the daemon. + * Gets all the host security attributes from the daemon. * - * Returns: (element-type FwupdDevice) (transfer container): results + * You must have called fwupd_client_connect_async() on @self before using + * this method. * - * Since: 0.9.2 + * Since: 1.5.0 **/ -GPtrArray * -fwupd_client_get_devices (FwupdClient *client, GCancellable *cancellable, GError **error) -{ - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_autoptr(GVariant) val = NULL; - - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) - return NULL; +void +fwupd_client_get_host_security_attrs_async (FwupdClient *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); /* call into daemon */ - val = g_dbus_proxy_call_sync (priv->proxy, - "GetDevices", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - error); - if (val == NULL) { - if (error != NULL) - fwupd_client_fixup_dbus_error (*error); - return NULL; - } - return fwupd_device_array_from_variant (val); + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "GetHostSecurityAttrs", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, cancellable, + fwupd_client_get_host_security_attrs_cb, + g_steal_pointer (&task)); } /** - * fwupd_client_get_history: - * @client: A #FwupdClient - * @cancellable: the #GCancellable, or %NULL + * fwupd_client_get_host_security_attrs_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult * @error: the #GError, or %NULL * - * Gets all the history. + * Gets the result of fwupd_client_get_host_security_attrs_async(). * - * Returns: (element-type FwupdDevice) (transfer container): results + * Returns: (element-type FwupdSecurityAttr) (transfer container): attributes * - * Since: 1.0.4 + * Since: 1.5.0 **/ GPtrArray * -fwupd_client_get_history (FwupdClient *client, GCancellable *cancellable, GError **error) +fwupd_client_get_host_security_attrs_finish (FwupdClient *self, GAsyncResult *res, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_autoptr(GVariant) val = NULL; - - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} - /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) - return NULL; +static GHashTable * +fwupd_report_metadata_hash_from_variant (GVariant *value) +{ + GHashTable *hash; + gsize sz; + g_autoptr(GVariant) untuple = NULL; + + hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + untuple = g_variant_get_child_value (value, 0); + sz = g_variant_n_children (untuple); + for (guint i = 0; i < sz; i++) { + g_autoptr(GVariant) data = NULL; + const gchar *key = NULL; + const gchar *val = NULL; + data = g_variant_get_child_value (untuple, i); + g_variant_get (data, "{&s&s}", &key, &val); + g_hash_table_insert (hash, g_strdup (key), g_strdup (val)); + } + return hash; +} - /* call into daemon */ - val = g_dbus_proxy_call_sync (priv->proxy, - "GetHistory", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - error); +static void +fwupd_client_get_report_metadata_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); if (val == NULL) { - if (error != NULL) - fwupd_client_fixup_dbus_error (*error); - return NULL; + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; } - return fwupd_device_array_from_variant (val); + + /* success */ + g_task_return_pointer (task, + fwupd_report_metadata_hash_from_variant (val), + (GDestroyNotify) g_hash_table_unref); } /** - * fwupd_client_get_device_by_id: - * @client: A #FwupdClient - * @device_id: the device ID, e.g. `usb:00:01:03:03` + * fwupd_client_get_report_metadata_async: + * @self: A #FwupdClient * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * + * Gets all the report metadata from the daemon. + * + * You must have called fwupd_client_connect_async() on @self before using + * this method. + * + * Since: 1.5.0 + **/ +void +fwupd_client_get_report_metadata_async (FwupdClient *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* call into daemon */ + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "GetReportMetadata", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, cancellable, + fwupd_client_get_report_metadata_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_get_report_metadata_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult * @error: the #GError, or %NULL * - * Gets a device by it's device ID. + * Gets the result of fwupd_client_get_report_metadata_async(). * - * Returns: (transfer full): a #FwupdDevice or %NULL + * Returns: (transfer container): attributes * - * Since: 0.9.3 + * Since: 1.5.0 **/ -FwupdDevice * -fwupd_client_get_device_by_id (FwupdClient *client, - const gchar *device_id, - GCancellable *cancellable, - GError **error) +GHashTable * +fwupd_client_get_report_metadata_finish (FwupdClient *self, GAsyncResult *res, GError **error) { - g_autoptr(GPtrArray) devices = NULL; - - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); - g_return_val_if_fail (device_id != NULL, NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} - /* get all the devices */ - devices = fwupd_client_get_devices (client, cancellable, error); - if (devices == NULL) - return NULL; +static void +fwupd_client_get_devices_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; - /* find the device by ID (client side) */ - for (guint i = 0; i < devices->len; i++) { - FwupdDevice *dev = g_ptr_array_index (devices, i); - if (g_strcmp0 (fwupd_device_get_id (dev), device_id) == 0) - return g_object_ref (dev); + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; } - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "failed to find %s", device_id); - return NULL; + + /* success */ + g_task_return_pointer (task, + fwupd_device_array_from_variant (val), + (GDestroyNotify) g_ptr_array_unref); } /** - * fwupd_client_get_devices_by_guid: - * @client: A #FwupdClient - * @guid: the GUID, e.g. `e22c4520-43dc-5bb3-8245-5787fead9b63` + * fwupd_client_get_devices_async: + * @self: A #FwupdClient * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * - * Gets any devices that provide a specific GUID. An error is returned if no - * devices contains this GUID. + * Gets all the devices registered with the daemon. * - * Returns: (element-type FwupdDevice) (transfer container): devices or %NULL + * You must have called fwupd_client_connect_async() on @self before using + * this method. * - * Since: 1.4.1 + * Since: 1.5.0 **/ -GPtrArray * -fwupd_client_get_devices_by_guid (FwupdClient *client, - const gchar *guid, - GCancellable *cancellable, - GError **error) +void +fwupd_client_get_devices_async (FwupdClient *self, GCancellable *cancellable, + GAsyncReadyCallback callback, gpointer callback_data) { - g_autoptr(GPtrArray) devices = NULL; - g_autoptr(GPtrArray) devices_tmp = NULL; - - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); - g_return_val_if_fail (guid != NULL, NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - /* get all the devices */ - devices_tmp = fwupd_client_get_devices (client, cancellable, error); - if (devices_tmp == NULL) - return NULL; - - /* find the devices by GUID (client side) */ - devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - for (guint i = 0; i < devices_tmp->len; i++) { - FwupdDevice *dev_tmp = g_ptr_array_index (devices_tmp, i); - if (fwupd_device_has_guid (dev_tmp, guid)) - g_ptr_array_add (devices, g_object_ref (dev_tmp)); - } + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; - /* nothing */ - if (devices->len == 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "failed to find any device providing %s", guid); - return NULL; - } + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); - /* success */ - return g_steal_pointer (&devices); + /* call into daemon */ + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "GetDevices", + NULL, G_DBUS_CALL_FLAGS_NONE, + -1, cancellable, + fwupd_client_get_devices_cb, + g_steal_pointer (&task)); } /** - * fwupd_client_get_releases: - * @client: A #FwupdClient - * @device_id: the device ID - * @cancellable: the #GCancellable, or %NULL + * fwupd_client_get_devices_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult * @error: the #GError, or %NULL * - * Gets all the releases for a specific device + * Gets the result of fwupd_client_get_devices_async(). * - * Returns: (element-type FwupdRelease) (transfer container): results + * Returns: (element-type FwupdDevice) (transfer container): results * - * Since: 0.9.3 + * Since: 1.5.0 **/ GPtrArray * -fwupd_client_get_releases (FwupdClient *client, const gchar *device_id, - GCancellable *cancellable, GError **error) +fwupd_client_get_devices_finish (FwupdClient *self, GAsyncResult *res, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_autoptr(GVariant) val = NULL; - - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); - g_return_val_if_fail (device_id != NULL, NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} - /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) - return NULL; +static void +fwupd_client_get_plugins_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; - /* call into daemon */ - val = g_dbus_proxy_call_sync (priv->proxy, - "GetReleases", - g_variant_new ("(s)", device_id), - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - error); + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); if (val == NULL) { - if (error != NULL) - fwupd_client_fixup_dbus_error (*error); - return NULL; + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; } - return fwupd_release_array_from_variant (val); + + /* success */ + g_task_return_pointer (task, + fwupd_plugin_array_from_variant (val), + (GDestroyNotify) g_ptr_array_unref); } /** - * fwupd_client_get_downgrades: - * @client: A #FwupdClient - * @device_id: the device ID + * fwupd_client_get_plugins_async: + * @self: A #FwupdClient * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * - * Gets all the downgrades for a specific device. + * Gets all the plugins being used by the daemon. * - * Returns: (element-type FwupdRelease) (transfer container): results + * You must have called fwupd_client_connect_async() on @self before using + * this method. * - * Since: 0.9.8 + * Since: 1.5.0 **/ -GPtrArray * -fwupd_client_get_downgrades (FwupdClient *client, const gchar *device_id, - GCancellable *cancellable, GError **error) +void +fwupd_client_get_plugins_async (FwupdClient *self, GCancellable *cancellable, + GAsyncReadyCallback callback, gpointer callback_data) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_autoptr(GVariant) val = NULL; - - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); - g_return_val_if_fail (device_id != NULL, NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; - /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) - return NULL; + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); /* call into daemon */ - val = g_dbus_proxy_call_sync (priv->proxy, - "GetDowngrades", - g_variant_new ("(s)", device_id), - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - error); - if (val == NULL) { - if (error != NULL) - fwupd_client_fixup_dbus_error (*error); - return NULL; - } - return fwupd_release_array_from_variant (val); + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "GetPlugins", + NULL, G_DBUS_CALL_FLAGS_NONE, + -1, cancellable, + fwupd_client_get_plugins_cb, + g_steal_pointer (&task)); } /** - * fwupd_client_get_upgrades: - * @client: A #FwupdClient - * @device_id: the device ID - * @cancellable: the #GCancellable, or %NULL + * fwupd_client_get_plugins_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult * @error: the #GError, or %NULL * - * Gets all the upgrades for a specific device. + * Gets the result of fwupd_client_get_plugins_async(). * - * Returns: (element-type FwupdRelease) (transfer container): results + * Returns: (element-type FwupdDevice) (transfer container): results * - * Since: 0.9.8 + * Since: 1.5.0 **/ GPtrArray * -fwupd_client_get_upgrades (FwupdClient *client, const gchar *device_id, - GCancellable *cancellable, GError **error) +fwupd_client_get_plugins_finish (FwupdClient *self, GAsyncResult *res, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_autoptr(GVariant) val = NULL; - - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); - g_return_val_if_fail (device_id != NULL, NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} - /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) - return NULL; +static void +fwupd_client_get_history_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; - /* call into daemon */ - val = g_dbus_proxy_call_sync (priv->proxy, - "GetUpgrades", - g_variant_new ("(s)", device_id), - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - error); + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); if (val == NULL) { - if (error != NULL) - fwupd_client_fixup_dbus_error (*error); - return NULL; + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; } - return fwupd_release_array_from_variant (val); -} -static void -fwupd_client_proxy_call_cb (GObject *source, GAsyncResult *res, gpointer user_data) -{ - FwupdClientHelper *helper = (FwupdClientHelper *) user_data; - helper->val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), - res, &helper->error); - if (helper->val != NULL) - helper->ret = TRUE; - if (helper->error != NULL) - fwupd_client_fixup_dbus_error (helper->error); - g_main_loop_quit (helper->loop); + /* success */ + g_task_return_pointer (task, + fwupd_device_array_from_variant (val), + (GDestroyNotify) g_ptr_array_unref); } /** - * fwupd_client_modify_config - * @client: A #FwupdClient - * @key: key, e.g. `BlacklistPlugins` - * @value: value, e.g. `*` + * fwupd_client_get_history_async: + * @self: A #FwupdClient * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * - * Modifies a daemon config option. - * The daemon will only respond to this request with proper permissions + * Gets all the history. * - * Returns: %TRUE for success + * You must have called fwupd_client_connect_async() on @self before using + * this method. * - * Since: 1.2.8 + * Since: 1.5.0 **/ -gboolean -fwupd_client_modify_config (FwupdClient *client, const gchar *key, const gchar *value, - GCancellable *cancellable, GError **error) +void +fwupd_client_get_history_async (FwupdClient *self, GCancellable *cancellable, + GAsyncReadyCallback callback, gpointer callback_data) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_autoptr(FwupdClientHelper) helper = NULL; - - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; - /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) - return FALSE; + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); /* call into daemon */ - helper = fwupd_client_helper_new (); - g_dbus_proxy_call (priv->proxy, - "ModifyConfig", - g_variant_new ("(ss)", key, value), - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - fwupd_client_proxy_call_cb, - helper); - g_main_loop_run (helper->loop); - if (!helper->ret) { - g_propagate_error (error, helper->error); - helper->error = NULL; - return FALSE; - } - return TRUE; + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "GetHistory", + NULL, G_DBUS_CALL_FLAGS_NONE, + -1, cancellable, + fwupd_client_get_history_cb, + g_steal_pointer (&task)); } /** - * fwupd_client_activate: - * @client: A #FwupdClient - * @cancellable: the #GCancellable, or %NULL - * @device_id: a device + * fwupd_client_get_history_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult * @error: the #GError, or %NULL * - * Activates up a device, which normally means the device switches to a new - * firmware version. This should only be called when data loss cannot occur. + * Gets the result of fwupd_client_get_history_async(). * - * Returns: %TRUE for success + * Returns: (element-type FwupdDevice) (transfer container): results * - * Since: 1.2.6 + * Since: 1.5.0 **/ -gboolean -fwupd_client_activate (FwupdClient *client, GCancellable *cancellable, - const gchar *device_id, GError **error) +GPtrArray * +fwupd_client_get_history_finish (FwupdClient *self, GAsyncResult *res, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_autoptr(FwupdClientHelper) helper = NULL; + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); - g_return_val_if_fail (device_id != NULL, FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); +static void +fwupd_client_get_device_by_id_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) devices = NULL; + const gchar *device_id = g_task_get_task_data (task); - /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) - return FALSE; + devices = fwupd_client_get_devices_finish (FWUPD_CLIENT (source), res, &error); + if (devices == NULL) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } - /* call into daemon */ - helper = fwupd_client_helper_new (); - g_dbus_proxy_call (priv->proxy, - "Activate", - g_variant_new ("(s)", device_id), - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - fwupd_client_proxy_call_cb, - helper); - g_main_loop_run (helper->loop); - if (!helper->ret) { - g_propagate_error (error, helper->error); - helper->error = NULL; - return FALSE; + /* find the device by ID (client side) */ + for (guint i = 0; i < devices->len; i++) { + FwupdDevice *dev = g_ptr_array_index (devices, i); + if (g_strcmp0 (fwupd_device_get_id (dev), device_id) == 0) { + g_task_return_pointer (task, + g_object_ref (dev), + (GDestroyNotify) g_object_unref); + return; + } } - return TRUE; + + /* failed */ + g_task_return_new_error (task, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "failed to find %s", device_id); } /** - * fwupd_client_verify: - * @client: A #FwupdClient + * fwupd_client_get_device_by_id_async: + * @self: A #FwupdClient * @device_id: the device ID * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * - * Verify a specific device. + * Gets a device by it's device ID. * - * Returns: %TRUE for verification success + * You must have called fwupd_client_connect_async() on @self before using + * this method. * - * Since: 0.7.0 + * Since: 1.5.0 **/ -gboolean -fwupd_client_verify (FwupdClient *client, const gchar *device_id, - GCancellable *cancellable, GError **error) -{ - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_autoptr(FwupdClientHelper) helper = NULL; - - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); - g_return_val_if_fail (device_id != NULL, FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) - return FALSE; +void +fwupd_client_get_device_by_id_async (FwupdClient *self, const gchar *device_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (device_id != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); /* call into daemon */ - helper = fwupd_client_helper_new (); - g_dbus_proxy_call (priv->proxy, - "Verify", - g_variant_new ("(s)", device_id), - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - fwupd_client_proxy_call_cb, - helper); - g_main_loop_run (helper->loop); - if (!helper->ret) { - g_propagate_error (error, helper->error); - helper->error = NULL; - return FALSE; - } - return TRUE; + task = g_task_new (self, cancellable, callback, callback_data); + g_task_set_task_data (task, g_strdup (device_id), g_free); + fwupd_client_get_devices_async (self, cancellable, + fwupd_client_get_device_by_id_cb, + g_steal_pointer (&task)); } /** - * fwupd_client_verify_update: - * @client: A #FwupdClient - * @device_id: the device ID - * @cancellable: the #GCancellable, or %NULL + * fwupd_client_get_device_by_id_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult * @error: the #GError, or %NULL * - * Update the verification record for a specific device. + * Gets the result of fwupd_client_get_device_by_id_async(). * - * Returns: %TRUE for verification success + * Returns: (transfer full): a #FwupdDevice, or %NULL for failure * - * Since: 0.8.0 + * Since: 1.5.0 **/ -gboolean -fwupd_client_verify_update (FwupdClient *client, const gchar *device_id, - GCancellable *cancellable, GError **error) +FwupdDevice * +fwupd_client_get_device_by_id_finish (FwupdClient *self, GAsyncResult *res, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_autoptr(FwupdClientHelper) helper = NULL; + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); - g_return_val_if_fail (device_id != NULL, FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); +static void +fwupd_client_get_devices_by_guid_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) devices = NULL; + g_autoptr(GPtrArray) devices_tmp = NULL; + const gchar *guid = g_task_get_task_data (task); - /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) - return FALSE; + /* get all the devices */ + devices_tmp = fwupd_client_get_devices_finish (FWUPD_CLIENT (source), res, &error); + if (devices_tmp == NULL) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } - /* call into daemon */ - helper = fwupd_client_helper_new (); - g_dbus_proxy_call (priv->proxy, - "VerifyUpdate", - g_variant_new ("(s)", device_id), - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - fwupd_client_proxy_call_cb, - helper); - g_main_loop_run (helper->loop); - if (!helper->ret) { - g_propagate_error (error, helper->error); - helper->error = NULL; - return FALSE; + /* find the devices by GUID (client side) */ + devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + for (guint i = 0; i < devices_tmp->len; i++) { + FwupdDevice *dev_tmp = g_ptr_array_index (devices_tmp, i); + if (fwupd_device_has_guid (dev_tmp, guid)) + g_ptr_array_add (devices, g_object_ref (dev_tmp)); } - return TRUE; + + /* nothing */ + if (devices->len == 0) { + g_task_return_new_error (task, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "failed to find any device providing %s", guid); + return; + } + + /* success */ + g_task_return_pointer (task, + g_steal_pointer (&devices), + (GDestroyNotify) g_ptr_array_unref); } /** - * fwupd_client_unlock: - * @client: A #FwupdClient - * @device_id: the device ID + * fwupd_client_get_devices_by_guid_async: + * @self: A #FwupdClient + * @guid: the GUID, e.g. `e22c4520-43dc-5bb3-8245-5787fead9b63` * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * + * Gets any devices that provide a specific GUID. An error is returned if no + * devices contains this GUID. + * + * You must have called fwupd_client_connect_async() on @self before using + * this method. + * + * Since: 1.5.0 + **/ +void +fwupd_client_get_devices_by_guid_async (FwupdClient *self, const gchar *guid, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (guid != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* call into daemon */ + task = g_task_new (self, cancellable, callback, callback_data); + g_task_set_task_data (task, g_strdup (guid), g_free); + fwupd_client_get_devices_async (self, cancellable, + fwupd_client_get_devices_by_guid_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_get_devices_by_guid_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult * @error: the #GError, or %NULL * - * Unlocks a specific device so firmware can be read or wrote. + * Gets the result of fwupd_client_get_devices_by_guid_async(). * - * Returns: %TRUE for success + * Returns: (element-type FwupdRelease) (transfer container): results * - * Since: 0.7.0 + * Since: 1.5.0 **/ -gboolean -fwupd_client_unlock (FwupdClient *client, const gchar *device_id, - GCancellable *cancellable, GError **error) +GPtrArray * +fwupd_client_get_devices_by_guid_finish (FwupdClient *self, GAsyncResult *res, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_autoptr(FwupdClientHelper) helper = NULL; - - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); - g_return_val_if_fail (device_id != NULL, FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} - /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) - return FALSE; +static void +fwupd_client_get_releases_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; - /* call into daemon */ - helper = fwupd_client_helper_new (); - g_dbus_proxy_call (priv->proxy, - "Unlock", - g_variant_new ("(s)", device_id), - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - fwupd_client_proxy_call_cb, - helper); - g_main_loop_run (helper->loop); - if (!helper->ret) { - g_propagate_error (error, helper->error); - helper->error = NULL; - return FALSE; + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; } - return TRUE; + + /* success */ + g_task_return_pointer (task, + fwupd_release_array_from_variant (val), + (GDestroyNotify) g_ptr_array_unref); } /** - * fwupd_client_clear_results: - * @client: A #FwupdClient + * fwupd_client_get_releases_async: + * @self: A #FwupdClient * @device_id: the device ID * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * - * Clears the results for a specific device. + * Gets all the releases for a specific device * - * Returns: %TRUE for success + * You must have called fwupd_client_connect_async() on @self before using + * this method. * - * Since: 0.7.0 + * Since: 1.5.0 **/ -gboolean -fwupd_client_clear_results (FwupdClient *client, const gchar *device_id, - GCancellable *cancellable, GError **error) -{ - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_autoptr(FwupdClientHelper) helper = NULL; - - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); - g_return_val_if_fail (device_id != NULL, FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) - return FALSE; +void +fwupd_client_get_releases_async (FwupdClient *self, const gchar *device_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (device_id != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); /* call into daemon */ - helper = fwupd_client_helper_new (); - g_dbus_proxy_call (priv->proxy, - "ClearResults", + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "GetReleases", g_variant_new ("(s)", device_id), G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - fwupd_client_proxy_call_cb, - helper); - g_main_loop_run (helper->loop); - if (!helper->ret) { - g_propagate_error (error, helper->error); - helper->error = NULL; - return FALSE; - } - return TRUE; + -1, cancellable, + fwupd_client_get_releases_cb, + g_steal_pointer (&task)); } /** - * fwupd_client_get_results: - * @client: A #FwupdClient - * @device_id: the device ID - * @cancellable: the #GCancellable, or %NULL + * fwupd_client_get_releases_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult * @error: the #GError, or %NULL * - * Gets the results of a previous firmware update for a specific device. + * Gets the result of fwupd_client_get_releases_async(). * - * Returns: (transfer full): a #FwupdDevice, or %NULL for failure + * Returns: (element-type FwupdRelease) (transfer container): results * - * Since: 0.7.0 + * Since: 1.5.0 **/ -FwupdDevice * -fwupd_client_get_results (FwupdClient *client, const gchar *device_id, - GCancellable *cancellable, GError **error) +GPtrArray * +fwupd_client_get_releases_finish (FwupdClient *self, GAsyncResult *res, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_autoptr(FwupdClientHelper) helper = NULL; - - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); - g_return_val_if_fail (device_id != NULL, NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) - return NULL; - - /* call into daemon */ - helper = fwupd_client_helper_new (); - g_dbus_proxy_call (priv->proxy, - "GetResults", - g_variant_new ("(s)", device_id), - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - fwupd_client_proxy_call_cb, - helper); - g_main_loop_run (helper->loop); - if (!helper->ret) { - g_propagate_error (error, helper->error); - helper->error = NULL; - return NULL; - } - return fwupd_device_from_variant (helper->val); + return g_task_propagate_pointer (G_TASK(res), error); } -#ifdef HAVE_GIO_UNIX static void -fwupd_client_send_message_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +fwupd_client_get_downgrades_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) { - FwupdClientHelper *helper = (FwupdClientHelper *) user_data; - GDBusConnection *con = G_DBUS_CONNECTION (source_object); - helper->message = g_dbus_connection_send_message_with_reply_finish (con, res, - &helper->error); - if (helper->message && - !g_dbus_message_to_gerror (helper->message, &helper->error)) { - helper->ret = TRUE; - helper->val = g_dbus_message_get_body (helper->message); - if (helper->val != NULL) - g_variant_ref (helper->val); - } - if (helper->error != NULL) - fwupd_client_fixup_dbus_error (helper->error); - g_main_loop_quit (helper->loop); -} -#endif + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_pointer (task, + fwupd_release_array_from_variant (val), + (GDestroyNotify) g_ptr_array_unref); +} + +/** + * fwupd_client_get_downgrades_async: + * @self: A #FwupdClient + * @device_id: the device ID + * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * + * Gets all the downgrades for a specific device. + * + * You must have called fwupd_client_connect_async() on @self before using + * this method. + * + * Since: 1.5.0 + **/ +void +fwupd_client_get_downgrades_async (FwupdClient *self, const gchar *device_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (device_id != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* call into daemon */ + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "GetDowngrades", + g_variant_new ("(s)", device_id), + G_DBUS_CALL_FLAGS_NONE, + -1, cancellable, + fwupd_client_get_downgrades_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_get_downgrades_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_get_downgrades_async(). + * + * Returns: (element-type FwupdRelease) (transfer container): results + * + * Since: 1.5.0 + **/ +GPtrArray * +fwupd_client_get_downgrades_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} + +static void +fwupd_client_get_upgrades_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_pointer (task, + fwupd_release_array_from_variant (val), + (GDestroyNotify) g_ptr_array_unref); +} + +/** + * fwupd_client_get_upgrades_async: + * @self: A #FwupdClient + * @device_id: the device ID + * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * + * Gets all the upgrades for a specific device. + * + * You must have called fwupd_client_connect_async() on @self before using + * this method. + * + * Since: 1.5.0 + **/ +void +fwupd_client_get_upgrades_async (FwupdClient *self, const gchar *device_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (device_id != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* call into daemon */ + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "GetUpgrades", + g_variant_new ("(s)", device_id), + G_DBUS_CALL_FLAGS_NONE, + -1, cancellable, + fwupd_client_get_upgrades_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_get_upgrades_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_get_upgrades_async(). + * + * Returns: (element-type FwupdRelease) (transfer container): results + * + * Since: 1.5.0 + **/ +GPtrArray * +fwupd_client_get_upgrades_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} + +static void +fwupd_client_modify_config_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_boolean (task, TRUE); +} + +/** + * fwupd_client_modify_config_async: + * @self: A #FwupdClient + * @key: key, e.g. `DisabledPlugins` + * @value: value, e.g. `*` + * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * + * Modifies a daemon config option. + * The daemon will only respond to this request with proper permissions + * + * Since: 1.5.0 + **/ +void +fwupd_client_modify_config_async (FwupdClient *self, + const gchar *key, + const gchar *value, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (key != NULL); + g_return_if_fail (value != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* call into daemon */ + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "ModifyConfig", + g_variant_new ("(ss)", key, value), + G_DBUS_CALL_FLAGS_NONE, -1, + cancellable, + fwupd_client_modify_config_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_modify_config_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_modify_config_async(). + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fwupd_client_modify_config_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); +} + +static void +fwupd_client_activate_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_boolean (task, TRUE); +} + +/** + * fwupd_client_activate_async: + * @self: A #FwupdClient + * @device_id: a device + * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * + * Activates up a device, which normally means the device switches to a new + * firmware version. This should only be called when data loss cannot occur. + * + * Since: 1.5.0 + **/ +void +fwupd_client_activate_async (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (device_id != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* call into daemon */ + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "Activate", + g_variant_new ("(s)", device_id), + G_DBUS_CALL_FLAGS_NONE, -1, + cancellable, + fwupd_client_activate_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_activate_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_activate_async(). + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fwupd_client_activate_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); +} + +static void +fwupd_client_verify_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_boolean (task, TRUE); +} + +/** + * fwupd_client_verify_async: + * @self: A #FwupdClient + * @device_id: the device ID + * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * + * Verify a specific device. + * + * Since: 1.5.0 + **/ +void +fwupd_client_verify_async (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (device_id != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* call into daemon */ + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "Verify", + g_variant_new ("(s)", device_id), + G_DBUS_CALL_FLAGS_NONE, -1, + cancellable, + fwupd_client_verify_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_verify_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_verify_async(). + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fwupd_client_verify_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); +} + +static void +fwupd_client_verify_update_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_boolean (task, TRUE); +} + +/** + * fwupd_client_verify_update_async: + * @self: A #FwupdClient + * @device_id: the device ID + * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * + * Update the verification record for a specific device. + * + * Since: 1.5.0 + **/ +void +fwupd_client_verify_update_async (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (device_id != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* call into daemon */ + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "VerifyUpdate", + g_variant_new ("(s)", device_id), + G_DBUS_CALL_FLAGS_NONE, -1, + cancellable, + fwupd_client_verify_update_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_verify_update_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_verify_update_async(). + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fwupd_client_verify_update_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); +} + +static void +fwupd_client_unlock_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_boolean (task, TRUE); +} + +/** + * fwupd_client_unlock_async: + * @self: A #FwupdClient + * @device_id: the device ID + * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * + * Unlocks a specific device so firmware can be read or wrote. + * + * Since: 1.5.0 + **/ +void +fwupd_client_unlock_async (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (device_id != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* call into daemon */ + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "Unlock", + g_variant_new ("(s)", device_id), + G_DBUS_CALL_FLAGS_NONE, -1, + cancellable, + fwupd_client_unlock_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_unlock_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_unlock_async(). + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fwupd_client_unlock_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); +} + +static void +fwupd_client_clear_results_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_boolean (task, TRUE); +} + +/** + * fwupd_client_clear_results_async: + * @self: A #FwupdClient + * @device_id: a device + * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * + * Clears the results for a specific device. + * + * Since: 1.5.0 + **/ +void +fwupd_client_clear_results_async (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (device_id != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* call into daemon */ + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "ClearResults", + g_variant_new ("(s)", device_id), + G_DBUS_CALL_FLAGS_NONE, -1, + cancellable, + fwupd_client_clear_results_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_clear_results_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_clear_results_async(). + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fwupd_client_clear_results_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); +} + +static void +fwupd_client_get_results_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_pointer (task, + fwupd_device_from_variant (val), + (GDestroyNotify) g_ptr_array_unref); +} + +/** + * fwupd_client_get_results_async: + * @self: A #FwupdClient + * @device_id: the device ID + * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * + * Gets the results of a previous firmware update for a specific device. + * + * You must have called fwupd_client_connect_async() on @self before using + * this method. + * + * Since: 1.5.0 + **/ +void +fwupd_client_get_results_async (FwupdClient *self, const gchar *device_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (device_id != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* call into daemon */ + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "GetResults", + g_variant_new ("(s)", device_id), + G_DBUS_CALL_FLAGS_NONE, + -1, cancellable, + fwupd_client_get_results_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_get_results_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_get_results_async(). + * + * Returns: (transfer full): a #FwupdDevice, or %NULL for failure + * + * Since: 1.5.0 + **/ +FwupdDevice * +fwupd_client_get_results_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} #ifdef HAVE_GIO_UNIX -static gboolean -fwupd_client_install_fd (FwupdClient *client, - const gchar *device_id, - GUnixInputStream *istr, - const gchar *filename_hint, - FwupdInstallFlags install_flags, - GCancellable *cancellable, - GError **error) + +static void +fwupd_client_install_stream_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + g_autoptr(GDBusMessage) msg = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GTask) task = G_TASK (user_data); + + msg = g_dbus_connection_send_message_with_reply_finish (G_DBUS_CONNECTION (source), + res, &error); + if (msg == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + if (g_dbus_message_to_gerror (msg, &error)) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_boolean (task, TRUE); +} + +void +fwupd_client_install_stream_async (FwupdClient *self, + const gchar *device_id, + GUnixInputStream *istr, + const gchar *filename_hint, + FwupdInstallFlags install_flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - GVariant *body; + FwupdClientPrivate *priv = GET_PRIVATE (self); GVariantBuilder builder; - gint retval; - g_autoptr(FwupdClientHelper) helper = NULL; g_autoptr(GDBusMessage) request = NULL; g_autoptr(GUnixFDList) fd_list = NULL; + g_autoptr(GTask) task = g_task_new (self, cancellable, callback, callback_data); /* set options */ g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); @@ -1170,10 +2216,18 @@ g_variant_builder_add (&builder, "{sv}", "allow-reinstall", g_variant_new_boolean (TRUE)); } + if (install_flags & FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH) { + g_variant_builder_add (&builder, "{sv}", + "allow-branch-switch", g_variant_new_boolean (TRUE)); + } if (install_flags & FWUPD_INSTALL_FLAG_FORCE) { g_variant_builder_add (&builder, "{sv}", "force", g_variant_new_boolean (TRUE)); } + if (install_flags & FWUPD_INSTALL_FLAG_IGNORE_POWER) { + g_variant_builder_add (&builder, "{sv}", + "ignore-power", g_variant_new_boolean (TRUE)); + } if (install_flags & FWUPD_INSTALL_FLAG_NO_HISTORY) { g_variant_builder_add (&builder, "{sv}", "no-history", g_variant_new_boolean (TRUE)); @@ -1181,8 +2235,7 @@ /* set out of band file descriptor */ fd_list = g_unix_fd_list_new (); - retval = g_unix_fd_list_append (fd_list, g_unix_input_stream_get_fd (istr), NULL); - g_assert (retval != -1); + g_unix_fd_list_append (fd_list, g_unix_input_stream_get_fd (istr), NULL); request = g_dbus_message_new_method_call (FWUPD_DBUS_SERVICE, FWUPD_DBUS_PATH, FWUPD_DBUS_INTERFACE, @@ -1190,315 +2243,648 @@ g_dbus_message_set_unix_fd_list (request, fd_list); /* call into daemon */ - helper = fwupd_client_helper_new (); - body = g_variant_new ("(sha{sv})", device_id, g_unix_input_stream_get_fd (istr), &builder); - g_dbus_message_set_body (request, body); - g_dbus_connection_send_message_with_reply (priv->conn, + g_dbus_message_set_body (request, g_variant_new ("(sha{sv})", + device_id, + g_unix_input_stream_get_fd (istr), + &builder)); + g_dbus_connection_send_message_with_reply (g_dbus_proxy_get_connection (priv->proxy), request, G_DBUS_SEND_MESSAGE_FLAGS_NONE, G_MAXINT, NULL, cancellable, - fwupd_client_send_message_cb, - helper); - g_main_loop_run (helper->loop); - if (!helper->ret) { - g_propagate_error (error, helper->error); - helper->error = NULL; - return FALSE; - } - return TRUE; + fwupd_client_install_stream_cb, + g_steal_pointer (&task)); } #endif /** - * fwupd_client_install_bytes: - * @client: A #FwupdClient + * fwupd_client_install_bytes_async: + * @self: A #FwupdClient * @device_id: the device ID * @bytes: #GBytes * @install_flags: the #FwupdInstallFlags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * * Install firmware onto a specific device. * - * Returns: %TRUE for success + * NOTE: This method is thread-safe, but progress signals will be + * emitted in the global default main context, if not explicitly set with + * fwupd_client_set_main_context(). * - * Since: 1.4.5 + * Since: 1.5.0 **/ -gboolean -fwupd_client_install_bytes (FwupdClient *client, - const gchar *device_id, - GBytes *bytes, - FwupdInstallFlags install_flags, - GCancellable *cancellable, - GError **error) +void +fwupd_client_install_bytes_async (FwupdClient *self, + const gchar *device_id, + GBytes *bytes, + FwupdInstallFlags install_flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) { #ifdef HAVE_GIO_UNIX + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GError) error = NULL; g_autoptr(GUnixInputStream) istr = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); - g_return_val_if_fail (device_id != NULL, FALSE); - g_return_val_if_fail (bytes != NULL, FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) - return FALSE; + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* move to a thread if this ever takes more than a few ms */ + istr = fwupd_unix_input_stream_from_bytes (bytes, &error); + if (istr == NULL) { + g_autoptr(GTask) task = g_task_new (self, cancellable, callback, callback_data); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } - istr = fwupd_unix_input_stream_from_bytes (bytes, error); - if (istr == NULL) - return FALSE; - return fwupd_client_install_fd (client, device_id, istr, NULL, - install_flags, cancellable, error); + /* call into daemon */ + fwupd_client_install_stream_async (self, device_id, istr, NULL, + install_flags, cancellable, + callback, callback_data); #else - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Not supported as is unavailable"); - return FALSE; + g_autoptr(GTask) task = g_task_new (self, cancellable, callback, callback_data); + g_task_return_new_error (task, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as is unavailable"); #endif } /** - * fwupd_client_install: - * @client: A #FwupdClient + * fwupd_client_install_bytes_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_install_bytes_async(). + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fwupd_client_install_bytes_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); +} + +/** + * fwupd_client_install_async: + * @self: A #FwupdClient * @device_id: the device ID * @filename: the filename to install * @install_flags: the #FwupdInstallFlags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * - * Install a file onto a specific device. + * Install firmware onto a specific device. * - * Returns: %TRUE for success + * NOTE: This method is thread-safe, but progress signals will be + * emitted in the global default main context, if not explicitly set with + * fwupd_client_set_main_context(). * - * Since: 0.7.0 + * Since: 1.5.0 **/ -gboolean -fwupd_client_install (FwupdClient *client, - const gchar *device_id, - const gchar *filename, - FwupdInstallFlags install_flags, - GCancellable *cancellable, - GError **error) +void +fwupd_client_install_async (FwupdClient *self, + const gchar *device_id, + const gchar *filename, + FwupdInstallFlags install_flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) { #ifdef HAVE_GIO_UNIX + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GError) error = NULL; g_autoptr(GUnixInputStream) istr = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); - g_return_val_if_fail (device_id != NULL, FALSE); - g_return_val_if_fail (filename != NULL, FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (device_id != NULL); + g_return_if_fail (filename != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* move to a thread if this ever takes more than a few ms */ + istr = fwupd_unix_input_stream_from_fn (filename, &error); + if (istr == NULL) { + g_autoptr(GTask) task = g_task_new (self, cancellable, callback, callback_data); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* call into daemon */ + fwupd_client_install_stream_async (self, device_id, istr, NULL, + install_flags, cancellable, + callback, callback_data); +#else + g_autoptr(GTask) task = g_task_new (self, cancellable, callback, callback_data); + g_task_return_new_error (task, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as is unavailable"); +#endif +} + +/** + * fwupd_client_install_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_install_async(). + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fwupd_client_install_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); +} - /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) - return FALSE; +typedef struct { + FwupdDevice *device; + FwupdRelease *release; + FwupdInstallFlags install_flags; + FwupdClientDownloadFlags download_flags; +} FwupdClientInstallReleaseData; - istr = fwupd_unix_input_stream_from_fn (filename, error); - if (istr == NULL) - return FALSE; - return fwupd_client_install_fd (client, device_id, istr, filename, - install_flags, cancellable, error); +static void +fwupd_client_install_release_data_free (FwupdClientInstallReleaseData *data) +{ + g_object_unref (data->device); + g_object_unref (data->release); + g_free (data); +} + +static void +fwupd_client_install_release_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + g_autoptr(GError) error = NULL; + g_autoptr(GTask) task = G_TASK (user_data); + + if (!fwupd_client_install_release_finish (FWUPD_CLIENT (source), res, &error)) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_boolean (task, TRUE); +} + +static void +fwupd_client_install_release_bytes_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + g_autoptr(GError) error = NULL; + g_autoptr(GTask) task = G_TASK (user_data); + + if (!fwupd_client_install_bytes_finish (FWUPD_CLIENT (source), res, &error)) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_boolean (task, TRUE); +} + +static void +fwupd_client_install_release_download_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + g_autoptr(GBytes) blob = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GTask) task = G_TASK (user_data); + FwupdClientInstallReleaseData *data = g_task_get_task_data (task); + GChecksumType checksum_type; + GCancellable *cancellable = g_task_get_cancellable (task); + const gchar *checksum_expected; + g_autofree gchar *checksum_actual = NULL; + + blob = fwupd_client_download_bytes_finish (FWUPD_CLIENT (source), res, &error); + if (blob == NULL) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* verify checksum */ + checksum_expected = fwupd_checksum_get_best (fwupd_release_get_checksums (data->release)); + checksum_type = fwupd_checksum_guess_kind (checksum_expected); + checksum_actual = g_compute_checksum_for_bytes (checksum_type, blob); + if (g_strcmp0 (checksum_expected, checksum_actual) != 0) { + g_task_return_new_error (task, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "checksum invalid, expected %s got %s", + checksum_expected, checksum_actual); + return; + } + + /* if the device specifies ONLY_OFFLINE automatically set this flag */ + if (fwupd_device_has_flag (data->device, FWUPD_DEVICE_FLAG_ONLY_OFFLINE)) + data->install_flags |= FWUPD_INSTALL_FLAG_OFFLINE; + fwupd_client_install_bytes_async (FWUPD_CLIENT (source), + fwupd_device_get_id (data->device), blob, + data->install_flags, cancellable, + fwupd_client_install_release_bytes_cb, + g_steal_pointer (&task)); +} + +static gboolean +fwupd_client_is_url_http (const gchar *perhaps_url) +{ +#ifdef HAVE_LIBCURL_7_62_0 + g_autoptr(CURLU) h = curl_url (); + return curl_url_set (h, CURLUPART_URL, perhaps_url, 0) == CURLUE_OK; #else - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Not supported as is unavailable"); - return FALSE; + return g_str_has_prefix (perhaps_url, "http://") || + g_str_has_prefix (perhaps_url, "https://"); #endif } +static gboolean +fwupd_client_is_url_ipfs (const gchar *perhaps_url) +{ + return g_str_has_prefix (perhaps_url, "ipfs://") || + g_str_has_prefix (perhaps_url, "ipns://"); +} + +static void +fwupd_client_install_release_remote_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + GPtrArray *locations; + const gchar *uri_tmp; + g_autofree gchar *fn = NULL; + g_autoptr(FwupdRemote) remote = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GPtrArray) uris_built = g_ptr_array_new_with_free_func (g_free); + FwupdClientInstallReleaseData *data = g_task_get_task_data (task); + GCancellable *cancellable = g_task_get_cancellable (task); + + /* if a remote-id was specified, the remote has to exist */ + remote = fwupd_client_get_remote_by_id_finish (FWUPD_CLIENT (source), res, &error); + if (remote == NULL) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* get the default release only until other parts of fwupd can cope */ + locations = fwupd_release_get_locations (data->release); + if (locations->len == 0) { + g_task_return_new_error (task, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "release missing URI"); + return; + } + uri_tmp = g_ptr_array_index (locations, 0); + + /* local and directory remotes may have the firmware already */ + if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_LOCAL && + !fwupd_client_is_url_http (uri_tmp)) { + const gchar *fn_cache = fwupd_remote_get_filename_cache (remote); + g_autofree gchar *path = g_path_get_dirname (fn_cache); + fn = g_build_filename (path, uri_tmp, NULL); + } else if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_DIRECTORY) { + fn = g_strdup (uri_tmp + 7); + } + + /* install with flags chosen by the user */ + if (fn != NULL) { + fwupd_client_install_async (FWUPD_CLIENT (source), + fwupd_device_get_id (data->device), + fn, data->install_flags, + cancellable, + fwupd_client_install_release_cb, + g_steal_pointer (&task)); + return; + } + + /* remote file */ + for (guint i = 0; i < locations->len; i++) { + uri_tmp = g_ptr_array_index (locations, i); + if (fwupd_client_is_url_ipfs (uri_tmp)) { + g_ptr_array_add (uris_built, g_strdup (uri_tmp)); + } else if (fwupd_client_is_url_http (uri_tmp)) { + g_autofree gchar *uri_str = NULL; + uri_str = fwupd_remote_build_firmware_uri (remote, + uri_tmp, + &error); + if (uri_str == NULL) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + g_ptr_array_add (uris_built, g_steal_pointer (&uri_str)); + } + } + + /* download file */ + fwupd_client_download_bytes2_async (FWUPD_CLIENT (source), + uris_built, + data->download_flags, + cancellable, + fwupd_client_install_release_download_cb, + g_steal_pointer (&task)); +} + +#ifdef HAVE_LIBCURL +static GPtrArray * +fwupd_client_filter_locations (GPtrArray *locations, + FwupdClientDownloadFlags download_flags, + GError **error) +{ + g_autoptr(GPtrArray) uris_filtered = g_ptr_array_new_with_free_func (g_free); + + g_return_val_if_fail (locations != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + for (guint i = 0; i < locations->len; i++) { + const gchar *uri = g_ptr_array_index (locations, i); + if ((download_flags & FWUPD_CLIENT_DOWNLOAD_FLAG_ONLY_IPFS) > 0 && + !fwupd_client_is_url_ipfs (uri)) + continue; + g_ptr_array_add (uris_filtered, g_strdup (uri)); + } + if (uris_filtered->len == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "no valid release URIs"); + return NULL; + } + return g_steal_pointer (&uris_filtered); +} +#endif + /** - * fwupd_client_install_release: - * @client: A #FwupdClient + * fwupd_client_install_release2_async: + * @self: A #FwupdClient * @device: A #FwupdDevice * @release: A #FwupdRelease * @install_flags: the #FwupdInstallFlags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL - * @cancellable: A #GCancellable, or %NULL - * @error: A #GError, or %NULL + * @download_flags: the #FwupdClientDownloadFlags, e.g. %FWUPD_CLIENT_DOWNLOAD_FLAG_DISABLE_IPFS + * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * * Installs a new release on a device, downloading the firmware if required. * - * Returns: %TRUE for success + * NOTE: This method is thread-safe, but progress signals will be + * emitted in the global default main context, if not explicitly set with + * fwupd_client_set_main_context(). * - * Since: 1.4.5 + * Since: 1.5.6 **/ -gboolean -fwupd_client_install_release (FwupdClient *client, - FwupdDevice *device, - FwupdRelease *release, - FwupdInstallFlags install_flags, - GCancellable *cancellable, - GError **error) -{ - GChecksumType checksum_type; - const gchar *checksum_expected; +void +fwupd_client_install_release2_async (FwupdClient *self, + FwupdDevice *device, + FwupdRelease *release, + FwupdInstallFlags install_flags, + FwupdClientDownloadFlags download_flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + FwupdClientInstallReleaseData *data; const gchar *remote_id; - const gchar *uri_tmp; - g_autofree gchar *checksum_actual = NULL; - g_autofree gchar *uri_str = NULL; - g_autoptr(GBytes) blob = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (FWUPD_IS_DEVICE (device)); + g_return_if_fail (FWUPD_IS_RELEASE (release)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* call into daemon */ + task = g_task_new (self, cancellable, callback, callback_data); + data = g_new0 (FwupdClientInstallReleaseData, 1); + data->device = g_object_ref (device); + data->release = g_object_ref (release); + data->download_flags = download_flags; + data->install_flags = install_flags; + g_task_set_task_data (task, data, (GDestroyNotify) fwupd_client_install_release_data_free); /* work out what remote-specific URI fields this should use */ - uri_tmp = fwupd_release_get_uri (release); remote_id = fwupd_release_get_remote_id (release); - if (remote_id != NULL) { - g_autoptr(FwupdRemote) remote = NULL; - g_autofree gchar *fn = NULL; + if (remote_id == NULL) { + fwupd_client_download_bytes2_async (self, + fwupd_release_get_locations (release), + download_flags, + cancellable, + fwupd_client_install_release_download_cb, + g_steal_pointer (&task)); + return; + } - /* if a remote-id was specified, the remote has to exist */ - remote = fwupd_client_get_remote_by_id (client, remote_id, cancellable, error); - if (remote == NULL) - return FALSE; - - /* local and directory remotes have the firmware already */ - if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_LOCAL) { - const gchar *fn_cache = fwupd_remote_get_filename_cache (remote); - g_autofree gchar *path = g_path_get_dirname (fn_cache); - - fn = g_build_filename (path, uri_tmp, NULL); - } else if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_DIRECTORY) { - fn = g_strdup (uri_tmp + 7); - } + /* if a remote-id was specified, the remote has to exist */ + fwupd_client_get_remote_by_id_async (self, remote_id, cancellable, + fwupd_client_install_release_remote_cb, + g_steal_pointer (&task)); +} - /* install with flags chosen by the user */ - if (fn != NULL) { - return fwupd_client_install (client, fwupd_device_get_id (device), - fn, install_flags, cancellable, error); - } +/** + * fwupd_client_install_release_async: + * @self: A #FwupdClient + * @device: A #FwupdDevice + * @release: A #FwupdRelease + * @install_flags: the #FwupdInstallFlags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL + * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * + * Installs a new release on a device, downloading the firmware if required. + * + * NOTE: This method is thread-safe, but progress signals will be + * emitted in the global default main context, if not explicitly set with + * fwupd_client_set_main_context(). + * + * Since: 1.5.0 + * Deprecated: 1.5.6 + **/ +void +fwupd_client_install_release_async (FwupdClient *self, + FwupdDevice *device, + FwupdRelease *release, + FwupdInstallFlags install_flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + return fwupd_client_install_release2_async (self, device, release, install_flags, + FWUPD_CLIENT_DOWNLOAD_FLAG_NONE, + cancellable, callback, callback_data); +} - /* remote file */ - uri_str = fwupd_remote_build_firmware_uri (remote, uri_tmp, error); - if (uri_str == NULL) - return FALSE; - } else { - uri_str = g_strdup (uri_tmp); - } +/** + * fwupd_client_install_release_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_install_release_async(). + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fwupd_client_install_release_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); +} - /* download file */ - blob = fwupd_client_download_bytes (client, uri_str, - FWUPD_CLIENT_DOWNLOAD_FLAG_NONE, - cancellable, error); - if (blob == NULL) - return FALSE; +#ifdef HAVE_GIO_UNIX - /* verify checksum */ - checksum_expected = fwupd_checksum_get_best (fwupd_release_get_checksums (release)); - checksum_type = fwupd_checksum_guess_kind (checksum_expected); - checksum_actual = g_compute_checksum_for_bytes (checksum_type, blob); - if (g_strcmp0 (checksum_expected, checksum_actual) != 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Checksum invalid, expected %s got %s", - checksum_expected, checksum_actual); - return FALSE; +static void +fwupd_client_get_details_stream_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + g_autoptr(GDBusMessage) msg = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GTask) task = G_TASK (user_data); + + msg = g_dbus_connection_send_message_with_reply_finish (G_DBUS_CONNECTION (source), + res, &error); + if (msg == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + if (g_dbus_message_to_gerror (msg, &error)) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; } - /* if the device specifies ONLY_OFFLINE automatically set this flag */ - if (fwupd_device_has_flag (device, FWUPD_DEVICE_FLAG_ONLY_OFFLINE)) - install_flags |= FWUPD_INSTALL_FLAG_OFFLINE; - return fwupd_client_install_bytes (client, - fwupd_device_get_id (device), blob, - install_flags, NULL, error); + /* success */ + g_task_return_pointer (task, + fwupd_device_array_from_variant (g_dbus_message_get_body (msg)), + (GDestroyNotify) g_ptr_array_unref); } -/** - * fwupd_client_get_details: - * @client: A #FwupdClient - * @filename: the firmware filename, e.g. `firmware.cab` - * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL - * - * Gets details about a specific firmware file. - * - * Returns: (transfer container) (element-type FwupdDevice): an array of results - * - * Since: 1.0.0 - **/ -GPtrArray * -fwupd_client_get_details (FwupdClient *client, const gchar *filename, - GCancellable *cancellable, GError **error) +void +fwupd_client_get_details_stream_async (FwupdClient *self, + GUnixInputStream *istr, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) { -#ifdef HAVE_GIO_UNIX - FwupdClientPrivate *priv = GET_PRIVATE (client); - GVariant *body; - gint fd; - gint retval; - g_autoptr(FwupdClientHelper) helper = NULL; + FwupdClientPrivate *priv = GET_PRIVATE (self); + gint fd = g_unix_input_stream_get_fd (istr); g_autoptr(GDBusMessage) request = NULL; g_autoptr(GUnixFDList) fd_list = NULL; - - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); - g_return_val_if_fail (filename != NULL, NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) - return NULL; - - /* open file */ - fd = open (filename, O_RDONLY); - if (fd < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "failed to open %s", - filename); - return NULL; - } + g_autoptr(GTask) task = g_task_new (self, cancellable, callback, callback_data); /* set out of band file descriptor */ fd_list = g_unix_fd_list_new (); - retval = g_unix_fd_list_append (fd_list, fd, NULL); - g_assert (retval != -1); + g_unix_fd_list_append (fd_list, fd, NULL); request = g_dbus_message_new_method_call (FWUPD_DBUS_SERVICE, FWUPD_DBUS_PATH, FWUPD_DBUS_INTERFACE, "GetDetails"); g_dbus_message_set_unix_fd_list (request, fd_list); - /* g_unix_fd_list_append did a dup() already */ - close (fd); - /* call into daemon */ - helper = fwupd_client_helper_new (); - body = g_variant_new ("(h)", fd); - g_dbus_message_set_body (request, body); - - g_dbus_connection_send_message_with_reply (priv->conn, + g_dbus_message_set_body (request, g_variant_new ("(h)", fd)); + g_dbus_connection_send_message_with_reply (g_dbus_proxy_get_connection (priv->proxy), request, G_DBUS_SEND_MESSAGE_FLAGS_NONE, - -1, + G_MAXINT, NULL, cancellable, - fwupd_client_send_message_cb, - helper); - g_main_loop_run (helper->loop); - if (!helper->ret) { - g_propagate_error (error, helper->error); - helper->error = NULL; - return NULL; + fwupd_client_get_details_stream_cb, + g_steal_pointer (&task)); +} +#endif + +/** + * fwupd_client_get_details_bytes_async: + * @self: A #FwupdClient + * @bytes: a #GBytes for the firmware, e.g. `firmware.cab` + * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * + * Gets details about a specific firmware file. + * + * Since: 1.5.0 + **/ +void +fwupd_client_get_details_bytes_async (FwupdClient *self, + GBytes *bytes, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ +#ifdef HAVE_GIO_UNIX + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GError) error = NULL; + g_autoptr(GUnixInputStream) istr = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* move to a thread if this ever takes more than a few ms */ + istr = fwupd_unix_input_stream_from_bytes (bytes, &error); + if (istr == NULL) { + g_autoptr(GTask) task = g_task_new (self, cancellable, callback, callback_data); + g_task_return_error (task, g_steal_pointer (&error)); + return; } - /* return results */ - return fwupd_device_array_from_variant (helper->val); + /* call into daemon */ + fwupd_client_get_details_stream_async (self, istr, cancellable, + callback, callback_data); #else - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Not supported as is unavailable"); - return NULL; + g_autoptr(GTask) task = g_task_new (self, cancellable, callback, callback_data); + g_task_return_new_error (task, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as is unavailable"); #endif } /** + * fwupd_client_get_details_bytes_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_get_details_bytes_async(). + * + * Returns: (transfer container) (element-type FwupdDevice): an array of results + * + * Since: 1.5.0 + **/ +GPtrArray * +fwupd_client_get_details_bytes_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} + +/** * fwupd_client_get_percentage: - * @client: A #FwupdClient + * @self: A #FwupdClient * * Gets the last returned percentage value. * @@ -1507,16 +2893,16 @@ * Since: 0.7.3 **/ guint -fwupd_client_get_percentage (FwupdClient *client) +fwupd_client_get_percentage (FwupdClient *self) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_return_val_if_fail (FWUPD_IS_CLIENT (client), 0); + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), 0); return priv->percentage; } /** * fwupd_client_get_daemon_version: - * @client: A #FwupdClient + * @self: A #FwupdClient * * Gets the daemon version number. * @@ -1525,16 +2911,16 @@ * Since: 0.9.6 **/ const gchar * -fwupd_client_get_daemon_version (FwupdClient *client) +fwupd_client_get_daemon_version (FwupdClient *self) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); return priv->daemon_version; } /** * fwupd_client_get_host_product: - * @client: A #FwupdClient + * @self: A #FwupdClient * * Gets the string that represents the host running fwupd * @@ -1543,16 +2929,16 @@ * Since: 1.3.1 **/ const gchar * -fwupd_client_get_host_product (FwupdClient *client) +fwupd_client_get_host_product (FwupdClient *self) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); return priv->host_product; } /** * fwupd_client_get_host_machine_id: - * @client: A #FwupdClient + * @self: A #FwupdClient * * Gets the string that represents the host machine ID * @@ -1561,16 +2947,34 @@ * Since: 1.3.2 **/ const gchar * -fwupd_client_get_host_machine_id (FwupdClient *client) +fwupd_client_get_host_machine_id (FwupdClient *self) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); return priv->host_machine_id; } /** + * fwupd_client_get_host_security_id: + * @self: A #FwupdClient + * + * Gets the string that represents the host machine ID + * + * Returns: a string, or %NULL for unknown. + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_client_get_host_security_id (FwupdClient *self) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + return priv->host_security_id; +} + +/** * fwupd_client_get_status: - * @client: A #FwupdClient + * @self: A #FwupdClient * * Gets the last returned status value. * @@ -1579,492 +2983,939 @@ * Since: 0.7.3 **/ FwupdStatus -fwupd_client_get_status (FwupdClient *client) +fwupd_client_get_status (FwupdClient *self) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FWUPD_STATUS_UNKNOWN); + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FWUPD_STATUS_UNKNOWN); return priv->status; } /** * fwupd_client_get_tainted: - * @client: A #FwupdClient + * @self: A #FwupdClient + * + * Gets if the daemon has been tainted by 3rd party code. + * + * Returns: %TRUE if the daemon is unsupported + * + * Since: 1.2.4 + **/ +gboolean +fwupd_client_get_tainted (FwupdClient *self) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + return priv->tainted; +} + +/** + * fwupd_client_get_daemon_interactive: + * @self: A #FwupdClient + * + * Gets if the daemon is running in an interactive terminal. + * + * Returns: %TRUE if the daemon is running in an interactive terminal + * + * Since: 1.3.4 + **/ +gboolean +fwupd_client_get_daemon_interactive (FwupdClient *self) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + return priv->interactive; +} + +#ifdef HAVE_GIO_UNIX + +static void +fwupd_client_update_metadata_stream_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + g_autoptr(GDBusMessage) msg = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GTask) task = G_TASK (user_data); + + msg = g_dbus_connection_send_message_with_reply_finish (G_DBUS_CONNECTION (source), + res, &error); + if (msg == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + if (g_dbus_message_to_gerror (msg, &error)) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_boolean (task, TRUE); +} + +void +fwupd_client_update_metadata_stream_async (FwupdClient *self, + const gchar *remote_id, + GUnixInputStream *istr, + GUnixInputStream *istr_sig, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GDBusMessage) request = NULL; + g_autoptr(GUnixFDList) fd_list = NULL; + g_autoptr(GTask) task = g_task_new (self, cancellable, callback, callback_data); + + /* set out of band file descriptor */ + fd_list = g_unix_fd_list_new (); + g_unix_fd_list_append (fd_list, g_unix_input_stream_get_fd (istr), NULL); + g_unix_fd_list_append (fd_list, g_unix_input_stream_get_fd (istr_sig), NULL); + request = g_dbus_message_new_method_call (FWUPD_DBUS_SERVICE, + FWUPD_DBUS_PATH, + FWUPD_DBUS_INTERFACE, + "UpdateMetadata"); + g_dbus_message_set_unix_fd_list (request, fd_list); + + /* call into daemon */ + g_dbus_message_set_body (request, g_variant_new ("(shh)", + remote_id, + g_unix_input_stream_get_fd (istr), + g_unix_input_stream_get_fd (istr_sig))); + g_dbus_connection_send_message_with_reply (g_dbus_proxy_get_connection (priv->proxy), + request, + G_DBUS_SEND_MESSAGE_FLAGS_NONE, + G_MAXINT, + NULL, + cancellable, + fwupd_client_update_metadata_stream_cb, + g_steal_pointer (&task)); +} +#endif + +/** + * fwupd_client_update_metadata_bytes_async: + * @self: A #FwupdClient + * @remote_id: remote ID, e.g. `lvfs-testing` + * @metadata: XML metadata data + * @signature: signature data + * @cancellable: #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * + * Updates the metadata. This allows a session process to download the metadata + * and metadata signing file to be passed into the daemon to be checked and + * parsed. + * + * The @remote_id allows the firmware to be tagged so that the remote can be + * matched when the firmware is downloaded. + * + * NOTE: This method is thread-safe, but progress signals will be + * emitted in the global default main context, if not explicitly set with + * fwupd_client_set_main_context(). + * + * Since: 1.5.0 + **/ +void +fwupd_client_update_metadata_bytes_async (FwupdClient *self, + const gchar *remote_id, + GBytes *metadata, + GBytes *signature, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ +#ifdef HAVE_GIO_UNIX + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GError) error = NULL; + g_autoptr(GUnixInputStream) istr = NULL; + g_autoptr(GUnixInputStream) istr_sig = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (remote_id != NULL); + g_return_if_fail (metadata != NULL); + g_return_if_fail (signature != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* move to a thread if this ever takes more than a few ms */ + istr = fwupd_unix_input_stream_from_bytes (metadata, &error); + if (istr == NULL) { + g_autoptr(GTask) task = g_task_new (self, cancellable, callback, callback_data); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + istr_sig = fwupd_unix_input_stream_from_bytes (signature, &error); + if (istr_sig == NULL) { + g_autoptr(GTask) task = g_task_new (self, cancellable, callback, callback_data); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* call into daemon */ + fwupd_client_update_metadata_stream_async (self, remote_id, istr, istr_sig, + cancellable, + callback, callback_data); +#else + g_autoptr(GTask) task = g_task_new (self, cancellable, callback, callback_data); + g_task_return_new_error (task, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as is unavailable"); +#endif +} + +/** + * fwupd_client_update_metadata_bytes_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_update_metadata_bytes_async(). + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fwupd_client_update_metadata_bytes_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); +} + +typedef struct { + FwupdRemote *remote; + GBytes *signature; + GBytes *metadata; +} FwupdClientRefreshRemoteData; + +static void +fwupd_client_refresh_remote_data_free (FwupdClientRefreshRemoteData *data) +{ + if (data->signature != NULL) + g_bytes_unref (data->signature); + if (data->metadata != NULL) + g_bytes_unref (data->metadata); + g_object_unref (data->remote); + g_free (data); +} + +static void +fwupd_client_refresh_remote_update_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GError) error = NULL; + g_autoptr(GTask) task = G_TASK (user_data); + + /* save metadata */ + if (!fwupd_client_update_metadata_bytes_finish (FWUPD_CLIENT (source), res, &error)) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_boolean (task, TRUE); +} + +static void +fwupd_client_refresh_remote_metadata_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GBytes) bytes = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GTask) task = G_TASK (user_data); + FwupdClientRefreshRemoteData *data = g_task_get_task_data (task); + FwupdClient *self = g_task_get_source_object (task); + GCancellable *cancellable = g_task_get_cancellable (task); + + /* save metadata */ + bytes = fwupd_client_download_bytes_finish (FWUPD_CLIENT (source), res, &error); + if (bytes == NULL) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + data->metadata = g_steal_pointer (&bytes); + + /* send all this to fwupd */ + fwupd_client_update_metadata_bytes_async (self, + fwupd_remote_get_id (data->remote), + data->metadata, + data->signature, + cancellable, + fwupd_client_refresh_remote_update_cb, + g_steal_pointer (&task)); +} + +static void +fwupd_client_refresh_remote_signature_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GBytes) bytes = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GTask) task = G_TASK (user_data); + FwupdClientRefreshRemoteData *data = g_task_get_task_data (task); + FwupdClient *self = g_task_get_source_object (task); + GCancellable *cancellable = g_task_get_cancellable (task); + GChecksumType checksum_kind; + g_autofree gchar *checksum = NULL; + + /* save signature */ + bytes = fwupd_client_download_bytes_finish (FWUPD_CLIENT (source), res, &error); + if (bytes == NULL) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + data->signature = g_steal_pointer (&bytes); + if (fwupd_remote_get_keyring_kind (data->remote) == FWUPD_KEYRING_KIND_JCAT) { + if (!fwupd_remote_load_signature_bytes (data->remote, data->signature, &error)) { + g_prefix_error (&error, "Failed to load signature: "); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + } + + /* is the signature checksum the same? */ + checksum_kind = fwupd_checksum_guess_kind (fwupd_remote_get_checksum (data->remote)); + checksum = g_compute_checksum_for_data (checksum_kind, + (const guchar *) g_bytes_get_data (data->signature, NULL), + g_bytes_get_size (data->signature)); + if (g_strcmp0 (checksum, fwupd_remote_get_checksum (data->remote)) == 0) { + g_debug ("metadata signature of %s is unchanged, skipping", + fwupd_remote_get_id (data->remote)); + g_task_return_boolean (task, TRUE); + return; + } + + /* download metadata */ + fwupd_client_download_bytes_async (self, + fwupd_remote_get_metadata_uri (data->remote), + FWUPD_CLIENT_DOWNLOAD_FLAG_NONE, + cancellable, + fwupd_client_refresh_remote_metadata_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_refresh_remote_async: + * @self: A #FwupdClient + * @remote: A #FwupdRemote + * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * + * Refreshes a remote by downloading new metadata. + * + * NOTE: This method is thread-safe, but progress signals will be + * emitted in the global default main context, if not explicitly set with + * fwupd_client_set_main_context(). + * + * Since: 1.5.0 + **/ +void +fwupd_client_refresh_remote_async (FwupdClient *self, + FwupdRemote *remote, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientRefreshRemoteData *data; + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (FWUPD_IS_REMOTE (remote)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + task = g_task_new (self, cancellable, callback, callback_data); + data = g_new0 (FwupdClientRefreshRemoteData, 1); + data->remote = g_object_ref (remote); + g_task_set_task_data (task, + g_steal_pointer (&data), + (GDestroyNotify) fwupd_client_refresh_remote_data_free); + + /* download signature */ + fwupd_client_download_bytes_async (self, + fwupd_remote_get_metadata_uri_sig (remote), + FWUPD_CLIENT_DOWNLOAD_FLAG_NONE, + cancellable, + fwupd_client_refresh_remote_signature_cb, + g_steal_pointer (&task)); + +} + +/** + * fwupd_client_refresh_remote_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_refresh_remote_async(). + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fwupd_client_refresh_remote_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); +} + +static void +fwupd_client_get_remotes_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* success */ + g_task_return_pointer (task, + fwupd_remote_array_from_variant (val), + (GDestroyNotify) g_ptr_array_unref); +} + +/** + * fwupd_client_get_remotes_async: + * @self: A #FwupdClient + * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * + * Gets the list of remotes that have been configured for the system. + * + * You must have called fwupd_client_connect_async() on @self before using + * this method. + * + * Since: 1.5.0 + **/ +void +fwupd_client_get_remotes_async (FwupdClient *self, GCancellable *cancellable, + GAsyncReadyCallback callback, gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* call into daemon */ + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "GetRemotes", + NULL, G_DBUS_CALL_FLAGS_NONE, + -1, cancellable, + fwupd_client_get_remotes_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_get_remotes_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL * - * Gets if the daemon has been tainted by 3rd party code. + * Gets the result of fwupd_client_get_remotes_async(). * - * Returns: %TRUE if the daemon is unsupported + * Returns: (element-type FwupdRemote) (transfer container): results * - * Since: 1.2.4 + * Since: 1.5.0 **/ -gboolean -fwupd_client_get_tainted (FwupdClient *client) +GPtrArray * +fwupd_client_get_remotes_finish (FwupdClient *self, GAsyncResult *res, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); - return priv->tainted; + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); } +static void +fwupd_client_get_approved_firmware_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_auto(GStrv) strv = NULL; + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) array = g_ptr_array_new_with_free_func (g_free); + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + g_variant_get (val, "(^as)", &strv); + for (guint i = 0; strv[i] != NULL; i++) + g_ptr_array_add (array, g_strdup (strv[i])); + + /* success */ + g_task_return_pointer (task, + g_steal_pointer (&array), + (GDestroyNotify) g_ptr_array_unref); +} /** - * fwupd_client_get_daemon_interactive: - * @client: A #FwupdClient + * fwupd_client_get_approved_firmware_async: + * @self: A #FwupdClient + * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * - * Gets if the daemon is running in an interactive terminal. + * Gets the list of approved firmware. * - * Returns: %TRUE if the daemon is running in an interactive terminal + * You must have called fwupd_client_connect_async() on @self before using + * this method. * - * Since: 1.3.4 + * Since: 1.5.0 **/ -gboolean -fwupd_client_get_daemon_interactive (FwupdClient *client) -{ - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); - return priv->interactive; -} - -#ifdef HAVE_GIO_UNIX -static gboolean -fwupd_client_update_metadata_fds (FwupdClient *client, - const gchar *remote_id, - GUnixInputStream *metadata, - GUnixInputStream *signature, - GCancellable *cancellable, - GError **error) -{ - FwupdClientPrivate *priv = GET_PRIVATE (client); - GVariant *body; - g_autoptr(FwupdClientHelper) helper = NULL; - g_autoptr(GDBusMessage) request = NULL; - g_autoptr(GUnixFDList) fd_list = NULL; - - /* set out of band file descriptor */ - fd_list = g_unix_fd_list_new (); - g_unix_fd_list_append (fd_list, g_unix_input_stream_get_fd (metadata), NULL); - g_unix_fd_list_append (fd_list, g_unix_input_stream_get_fd (signature), NULL); - request = g_dbus_message_new_method_call (FWUPD_DBUS_SERVICE, - FWUPD_DBUS_PATH, - FWUPD_DBUS_INTERFACE, - "UpdateMetadata"); - g_dbus_message_set_unix_fd_list (request, fd_list); +void +fwupd_client_get_approved_firmware_async (FwupdClient *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); /* call into daemon */ - body = g_variant_new ("(shh)", - remote_id, - g_unix_input_stream_get_fd (metadata), - g_unix_input_stream_get_fd (signature)); - g_dbus_message_set_body (request, body); - helper = fwupd_client_helper_new (); - g_dbus_connection_send_message_with_reply (priv->conn, - request, - G_DBUS_SEND_MESSAGE_FLAGS_NONE, - -1, - NULL, - cancellable, - fwupd_client_send_message_cb, - helper); - g_main_loop_run (helper->loop); - if (!helper->ret) { - g_propagate_error (error, helper->error); - helper->error = NULL; - return FALSE; - } - return TRUE; + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "GetApprovedFirmware", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, cancellable, + fwupd_client_get_approved_firmware_cb, + g_steal_pointer (&task)); } -#endif - /** - * fwupd_client_update_metadata: - * @client: A #FwupdClient - * @remote_id: the remote ID, e.g. `lvfs-testing` - * @metadata_fn: the XML metadata filename - * @signature_fn: the GPG signature file - * @cancellable: the #GCancellable, or %NULL + * fwupd_client_get_approved_firmware_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult * @error: the #GError, or %NULL * - * Updates the metadata. This allows a session process to download the metadata - * and metadata signing file to be passed into the daemon to be checked and - * parsed. - * - * The @remote_id allows the firmware to be tagged so that the remote can be - * matched when the firmware is downloaded. + * Gets the result of fwupd_client_get_approved_firmware_async(). * - * Returns: %TRUE for success + * Returns: (element-type utf8) (transfer container): checksums, or %NULL for error * - * Since: 1.0.0 + * Since: 1.5.0 **/ -gboolean -fwupd_client_update_metadata (FwupdClient *client, - const gchar *remote_id, - const gchar *metadata_fn, - const gchar *signature_fn, - GCancellable *cancellable, - GError **error) +GPtrArray * +fwupd_client_get_approved_firmware_finish (FwupdClient *self, GAsyncResult *res, GError **error) { -#ifdef HAVE_GIO_UNIX - GUnixInputStream *istr; - GUnixInputStream *istr_sig; + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); - g_return_val_if_fail (remote_id != NULL, FALSE); - g_return_val_if_fail (metadata_fn != NULL, FALSE); - g_return_val_if_fail (signature_fn != NULL, FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); +static void +fwupd_client_set_approved_firmware_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; - /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) - return FALSE; + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } - /* open files */ - istr = fwupd_unix_input_stream_from_fn (metadata_fn, error); - if (istr == NULL) - return FALSE; - istr_sig = fwupd_unix_input_stream_from_fn (signature_fn, error); - if (istr_sig == NULL) - return FALSE; - return fwupd_client_update_metadata_fds (client, remote_id, - istr, istr_sig, - cancellable, error); -#else - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Not supported as is unavailable"); - return FALSE; -#endif + /* success */ + g_task_return_boolean (task, TRUE); } /** - * fwupd_client_update_metadata_bytes: - * @client: A #FwupdClient - * @remote_id: remote ID, e.g. `lvfs-testing` - * @metadata: XML metadata data - * @signature: signature data - * @cancellable: #GCancellable, or %NULL - * @error: the #GError, or %NULL - * - * Updates the metadata. This allows a session process to download the metadata - * and metadata signing file to be passed into the daemon to be checked and - * parsed. - * - * The @remote_id allows the firmware to be tagged so that the remote can be - * matched when the firmware is downloaded. + * fwupd_client_set_approved_firmware_async: + * @self: A #FwupdClient + * @checksums: (element-type utf8): firmware checksums + * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * - * Returns: %TRUE for success + * Sets the list of approved firmware. * - * Since: 1.4.5 + * Since: 1.5.0 **/ -gboolean -fwupd_client_update_metadata_bytes (FwupdClient *client, - const gchar *remote_id, - GBytes *metadata, - GBytes *signature, - GCancellable *cancellable, - GError **error) -{ -#ifdef HAVE_GIO_UNIX - GUnixInputStream *istr; - GUnixInputStream *istr_sig; - - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); - g_return_val_if_fail (remote_id != NULL, FALSE); - g_return_val_if_fail (metadata != NULL, FALSE); - g_return_val_if_fail (signature != NULL, FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); +void +fwupd_client_set_approved_firmware_async (FwupdClient *self, + GPtrArray *checksums, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + g_auto(GStrv) strv = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); - /* convert bytes to a readable fd */ - istr = fwupd_unix_input_stream_from_bytes (metadata, error); - if (istr == NULL) - return FALSE; - istr_sig = fwupd_unix_input_stream_from_bytes (signature, error); - if (istr_sig == NULL) - return FALSE; - return fwupd_client_update_metadata_fds (client, remote_id, - istr, istr_sig, - cancellable, error); -#else - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Not supported as is unavailable"); - return FALSE; -#endif + /* call into daemon */ + task = g_task_new (self, cancellable, callback, callback_data); + strv = g_new0 (gchar *, checksums->len + 1); + for (guint i = 0; i < checksums->len; i++) { + const gchar *tmp = g_ptr_array_index (checksums, i); + strv[i] = g_strdup (tmp); + } + g_dbus_proxy_call (priv->proxy, "SetApprovedFirmware", + g_variant_new ("(^as)", strv), + G_DBUS_CALL_FLAGS_NONE, -1, + cancellable, + fwupd_client_set_approved_firmware_cb, + g_steal_pointer (&task)); } /** - * fwupd_client_refresh_remote: - * @client: A #FwupdClient - * @remote: A #FwupdRemote - * @cancellable: A #GCancellable, or %NULL - * @error: A #GError, or %NULL + * fwupd_client_set_approved_firmware_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL * - * Refreshes a remote by downloading new metadata. + * Gets the result of fwupd_client_set_approved_firmware_async(). * * Returns: %TRUE for success * - * Since: 1.4.5 + * Since: 1.5.0 **/ gboolean -fwupd_client_refresh_remote (FwupdClient *client, - FwupdRemote *remote, - GCancellable *cancellable, - GError **error) +fwupd_client_set_approved_firmware_finish (FwupdClient *self, GAsyncResult *res, GError **error) { - g_autoptr(GBytes) metadata = NULL; - g_autoptr(GBytes) signature = NULL; - - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); - g_return_val_if_fail (FWUPD_IS_REMOTE (remote), FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); +} - /* download the signature */ - signature = fwupd_client_download_bytes (client, - fwupd_remote_get_metadata_uri_sig (remote), - FWUPD_CLIENT_DOWNLOAD_FLAG_NONE, - cancellable, error); - if (signature == NULL) - return FALSE; +static void +fwupd_client_get_blocked_firmware_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_auto(GStrv) strv = NULL; + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) array = g_ptr_array_new_with_free_func (g_free); + g_autoptr(GVariant) val = NULL; - /* find the download URI of the metadata from the JCat file */ - if (!fwupd_remote_load_signature_bytes (remote, signature, error)) - return FALSE; + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } - /* download the metadata */ - metadata = fwupd_client_download_bytes (client, - fwupd_remote_get_metadata_uri (remote), - FWUPD_CLIENT_DOWNLOAD_FLAG_NONE, - cancellable, error); - if (metadata == NULL) - return FALSE; + g_variant_get (val, "(^as)", &strv); + for (guint i = 0; strv[i] != NULL; i++) + g_ptr_array_add (array, g_strdup (strv[i])); - /* send all this to fwupd */ - return fwupd_client_update_metadata_bytes (client, - fwupd_remote_get_id (remote), - metadata, signature, - cancellable, error); + /* success */ + g_task_return_pointer (task, + g_steal_pointer (&array), + (GDestroyNotify) g_ptr_array_unref); } /** - * fwupd_client_get_remotes: - * @client: A #FwupdClient + * fwupd_client_get_blocked_firmware_async: + * @self: A #FwupdClient * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * - * Gets the list of remotes that have been configured for the system. + * Gets the list of blocked firmware. * - * Returns: (element-type FwupdRemote) (transfer container): list of remotes, or %NULL + * You must have called fwupd_client_connect_async() on @self before using + * this method. * - * Since: 0.9.3 + * Since: 1.5.0 **/ -GPtrArray * -fwupd_client_get_remotes (FwupdClient *client, GCancellable *cancellable, GError **error) -{ - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_autoptr(GVariant) val = NULL; - - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) - return NULL; +void +fwupd_client_get_blocked_firmware_async (FwupdClient *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); /* call into daemon */ - val = g_dbus_proxy_call_sync (priv->proxy, - "GetRemotes", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - error); - if (val == NULL) { - if (error != NULL) - fwupd_client_fixup_dbus_error (*error); - return NULL; - } - return fwupd_remote_array_from_variant (val); + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "GetBlockedFirmware", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, cancellable, + fwupd_client_get_blocked_firmware_cb, + g_steal_pointer (&task)); } /** - * fwupd_client_get_approved_firmware: - * @client: A #FwupdClient - * @cancellable: the #GCancellable, or %NULL + * fwupd_client_get_blocked_firmware_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult * @error: the #GError, or %NULL * - * Gets the list of approved firmware. + * Gets the result of fwupd_client_get_blocked_firmware_async(). * - * Returns: (transfer full): list of remotes, or %NULL + * Returns: (element-type utf8) (transfer container): checksums, or %NULL for error * - * Since: 1.2.6 + * Since: 1.5.0 **/ -gchar ** -fwupd_client_get_approved_firmware (FwupdClient *client, - GCancellable *cancellable, - GError **error) +GPtrArray * +fwupd_client_get_blocked_firmware_finish (FwupdClient *self, GAsyncResult *res, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_autoptr(GVariant) val = NULL; - gchar **retval = NULL; - - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} - /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) - return NULL; +static void +fwupd_client_set_blocked_firmware_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; - /* call into daemon */ - val = g_dbus_proxy_call_sync (priv->proxy, - "GetApprovedFirmware", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - error); + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); if (val == NULL) { - if (error != NULL) - fwupd_client_fixup_dbus_error (*error); - return NULL; + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; } - g_variant_get (val, "(^as)", &retval); - return retval; + + /* success */ + g_task_return_boolean (task, TRUE); } /** - * fwupd_client_set_approved_firmware: - * @client: A #FwupdClient - * @checksums: Array of checksums + * fwupd_client_set_blocked_firmware_async: + * @self: A #FwupdClient + * @checksums: (element-type utf8): firmware checksums * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * + * Sets the list of blocked firmware. + * + * Since: 1.5.0 + **/ +void +fwupd_client_set_blocked_firmware_async (FwupdClient *self, + GPtrArray *checksums, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + g_auto(GStrv) strv = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* call into daemon */ + task = g_task_new (self, cancellable, callback, callback_data); + strv = g_new0 (gchar *, checksums->len + 1); + for (guint i = 0; i < checksums->len; i++) { + const gchar *tmp = g_ptr_array_index (checksums, i); + strv[i] = g_strdup (tmp); + } + g_dbus_proxy_call (priv->proxy, "SetBlockedFirmware", + g_variant_new ("(^as)", strv), + G_DBUS_CALL_FLAGS_NONE, -1, + cancellable, + fwupd_client_set_blocked_firmware_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_set_blocked_firmware_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult * @error: the #GError, or %NULL * - * Sets the list of approved firmware. + * Gets the result of fwupd_client_set_blocked_firmware_async(). * * Returns: %TRUE for success * - * Since: 1.2.6 + * Since: 1.5.0 **/ gboolean -fwupd_client_set_approved_firmware (FwupdClient *client, - gchar **checksums, - GCancellable *cancellable, - GError **error) +fwupd_client_set_blocked_firmware_finish (FwupdClient *self, GAsyncResult *res, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_autoptr(GVariant) val = NULL; - - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); +} - /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) - return FALSE; +static void +fwupd_client_set_feature_flags_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; - /* call into daemon */ - val = g_dbus_proxy_call_sync (priv->proxy, - "SetApprovedFirmware", - g_variant_new ("(^as)", checksums), - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - error); + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); if (val == NULL) { - if (error != NULL) - fwupd_client_fixup_dbus_error (*error); - return FALSE; + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; } - return TRUE; + + /* success */ + g_task_return_boolean (task, TRUE); } /** - * fwupd_client_set_feature_flags: - * @client: A #FwupdClient + * fwupd_client_set_feature_flags_async: + * @self: A #FwupdClient * @feature_flags: #FwupdFeatureFlags, e.g. %FWUPD_FEATURE_FLAG_UPDATE_TEXT * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * * Sets the features the client supports. This allows firmware to depend on * specific front-end features, for instance showing the user an image on * how to detach the hardware. * - * Clients can call this none or multiple times. + * Since: 1.5.0 + **/ +void +fwupd_client_set_feature_flags_async (FwupdClient *self, + FwupdFeatureFlags feature_flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* call into daemon */ + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "SetFeatureFlags", + g_variant_new ("(t)", (guint64) feature_flags), + G_DBUS_CALL_FLAGS_NONE, -1, + cancellable, + fwupd_client_set_feature_flags_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_set_feature_flags_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_set_feature_flags_async(). * * Returns: %TRUE for success * - * Since: 1.4.5 + * Since: 1.5.0 **/ gboolean -fwupd_client_set_feature_flags (FwupdClient *client, - FwupdFeatureFlags feature_flags, - GCancellable *cancellable, - GError **error) +fwupd_client_set_feature_flags_finish (FwupdClient *self, GAsyncResult *res, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_autoptr(GVariant) val = NULL; - - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); +} - /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) - return FALSE; +static void +fwupd_client_self_sign_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + gchar *str = NULL; + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; - /* call into daemon */ - val = g_dbus_proxy_call_sync (priv->proxy, - "SetFeatureFlags", - g_variant_new ("(t)", (guint64) feature_flags), - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - error); + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); if (val == NULL) { - if (error != NULL) - fwupd_client_fixup_dbus_error (*error); - return FALSE; + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; } - return TRUE; + + /* success */ + g_variant_get (val, "(s)", &str); + g_task_return_pointer (task, + g_steal_pointer (&str), + (GDestroyNotify) g_free); } /** - * fwupd_client_self_sign: - * @client: A #FwupdClient + * fwupd_client_self_sign_async: + * @self: A #FwupdClient * @value: A string to sign, typically a JSON blob * @flags: #FwupdSelfSignFlags, e.g. %FWUPD_SELF_SIGN_FLAG_ADD_TIMESTAMP * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * * Signs the data using the client self-signed certificate. * - * Returns: %TRUE for success + * You must have called fwupd_client_connect_async() on @self before using + * this method. * - * Since: 1.2.6 + * Since: 1.5.0 **/ -gchar * -fwupd_client_self_sign (FwupdClient *client, - const gchar *value, - FwupdSelfSignFlags flags, - GCancellable *cancellable, - GError **error) +void +fwupd_client_self_sign_async (FwupdClient *self, + const gchar *value, + FwupdSelfSignFlags flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); GVariantBuilder builder; - g_autoptr(GVariant) val = NULL; - gchar *retval = NULL; + g_autoptr(GTask) task = NULL; - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) - return NULL; + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (value != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); /* set options */ g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); @@ -2078,131 +3929,204 @@ } /* call into daemon */ - val = g_dbus_proxy_call_sync (priv->proxy, - "SelfSign", - g_variant_new ("(sa{sv})", value, &builder), - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - error); + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, + "SelfSign", + g_variant_new ("(sa{sv})", value, &builder), + G_DBUS_CALL_FLAGS_NONE, + -1, cancellable, + fwupd_client_self_sign_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_self_sign_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_self_sign_async(). + * + * Returns: a signature, or %NULL for failure + * + * Since: 1.5.0 + **/ +gchar * +fwupd_client_self_sign_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} + +static void +fwupd_client_modify_remote_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); if (val == NULL) { - if (error != NULL) - fwupd_client_fixup_dbus_error (*error); - return NULL; + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; } - g_variant_get (val, "(s)", &retval); - return retval; + + /* success */ + g_task_return_boolean (task, TRUE); } /** - * fwupd_client_modify_remote: - * @client: A #FwupdClient + * fwupd_client_modify_remote_async: + * @self: A #FwupdClient * @remote_id: the remote ID, e.g. `lvfs-testing` * @key: the key, e.g. `Enabled` * @value: the key, e.g. `true` * @cancellable: the #GCancellable, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * + * Modifies a system remote in a specific way. + * + * Since: 1.5.0 + **/ +void +fwupd_client_modify_remote_async (FwupdClient *self, + const gchar *remote_id, + const gchar *key, + const gchar *value, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (remote_id != NULL); + g_return_if_fail (key != NULL); + g_return_if_fail (value != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* call into daemon */ + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "ModifyRemote", + g_variant_new ("(sss)", remote_id, key, value), + G_DBUS_CALL_FLAGS_NONE, -1, + cancellable, + fwupd_client_modify_remote_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_modify_remote_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult * @error: the #GError, or %NULL * - * Modifies a system remote in a specific way. - * - * NOTE: User authentication may be required to complete this action. + * Gets the result of fwupd_client_modify_remote_async(). * * Returns: %TRUE for success * - * Since: 0.9.8 + * Since: 1.5.0 **/ gboolean -fwupd_client_modify_remote (FwupdClient *client, - const gchar *remote_id, - const gchar *key, - const gchar *value, - GCancellable *cancellable, - GError **error) +fwupd_client_modify_remote_finish (FwupdClient *self, GAsyncResult *res, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_autoptr(GVariant) val = NULL; - - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); - g_return_val_if_fail (remote_id != NULL, FALSE); - g_return_val_if_fail (key != NULL, FALSE); - g_return_val_if_fail (value != NULL, FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean (G_TASK(res), error); +} - /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) - return FALSE; +static void +fwupd_client_modify_device_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; - /* call into daemon */ - val = g_dbus_proxy_call_sync (priv->proxy, - "ModifyRemote", - g_variant_new ("(sss)", remote_id, key, value), - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - error); + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); if (val == NULL) { - if (error != NULL) - fwupd_client_fixup_dbus_error (*error); - return FALSE; + fwupd_client_fixup_dbus_error (error); + g_task_return_error (task, g_steal_pointer (&error)); + return; } - return TRUE; + + /* success */ + g_task_return_boolean (task, TRUE); } /** - * fwupd_client_modify_device: - * @client: A #FwupdClient + * fwupd_client_modify_device_async: + * @self: A #FwupdClient * @device_id: the device ID * @key: the key, e.g. `Flags` * @value: the key, e.g. `reported` * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * * Modifies a device in a specific way. Not all properties on the #FwupdDevice * are settable by the client, and some may have other restrictions on @value. * - * NOTE: User authentication may be required to complete this action. + * Since: 1.5.0 + **/ +void +fwupd_client_modify_device_async (FwupdClient *self, + const gchar *device_id, + const gchar *key, + const gchar *value, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (device_id != NULL); + g_return_if_fail (key != NULL); + g_return_if_fail (value != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* call into daemon */ + task = g_task_new (self, cancellable, callback, callback_data); + g_dbus_proxy_call (priv->proxy, "ModifyDevice", + g_variant_new ("(sss)", device_id, key, value), + G_DBUS_CALL_FLAGS_NONE, -1, + cancellable, + fwupd_client_modify_device_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_modify_device_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_modify_device_async(). * * Returns: %TRUE for success * - * Since: 1.0.4 + * Since: 1.5.0 **/ gboolean -fwupd_client_modify_device (FwupdClient *client, - const gchar *remote_id, - const gchar *key, - const gchar *value, - GCancellable *cancellable, - GError **error) +fwupd_client_modify_device_finish (FwupdClient *self, GAsyncResult *res, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_autoptr(GVariant) val = NULL; - - g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); - g_return_val_if_fail (remote_id != NULL, FALSE); - g_return_val_if_fail (key != NULL, FALSE); - g_return_val_if_fail (value != NULL, FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (g_task_is_valid (res, self), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* connect */ - if (!fwupd_client_connect (client, cancellable, error)) - return FALSE; - - /* call into daemon */ - val = g_dbus_proxy_call_sync (priv->proxy, - "ModifyDevice", - g_variant_new ("(sss)", remote_id, key, value), - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - error); - if (val == NULL) { - if (error != NULL) - fwupd_client_fixup_dbus_error (*error); - return FALSE; - } - return TRUE; + return g_task_propagate_boolean (G_TASK(res), error); } static FwupdRemote * @@ -2216,54 +4140,98 @@ return NULL; } +static void +fwupd_client_get_remote_by_id_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + FwupdRemote *remote_tmp; + g_autoptr(GTask) task = G_TASK (user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) remotes = NULL; + const gchar *remote_id = g_task_get_task_data (task); + + remotes = fwupd_client_get_remotes_finish (FWUPD_CLIENT (source), res, &error); + if (remotes == NULL) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + remote_tmp = fwupd_client_get_remote_by_id_noref (remotes, remote_id); + if (remote_tmp == NULL) { + g_task_return_new_error (task, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "no remote '%s' found in search paths", + remote_id); + return; + } + + /* success */ + g_task_return_pointer (task, + g_object_ref (remote_tmp), + (GDestroyNotify) g_object_unref); +} + /** - * fwupd_client_get_remote_by_id: - * @client: A #FwupdClient + * fwupd_client_get_remote_by_id_async: + * @self: A #FwupdClient * @remote_id: the remote ID, e.g. `lvfs-testing` * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * * Gets a specific remote that has been configured for the system. * + * Since: 1.5.0 + **/ +void +fwupd_client_get_remote_by_id_async (FwupdClient *self, + const gchar *remote_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (remote_id != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* call into daemon */ + task = g_task_new (self, cancellable, callback, callback_data); + g_task_set_task_data (task, g_strdup (remote_id), g_free); + fwupd_client_get_remotes_async (self, cancellable, + fwupd_client_get_remote_by_id_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_client_get_remote_by_id_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_get_remote_by_id_async(). + * * Returns: (transfer full): a #FwupdRemote, or %NULL if not found * - * Since: 0.9.3 + * Since: 1.5.0 **/ FwupdRemote * -fwupd_client_get_remote_by_id (FwupdClient *client, - const gchar *remote_id, - GCancellable *cancellable, - GError **error) +fwupd_client_get_remote_by_id_finish (FwupdClient *self, GAsyncResult *res, GError **error) { - FwupdRemote *remote; - g_autoptr(GPtrArray) remotes = NULL; - - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); - g_return_val_if_fail (remote_id != NULL, NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - /* find remote in list */ - remotes = fwupd_client_get_remotes (client, cancellable, error); - if (remotes == NULL) - return NULL; - remote = fwupd_client_get_remote_by_id_noref (remotes, remote_id); - if (remote == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "No remote '%s' found in search paths", - remote_id); - return NULL; - } - - /* success */ - return g_object_ref (remote); + return g_task_propagate_pointer (G_TASK(res), error); } /** * fwupd_client_set_user_agent: - * @client: A #FwupdClient + * @self: A #FwupdClient * @user_agent: the user agent ID, e.g. `gnome-software/3.34.1` * * Manually sets the user agent that is used for downloading. The user agent @@ -2272,18 +4240,44 @@ * Since: 1.4.5 **/ void -fwupd_client_set_user_agent (FwupdClient *client, const gchar *user_agent) +fwupd_client_set_user_agent (FwupdClient *self, const gchar *user_agent) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - g_return_if_fail (FWUPD_IS_CLIENT (client)); + FwupdClientPrivate *priv = GET_PRIVATE (self); + + g_return_if_fail (FWUPD_IS_CLIENT (self)); g_return_if_fail (user_agent != NULL); + + /* not changed */ + if (g_strcmp0 (priv->user_agent, user_agent) == 0) + return; + g_free (priv->user_agent); priv->user_agent = g_strdup (user_agent); } /** + * fwupd_client_get_user_agent: + * @self: A #FwupdClient + * + * Gets the string that represents the user agent that is used for + * uploading and downloading. The user agent will contain the runtime + * version of fwupd somewhere in the provided string. + * + * Returns: a string, or %NULL for unknown. + * + * Since: 1.5.2 + **/ +const gchar * +fwupd_client_get_user_agent (FwupdClient *self) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + return priv->user_agent; +} + +/** * fwupd_client_set_user_agent_for_package: - * @client: A #FwupdClient + * @self: A #FwupdClient * @package_name: client program name, e.g. "gnome-software" * @package_version: client program version, e.g. "3.28.1" * @@ -2300,15 +4294,15 @@ * Since: 1.4.5 **/ void -fwupd_client_set_user_agent_for_package (FwupdClient *client, +fwupd_client_set_user_agent_for_package (FwupdClient *self, const gchar *package_name, const gchar *package_version) { - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClientPrivate *priv = GET_PRIVATE (self); GString *str = g_string_new (NULL); g_autofree gchar *system = NULL; - g_return_if_fail (FWUPD_IS_CLIENT (client)); + g_return_if_fail (FWUPD_IS_CLIENT (self)); g_return_if_fail (package_name != NULL); g_return_if_fail (package_version != NULL); @@ -2329,203 +4323,471 @@ priv->user_agent = g_string_free (str, FALSE); } +#ifdef HAVE_LIBCURL +static size_t +fwupd_client_download_write_callback_cb (char *ptr, size_t size, size_t nmemb, void *userdata) +{ + GByteArray *buf = (GByteArray *) userdata; + gsize realsize = size * nmemb; + g_byte_array_append (buf, (const guint8 *) ptr, realsize); + return realsize; +} + +static GBytes * +fwupd_client_stream_read_bytes (GInputStream *stream, GError **error) +{ + guint8 tmp[0x8000] = { 0x0 }; + g_autoptr(GByteArray) buf = g_byte_array_new (); + + /* read from stream in 32kB chunks */ + while (TRUE) { + gssize sz; + sz = g_input_stream_read (stream, tmp, sizeof(tmp), NULL, error); + if (sz == 0) + break; + if (sz < 0) + return NULL; + g_byte_array_append (buf, tmp, sz); + } + return g_byte_array_free_to_bytes (g_steal_pointer (&buf)); +} + +static GBytes * +fwupd_client_download_ipfs (FwupdClient *self, const gchar *url, GError **error) +{ + GInputStream *stream = NULL; + g_autofree gchar *path = NULL; + g_autoptr(GSubprocess) subprocess = NULL; + + /* we get no detailed progess details */ + fwupd_client_set_status (self, FWUPD_STATUS_DOWNLOADING); + fwupd_client_set_percentage (self, 0); + + /* convert from URI to path */ + if (g_str_has_prefix (url, "ipfs://")) { + path = g_strdup_printf ("/ipfs/%s", url + 7); + } else if (g_str_has_prefix (url, "ipns://")) { + path = g_strdup_printf ("/ipns/%s", url + 7); + } else { + path = g_strdup (url); + } + + /* run sync */ + subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE, + error, "ipfs", "cat", path, NULL); + if (subprocess == NULL) + return NULL; + if (!g_subprocess_wait_check (subprocess, NULL, error)) + return NULL; + + /* get raw stdout */ + stream = g_subprocess_get_stdout_pipe (subprocess); + return fwupd_client_stream_read_bytes (stream, error); +} + +static GBytes * +fwupd_client_download_http (FwupdClient *self, + CURL *curl, + const gchar *url, + GError **error) +{ + CURLcode res; + gchar errbuf[CURL_ERROR_SIZE] = { '\0' }; + g_autoptr(GByteArray) buf = g_byte_array_new (); + + fwupd_client_set_status (self, FWUPD_STATUS_DOWNLOADING); + curl_easy_setopt (curl, CURLOPT_URL, url); + curl_easy_setopt (curl, CURLOPT_ERRORBUFFER, errbuf); + curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, fwupd_client_download_write_callback_cb); + curl_easy_setopt (curl, CURLOPT_WRITEDATA, buf); + res = curl_easy_perform (curl); + fwupd_client_set_status (self, FWUPD_STATUS_IDLE); + if (res != CURLE_OK) { + glong status_code = 0; + curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &status_code); + g_debug ("status-code was %ld", status_code); + if (status_code == 429) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Failed to download due to server limit"); + return NULL; + } + if (errbuf[0] != '\0') { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "failed to download file: %s", + errbuf); + return NULL; + } + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "failed to download file: %s", + curl_easy_strerror (res)); + return NULL; + } + return g_byte_array_free_to_bytes (g_steal_pointer (&buf)); +} static void -fwupd_client_download_chunk_cb (SoupMessage *msg, SoupBuffer *chunk, gpointer user_data) +fwupd_client_download_bytes_thread_cb (GTask *task, + gpointer source_object, + gpointer task_data, + GCancellable *cancellable) +{ + FwupdClient *self = FWUPD_CLIENT (source_object); + FwupdCurlHelper *helper = g_task_get_task_data (task); + g_autoptr(GBytes) blob = NULL; + + for (guint i = 0; i < helper->urls->len; i++) { + const gchar *url = g_ptr_array_index (helper->urls, i); + g_autoptr(GError) error = NULL; + g_debug ("downloading %s", url); + if (fwupd_client_is_url_http (url)) { + blob = fwupd_client_download_http (self, helper->curl, url, &error); + if (blob != NULL) + break; + } else if (fwupd_client_is_url_ipfs (url)) { + blob = fwupd_client_download_ipfs (self, url, &error); + if (blob != NULL) + break; + } else { + g_set_error (&error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "not sure how to handle: %s", url); + } + if (i == helper->urls->len - 1) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + fwupd_client_set_percentage (self, 0); + fwupd_client_set_status (self, FWUPD_STATUS_IDLE); + g_debug ("failed to download %s: %s, trying next URI…", + url, error->message); + } + g_task_return_pointer (task, + g_steal_pointer (&blob), + (GDestroyNotify) g_bytes_unref); +} +#endif + +/* private */ +void +fwupd_client_download_bytes2_async (FwupdClient *self, + GPtrArray *urls, + FwupdClientDownloadFlags flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) { - guint percentage; - goffset header_size; - goffset body_length; - FwupdClient *client = FWUPD_CLIENT (user_data); + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; +#ifdef HAVE_LIBCURL + g_autoptr(GError) error = NULL; + g_autoptr(FwupdCurlHelper) helper = NULL; +#endif - /* if it's returning "Found" or an error, ignore the percentage */ - if (msg->status_code != SOUP_STATUS_OK) { - g_debug ("ignoring status code %u (%s)", - msg->status_code, msg->reason_phrase); + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (urls != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* ensure networking set up */ + task = g_task_new (self, cancellable, callback, callback_data); +#ifdef HAVE_LIBCURL + helper = fwupd_client_curl_new (self, &error); + if (helper == NULL) { + g_task_return_error (task, g_steal_pointer (&error)); return; } - - /* get data */ - body_length = msg->response_body->length; - header_size = soup_message_headers_get_content_length (msg->response_headers); - if (header_size < body_length) + helper->urls = fwupd_client_filter_locations (urls, flags, &error); + if (helper->urls == NULL) { + g_task_return_error (task, g_steal_pointer (&error)); return; + } + g_task_set_task_data (task, g_steal_pointer (&helper), (GDestroyNotify) fwupd_client_curl_helper_free); - /* calculate percentage */ - percentage = (guint) ((100 * body_length) / header_size); - g_debug ("progress: %u%%", percentage); - fwupd_client_set_status (client, FWUPD_STATUS_DOWNLOADING); - fwupd_client_set_percentage (client, percentage); + /* download data */ + g_task_run_in_thread (task, fwupd_client_download_bytes_thread_cb); +#else + g_task_return_new_error (task, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "no libcurl support"); +#endif } /** - * fwupd_client_download_bytes: - * @client: A #FwupdClient + * fwupd_client_download_bytes_async: + * @self: A #FwupdClient * @url: the remote URL * @flags: #FwupdClientDownloadFlags, e.g. %FWUPD_CLIENT_DOWNLOAD_FLAG_NONE * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * * Downloads data from a remote server. The fwupd_client_set_user_agent() function * should be called before this method is used. * + * You must have called fwupd_client_connect_async() on @self before using + * this method. + * + * NOTE: This method is thread-safe, but progress signals will be + * emitted in the global default main context, if not explicitly set with + * fwupd_client_set_main_context(). + * + * Since: 1.5.0 + **/ +void +fwupd_client_download_bytes_async (FwupdClient *self, + const gchar *url, + FwupdClientDownloadFlags flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GPtrArray) urls = g_ptr_array_new_with_free_func (g_free); + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (url != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); + + /* just proxy */ + g_ptr_array_add (urls, g_strdup (url)); + fwupd_client_download_bytes2_async (self, urls, flags, cancellable, + callback, callback_data); +} + +/** + * fwupd_client_download_bytes_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_download_bytes_async(). + * * Returns: (transfer full): downloaded data, or %NULL for error * - * Since: 1.4.5 + * Since: 1.5.0 **/ GBytes * -fwupd_client_download_bytes (FwupdClient *client, - const gchar *url, - FwupdClientDownloadFlags flags, - GCancellable *cancellable, - GError **error) +fwupd_client_download_bytes_finish (FwupdClient *self, GAsyncResult *res, GError **error) { - FwupdClientPrivate *priv = GET_PRIVATE (client); - guint status_code; - g_autoptr(SoupMessage) msg = NULL; - g_autoptr(SoupURI) uri = NULL; - - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); - g_return_val_if_fail (url != NULL, NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} - /* ensure networking set up */ - if (!fwupd_client_ensure_networking (client, error)) - return NULL; - - /* download data */ - g_debug ("downloading %s", url); - uri = soup_uri_new (url); - msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri); - if (msg == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Failed to parse URI %s", url); - return NULL; - } - g_signal_connect (msg, "got-chunk", - G_CALLBACK (fwupd_client_download_chunk_cb), - client); - status_code = soup_session_send_message (priv->soup_session, msg); - fwupd_client_set_status (client, FWUPD_STATUS_IDLE); - if (status_code == 429) { - g_autofree gchar *str = g_strndup (msg->response_body->data, - msg->response_body->length); - if (g_strcmp0 (str, "Too Many Requests") == 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Failed to download due to server limit"); - return NULL; +#ifdef HAVE_LIBCURL +static void +fwupd_client_upload_bytes_thread_cb (GTask *task, + gpointer source_object, + gpointer task_data, + GCancellable *cancellable) +{ + FwupdClient *self = FWUPD_CLIENT (source_object); + FwupdCurlHelper *helper = g_task_get_task_data (task); + CURLcode res; + gchar errbuf[CURL_ERROR_SIZE] = { '\0' }; + g_autoptr(GByteArray) buf = g_byte_array_new (); + + curl_easy_setopt (helper->curl, CURLOPT_ERRORBUFFER, errbuf); + curl_easy_setopt (helper->curl, CURLOPT_WRITEFUNCTION, fwupd_client_download_write_callback_cb); + curl_easy_setopt (helper->curl, CURLOPT_WRITEDATA, buf); + res = curl_easy_perform (helper->curl); + fwupd_client_set_status (self, FWUPD_STATUS_IDLE); + if (res != CURLE_OK) { + glong status_code = 0; + curl_easy_getinfo (helper->curl, CURLINFO_RESPONSE_CODE, &status_code); + g_debug ("status-code was %ld", status_code); + if (errbuf[0] != '\0') { + g_task_return_new_error (task, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "failed to upload file: %s", + errbuf); + return; } - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Failed to download due to server limit: %s", str); - return NULL; - } - if (status_code != SOUP_STATUS_OK) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Failed to download %s: %s", - url, soup_status_get_phrase (status_code)); - return NULL; - } + g_task_return_new_error (task, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "failed to upload file: %s", + curl_easy_strerror (res)); - /* success */ - return g_bytes_new (msg->response_body->data, msg->response_body->length); + return; + } + g_task_return_pointer (task, + g_byte_array_free_to_bytes (g_steal_pointer (&buf)), + (GDestroyNotify) g_bytes_unref); } +#endif /** - * fwupd_client_upload_bytes: - * @client: A #FwupdClient + * fwupd_client_upload_bytes_async: + * @self: A #FwupdClient * @url: the remote URL * @payload: payload string * @signature: (nullable): signature string * @flags: #FwupdClientDownloadFlags, e.g. %FWUPD_CLIENT_DOWNLOAD_FLAG_NONE * @cancellable: the #GCancellable, or %NULL - * @error: the #GError, or %NULL + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback * * Uploads data to a remote server. The fwupd_client_set_user_agent() function * should be called before this method is used. * - * Returns: (transfer full): downloaded data, or %NULL for error + * You must have called fwupd_client_connect_async() on @self before using + * this method. * - * Since: 1.4.5 + * NOTE: This method is thread-safe, but progress signals will be + * emitted in the global default main context, if not explicitly set with + * fwupd_client_set_main_context(). + * + * Since: 1.5.0 **/ -GBytes * -fwupd_client_upload_bytes (FwupdClient *client, - const gchar *url, - const gchar *payload, - const gchar *signature, - FwupdClientUploadFlags flags, - GCancellable *cancellable, - GError **error) -{ - FwupdClientPrivate *priv = GET_PRIVATE (client); - guint status_code; - g_autoptr(SoupMessage) msg = NULL; - g_autoptr(SoupURI) uri = NULL; - - g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); - g_return_val_if_fail (url != NULL, NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); +void +fwupd_client_upload_bytes_async (FwupdClient *self, + const gchar *url, + const gchar *payload, + const gchar *signature, + FwupdClientUploadFlags flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_autoptr(GTask) task = NULL; +#ifdef HAVE_LIBCURL + g_autoptr(FwupdCurlHelper) helper = NULL; + g_autoptr(GError) error = NULL; +#endif + + g_return_if_fail (FWUPD_IS_CLIENT (self)); + g_return_if_fail (url != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (priv->proxy != NULL); /* ensure networking set up */ - if (!fwupd_client_ensure_networking (client, error)) - return NULL; + task = g_task_new (self, cancellable, callback, callback_data); +#ifdef HAVE_LIBCURL + helper = fwupd_client_curl_new (self, &error); + if (helper == NULL) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } /* build message */ - if ((flags | FWUPD_CLIENT_UPLOAD_FLAG_ALWAYS_MULTIPART) > 0 || + if ((flags & FWUPD_CLIENT_UPLOAD_FLAG_ALWAYS_MULTIPART) > 0 || signature != NULL) { - g_autoptr(SoupMultipart) mp = NULL; - mp = soup_multipart_new (SOUP_FORM_MIME_TYPE_MULTIPART); - soup_multipart_append_form_string (mp, "payload", payload); - if (signature != NULL) - soup_multipart_append_form_string (mp, "signature", signature); - msg = soup_form_request_new_from_multipart (url, mp); + curl_mimepart *part; + helper->mime = curl_mime_init (helper->curl); + curl_easy_setopt (helper->curl, CURLOPT_MIMEPOST, helper->mime); + part = curl_mime_addpart (helper->mime); + curl_mime_data (part, payload, CURL_ZERO_TERMINATED); + curl_mime_name (part, "payload"); + if (signature != NULL) { + part = curl_mime_addpart (helper->mime); + curl_mime_data (part, signature, CURL_ZERO_TERMINATED); + curl_mime_name (part, "signature"); + } } else { - msg = soup_message_new (SOUP_METHOD_POST, url); - soup_message_set_request (msg, "application/json; charset=utf-8", - SOUP_MEMORY_COPY, payload, strlen (payload)); + helper->headers = curl_slist_append (helper->headers, "Content-Type: text/plain"); + curl_easy_setopt (helper->curl, CURLOPT_HTTPHEADER, helper->headers); + curl_easy_setopt (helper->curl, CURLOPT_POST, 1L); + curl_easy_setopt (helper->curl, CURLOPT_POSTFIELDSIZE, strlen (payload)); + curl_easy_setopt (helper->curl, CURLOPT_COPYPOSTFIELDS, payload); } - /* POST request */ - if (msg == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Failed to parse URI %s", url); - return NULL; - } + fwupd_client_set_status (self, FWUPD_STATUS_IDLE); g_debug ("uploading to %s", url); - status_code = soup_session_send_message (priv->soup_session, msg); - g_debug ("server returned: %s", msg->response_body->data); + curl_easy_setopt (helper->curl, CURLOPT_URL, url); + g_task_set_task_data (task, g_steal_pointer (&helper), (GDestroyNotify) fwupd_client_curl_helper_free); + g_task_run_in_thread (task, fwupd_client_upload_bytes_thread_cb); +#else + g_task_return_new_error (task, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "no libcurl support"); +#endif +} - /* fall back to HTTP status codes in case the server is offline */ - if (!SOUP_STATUS_IS_SUCCESSFUL (status_code)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Failed to upllooad to %s: %s", - url, soup_status_get_phrase (status_code)); - return NULL; +/** + * fwupd_client_upload_bytes_finish: + * @self: A #FwupdClient + * @res: the #GAsyncResult + * @error: the #GError, or %NULL + * + * Gets the result of fwupd_client_upload_bytes_async(). + * + * Returns: (transfer full): response data, or %NULL for error + * + * Since: 1.5.0 + **/ +GBytes * +fwupd_client_upload_bytes_finish (FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (g_task_is_valid (res, self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} + +#ifdef SOUP_SESSION_COMPAT +/* this is bad; we dlopen libsoup-2.4.so.1 and get the gtype manually + * to avoid deps on both libcurl and libsoup whilst preserving ABI */ +static void +fwupd_client_ensure_soup_session (FwupdClient *self) +{ + FwupdClientObjectNewFunc func = NULL; + FwupdClientPrivate *priv = GET_PRIVATE (self); + GType soup_gtype; + + /* already set up */ + if (priv->soup_session != NULL) + return; + + /* known GType, just create */ + soup_gtype = g_type_from_name ("SoupSession"); + if (soup_gtype != 0) { + priv->soup_session = g_object_new (soup_gtype, NULL); + return; } - /* success */ - return g_bytes_new (msg->response_body->data, msg->response_body->length); + /* load the library at runtime, leaking the module */ + if (priv->soup_module == NULL) { + g_autofree gchar *fn = NULL; + fn = g_build_filename (FWUPD_LIBDIR, "libsoup-2.4.so.1", NULL); + priv->soup_module = g_module_open (fn, G_MODULE_BIND_LAZY); + if (priv->soup_module == NULL) { + g_warning ("failed to find libsoup library"); + return; + } + } + if (!g_module_symbol (priv->soup_module, + "soup_session_new", + (gpointer *) &func)) { + g_warning ("failed to find soup_session_get_type()"); + g_module_close (priv->soup_module); + priv->soup_module = NULL; + return; + } + priv->soup_session = func (); + g_object_set (priv->soup_session, "timeout", (guint) 60, NULL); } +#endif static void fwupd_client_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - FwupdClient *client = FWUPD_CLIENT (object); - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClient *self = FWUPD_CLIENT (object); + FwupdClientPrivate *priv = GET_PRIVATE (self); switch (prop_id) { case PROP_STATUS: @@ -2535,7 +4797,12 @@ g_value_set_boolean (value, priv->tainted); break; case PROP_SOUP_SESSION: +#ifdef SOUP_SESSION_COMPAT + fwupd_client_ensure_soup_session (self); g_value_set_object (value, priv->soup_session); +#else + g_value_set_object (value, NULL); +#endif break; case PROP_PERCENTAGE: g_value_set_uint (value, priv->percentage); @@ -2549,6 +4816,9 @@ case PROP_HOST_MACHINE_ID: g_value_set_string (value, priv->host_machine_id); break; + case PROP_HOST_SECURITY_ID: + g_value_set_string (value, priv->host_security_id); + break; case PROP_INTERACTIVE: g_value_set_boolean (value, priv->interactive); break; @@ -2562,8 +4832,8 @@ fwupd_client_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - FwupdClient *client = FWUPD_CLIENT (object); - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClient *self = FWUPD_CLIENT (object); + FwupdClientPrivate *priv = GET_PRIVATE (self); switch (prop_id) { case PROP_STATUS: @@ -2572,9 +4842,6 @@ case PROP_PERCENTAGE: priv->percentage = g_value_get_uint (value); break; - case PROP_SOUP_SESSION: - g_set_object (&priv->soup_session, g_value_get_object (value)); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -2592,7 +4859,7 @@ /** * FwupdClient::changed: - * @client: the #FwupdClient instance that emitted the signal + * @self: the #FwupdClient instance that emitted the signal * * The ::changed signal is emitted when the daemon internal has * changed, for instance when a device has been added or removed. @@ -2608,7 +4875,7 @@ /** * FwupdClient::state-changed: - * @client: the #FwupdClient instance that emitted the signal + * @self: the #FwupdClient instance that emitted the signal * @status: the #FwupdStatus * * The ::state-changed signal is emitted when the daemon status has @@ -2625,7 +4892,7 @@ /** * FwupdClient::device-added: - * @client: the #FwupdClient instance that emitted the signal + * @self: the #FwupdClient instance that emitted the signal * @result: the #FwupdDevice * * The ::device-added signal is emitted when a device has been @@ -2642,7 +4909,7 @@ /** * FwupdClient::device-removed: - * @client: the #FwupdClient instance that emitted the signal + * @self: the #FwupdClient instance that emitted the signal * @result: the #FwupdDevice * * The ::device-removed signal is emitted when a device has been @@ -2659,7 +4926,7 @@ /** * FwupdClient::device-changed: - * @client: the #FwupdClient instance that emitted the signal + * @self: the #FwupdClient instance that emitted the signal * @result: the #FwupdDevice * * The ::device-changed signal is emitted when a device has been @@ -2734,12 +5001,12 @@ /** * FwupdClient:soup-session: * - * The libsoup session. + * The libsoup session, now unused. * * Since: 1.4.5 */ - pspec = g_param_spec_object ("soup-session", NULL, NULL, SOUP_TYPE_SESSION, - G_PARAM_READWRITE | G_PARAM_STATIC_NAME); + pspec = g_param_spec_object ("soup-session", NULL, NULL, G_TYPE_OBJECT, + G_PARAM_READABLE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_SOUP_SESSION, pspec); /** @@ -2763,29 +5030,51 @@ pspec = g_param_spec_string ("host-machine-id", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_HOST_MACHINE_ID, pspec); + + /** + * FwupdClient:host-security-id: + * + * The host machine-id string + * + * Since: 1.5.0 + */ + pspec = g_param_spec_string ("host-security-id", NULL, NULL, + NULL, G_PARAM_READABLE | G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_HOST_SECURITY_ID, pspec); } static void -fwupd_client_init (FwupdClient *client) +fwupd_client_init (FwupdClient *self) { + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_mutex_init (&priv->proxy_mutex); + g_mutex_init (&priv->idle_mutex); + priv->idle_sources = g_ptr_array_new_with_free_func ((GDestroyNotify) fwupd_client_context_helper_free); } static void fwupd_client_finalize (GObject *object) { - FwupdClient *client = FWUPD_CLIENT (object); - FwupdClientPrivate *priv = GET_PRIVATE (client); + FwupdClient *self = FWUPD_CLIENT (object); + FwupdClientPrivate *priv = GET_PRIVATE (self); + g_clear_pointer (&priv->main_ctx, g_main_context_unref); g_free (priv->user_agent); g_free (priv->daemon_version); g_free (priv->host_product); g_free (priv->host_machine_id); - if (priv->conn != NULL) - g_object_unref (priv->conn); + g_free (priv->host_security_id); + g_mutex_clear (&priv->idle_mutex); + if (priv->idle_id != 0) + g_source_remove (priv->idle_id); + g_ptr_array_unref (priv->idle_sources); + g_mutex_clear (&priv->proxy_mutex); if (priv->proxy != NULL) g_object_unref (priv->proxy); +#ifdef SOUP_SESSION_COMPAT if (priv->soup_session != NULL) g_object_unref (priv->soup_session); +#endif G_OBJECT_CLASS (fwupd_client_parent_class)->finalize (object); } @@ -2802,7 +5091,7 @@ FwupdClient * fwupd_client_new (void) { - FwupdClient *client; - client = g_object_new (FWUPD_TYPE_CLIENT, NULL); - return FWUPD_CLIENT (client); + FwupdClient *self; + self = g_object_new (FWUPD_TYPE_CLIENT, NULL); + return FWUPD_CLIENT (self); } diff -Nru fwupd-1.4.5/libfwupd/fwupd-client.h fwupd-1.5.8/libfwupd/fwupd-client.h --- fwupd-1.4.5/libfwupd/fwupd-client.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupd/fwupd-client.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2018 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -11,6 +11,7 @@ #include "fwupd-enums.h" #include "fwupd-device.h" +#include "fwupd-plugin.h" #include "fwupd-remote.h" G_BEGIN_DECLS @@ -43,11 +44,13 @@ /** * FwupdClientDownloadFlags: * @FWUPD_CLIENT_DOWNLOAD_FLAG_NONE: No flags set + * @FWUPD_CLIENT_DOWNLOAD_FLAG_ONLY_IPFS: Only use IPFS when downloading URIs * * The options to use for downloading. **/ typedef enum { FWUPD_CLIENT_DOWNLOAD_FLAG_NONE = 0, /* Since: 1.4.5 */ + FWUPD_CLIENT_DOWNLOAD_FLAG_ONLY_IPFS = 1 << 0, /* Since: 1.5.6 */ /*< private >*/ FWUPD_CLIENT_DOWNLOAD_FLAG_LAST } FwupdClientDownloadFlags; @@ -67,164 +70,369 @@ } FwupdClientUploadFlags; FwupdClient *fwupd_client_new (void); -gboolean fwupd_client_connect (FwupdClient *client, - GCancellable *cancellable, - GError **error); -GPtrArray *fwupd_client_get_devices (FwupdClient *client, - GCancellable *cancellable, - GError **error); -GPtrArray *fwupd_client_get_history (FwupdClient *client, - GCancellable *cancellable, - GError **error); -GPtrArray *fwupd_client_get_releases (FwupdClient *client, - const gchar *device_id, - GCancellable *cancellable, - GError **error); -GPtrArray *fwupd_client_get_downgrades (FwupdClient *client, - const gchar *device_id, - GCancellable *cancellable, - GError **error); -GPtrArray *fwupd_client_get_upgrades (FwupdClient *client, - const gchar *device_id, - GCancellable *cancellable, - GError **error); -GPtrArray *fwupd_client_get_details (FwupdClient *client, - const gchar *filename, - GCancellable *cancellable, - GError **error); -gboolean fwupd_client_verify (FwupdClient *client, - const gchar *device_id, - GCancellable *cancellable, - GError **error); -gboolean fwupd_client_verify_update (FwupdClient *client, - const gchar *device_id, - GCancellable *cancellable, - GError **error); -gboolean fwupd_client_unlock (FwupdClient *client, - const gchar *device_id, +GMainContext *fwupd_client_get_main_context (FwupdClient *self); +void fwupd_client_set_main_context (FwupdClient *self, + GMainContext *main_ctx); +void fwupd_client_connect_async (FwupdClient *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_connect_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_get_devices_async (FwupdClient *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +GPtrArray *fwupd_client_get_devices_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_get_plugins_async (FwupdClient *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +GPtrArray *fwupd_client_get_plugins_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_get_history_async (FwupdClient *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +GPtrArray *fwupd_client_get_history_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_get_releases_async (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +GPtrArray *fwupd_client_get_releases_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_get_downgrades_async (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +GPtrArray *fwupd_client_get_downgrades_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_get_upgrades_async (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +GPtrArray *fwupd_client_get_upgrades_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_get_details_bytes_async (FwupdClient *self, + GBytes *bytes, GCancellable *cancellable, - GError **error); -gboolean fwupd_client_modify_config (FwupdClient *client, + GAsyncReadyCallback callback, + gpointer callback_data); +GPtrArray *fwupd_client_get_details_bytes_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_verify_async (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_verify_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_verify_update_async (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_verify_update_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_unlock_async (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_unlock_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_modify_config_async (FwupdClient *self, const gchar *key, const gchar *value, GCancellable *cancellable, - GError **error); -gboolean fwupd_client_activate (FwupdClient *client, - GCancellable *cancellable, - const gchar *device_id, - GError **error); -gboolean fwupd_client_clear_results (FwupdClient *client, - const gchar *device_id, - GCancellable *cancellable, - GError **error); -FwupdDevice *fwupd_client_get_results (FwupdClient *client, - const gchar *device_id, - GCancellable *cancellable, - GError **error); -FwupdDevice *fwupd_client_get_device_by_id (FwupdClient *client, - const gchar *device_id, - GCancellable *cancellable, - GError **error); -GPtrArray *fwupd_client_get_devices_by_guid (FwupdClient *client, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_modify_config_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_activate_async (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_activate_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_clear_results_async (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_clear_results_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_get_results_async (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +FwupdDevice *fwupd_client_get_results_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_get_host_security_attrs_async(FwupdClient *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +GPtrArray *fwupd_client_get_host_security_attrs_finish(FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_get_device_by_id_async (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +FwupdDevice *fwupd_client_get_device_by_id_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_get_devices_by_guid_async (FwupdClient *self, const gchar *guid, GCancellable *cancellable, - GError **error); -gboolean fwupd_client_install (FwupdClient *client, + GAsyncReadyCallback callback, + gpointer callback_data); +GPtrArray *fwupd_client_get_devices_by_guid_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_install_async (FwupdClient *self, const gchar *device_id, const gchar *filename, FwupdInstallFlags install_flags, GCancellable *cancellable, - GError **error); -gboolean fwupd_client_install_bytes (FwupdClient *client, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_install_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_install_bytes_async (FwupdClient *self, const gchar *device_id, GBytes *bytes, FwupdInstallFlags install_flags, GCancellable *cancellable, - GError **error); -gboolean fwupd_client_install_release (FwupdClient *client, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_install_bytes_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_install_release_async (FwupdClient *self, FwupdDevice *device, FwupdRelease *release, FwupdInstallFlags install_flags, GCancellable *cancellable, - GError **error); -gboolean fwupd_client_update_metadata (FwupdClient *client, - const gchar *remote_id, - const gchar *metadata_fn, - const gchar *signature_fn, + GAsyncReadyCallback callback, + gpointer callback_data) +G_DEPRECATED_FOR(fwupd_client_install_release2_async); +void fwupd_client_install_release2_async (FwupdClient *self, + FwupdDevice *device, + FwupdRelease *release, + FwupdInstallFlags install_flags, + FwupdClientDownloadFlags download_flags, GCancellable *cancellable, - GError **error); -gboolean fwupd_client_update_metadata_bytes (FwupdClient *client, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_install_release_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_update_metadata_bytes_async (FwupdClient *self, const gchar *remote_id, GBytes *metadata, GBytes *signature, GCancellable *cancellable, - GError **error); -gboolean fwupd_client_refresh_remote (FwupdClient *client, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_update_metadata_bytes_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_refresh_remote_async (FwupdClient *self, FwupdRemote *remote, GCancellable *cancellable, - GError **error); -gboolean fwupd_client_modify_remote (FwupdClient *client, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_refresh_remote_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_modify_remote_async (FwupdClient *self, const gchar *remote_id, const gchar *key, const gchar *value, GCancellable *cancellable, - GError **error); -gboolean fwupd_client_modify_device (FwupdClient *client, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_modify_remote_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_modify_device_async (FwupdClient *self, const gchar *device_id, const gchar *key, const gchar *value, GCancellable *cancellable, - GError **error); -FwupdStatus fwupd_client_get_status (FwupdClient *client); -gboolean fwupd_client_get_tainted (FwupdClient *client); -gboolean fwupd_client_get_daemon_interactive (FwupdClient *client); -guint fwupd_client_get_percentage (FwupdClient *client); -const gchar *fwupd_client_get_daemon_version (FwupdClient *client); -const gchar *fwupd_client_get_host_product (FwupdClient *client); -const gchar *fwupd_client_get_host_machine_id (FwupdClient *client); - -GPtrArray *fwupd_client_get_remotes (FwupdClient *client, - GCancellable *cancellable, - GError **error); -FwupdRemote *fwupd_client_get_remote_by_id (FwupdClient *client, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_modify_device_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_get_report_metadata_async (FwupdClient *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +GHashTable *fwupd_client_get_report_metadata_finish(FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; + +FwupdStatus fwupd_client_get_status (FwupdClient *self); +gboolean fwupd_client_get_tainted (FwupdClient *self); +gboolean fwupd_client_get_daemon_interactive (FwupdClient *self); +guint fwupd_client_get_percentage (FwupdClient *self); +const gchar *fwupd_client_get_daemon_version (FwupdClient *self); +const gchar *fwupd_client_get_host_product (FwupdClient *self); +const gchar *fwupd_client_get_host_machine_id (FwupdClient *self); +const gchar *fwupd_client_get_host_security_id (FwupdClient *self); + +void fwupd_client_get_remotes_async (FwupdClient *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +GPtrArray *fwupd_client_get_remotes_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_get_remote_by_id_async (FwupdClient *self, const gchar *remote_id, GCancellable *cancellable, - GError **error); - -gchar **fwupd_client_get_approved_firmware (FwupdClient *client, - GCancellable *cancellable, - GError **error); -gboolean fwupd_client_set_approved_firmware (FwupdClient *client, - gchar **checksums, - GCancellable *cancellable, - GError **error); -gchar *fwupd_client_self_sign (FwupdClient *client, + GAsyncReadyCallback callback, + gpointer callback_data); +FwupdRemote *fwupd_client_get_remote_by_id_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_get_approved_firmware_async(FwupdClient *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +GPtrArray *fwupd_client_get_approved_firmware_finish(FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_set_approved_firmware_async (FwupdClient *self, + GPtrArray *checksums, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_set_approved_firmware_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_get_blocked_firmware_async(FwupdClient *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +GPtrArray *fwupd_client_get_blocked_firmware_finish(FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_set_blocked_firmware_async (FwupdClient *self, + GPtrArray *checksums, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_set_blocked_firmware_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_self_sign_async (FwupdClient *self, const gchar *value, FwupdSelfSignFlags flags, GCancellable *cancellable, - GError **error); -gboolean fwupd_client_set_feature_flags (FwupdClient *client, + GAsyncReadyCallback callback, + gpointer callback_data); +gchar *fwupd_client_self_sign_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_set_feature_flags_async (FwupdClient *self, FwupdFeatureFlags feature_flags, GCancellable *cancellable, - GError **error); -void fwupd_client_set_user_agent (FwupdClient *client, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean fwupd_client_set_feature_flags_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +const gchar *fwupd_client_get_user_agent (FwupdClient *self); +void fwupd_client_set_user_agent (FwupdClient *self, const gchar *user_agent); -void fwupd_client_set_user_agent_for_package(FwupdClient *client, +void fwupd_client_set_user_agent_for_package(FwupdClient *self, const gchar *package_name, const gchar *package_version); -GBytes *fwupd_client_download_bytes (FwupdClient *client, +void fwupd_client_download_bytes_async (FwupdClient *self, const gchar *url, FwupdClientDownloadFlags flags, GCancellable *cancellable, - GError **error); -GBytes *fwupd_client_upload_bytes (FwupdClient *client, + GAsyncReadyCallback callback, + gpointer callback_data); +GBytes *fwupd_client_download_bytes_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_upload_bytes_async (FwupdClient *self, const gchar *url, const gchar *payload, const gchar *signature, FwupdClientUploadFlags flags, GCancellable *cancellable, - GError **error); -gboolean fwupd_client_ensure_networking (FwupdClient *client, - GError **error); + GAsyncReadyCallback callback, + gpointer callback_data); +GBytes *fwupd_client_upload_bytes_finish (FwupdClient *self, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fwupd_client_ensure_networking (FwupdClient *self, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; G_END_DECLS diff -Nru fwupd-1.4.5/libfwupd/fwupd-client-private.h fwupd-1.5.8/libfwupd/fwupd-client-private.h --- fwupd-1.4.5/libfwupd/fwupd-client-private.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupd/fwupd-client-private.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2016 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fwupd-client.h" + +#ifdef HAVE_GIO_UNIX +#include +#endif + +#ifdef HAVE_GIO_UNIX +void fwupd_client_get_details_stream_async (FwupdClient *self, + GUnixInputStream *istr, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +void fwupd_client_install_stream_async (FwupdClient *self, + const gchar *device_id, + GUnixInputStream *istr, + const gchar *filename_hint, + FwupdInstallFlags install_flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +void fwupd_client_update_metadata_stream_async(FwupdClient *self, + const gchar *remote_id, + GUnixInputStream *istr, + GUnixInputStream *istr_sig, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +void fwupd_client_download_bytes2_async (FwupdClient *self, + GPtrArray *urls, + FwupdClientDownloadFlags flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +#endif diff -Nru fwupd-1.4.5/libfwupd/fwupd-client-sync.c fwupd-1.5.8/libfwupd/fwupd-client-sync.c --- fwupd-1.4.5/libfwupd/fwupd-client-sync.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupd/fwupd-client-sync.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,2181 @@ +/* + * Copyright (C) 2016 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#ifdef HAVE_GIO_UNIX +#include +#endif + +#include "fwupd-client.h" +#include "fwupd-client-private.h" +#include "fwupd-client-sync.h" +#include "fwupd-common-private.h" +#include "fwupd-error.h" + +typedef struct { + gboolean ret; + gchar *str; + GError *error; + GPtrArray *array; + GMainContext *context; + GMainLoop *loop; + GVariant *val; + GHashTable *hash; + GBytes *bytes; + FwupdDevice *device; +} FwupdClientHelper; + +static void +fwupd_client_helper_free (FwupdClientHelper *helper) +{ + if (helper->val != NULL) + g_variant_unref (helper->val); + if (helper->error != NULL) + g_error_free (helper->error); + if (helper->array != NULL) + g_ptr_array_unref (helper->array); + if (helper->hash != NULL) + g_hash_table_unref (helper->hash); + if (helper->bytes != NULL) + g_bytes_unref (helper->bytes); + if (helper->device != NULL) + g_object_unref (helper->device); + g_free (helper->str); + g_main_loop_unref (helper->loop); + g_main_context_unref (helper->context); + g_main_context_pop_thread_default (helper->context); + g_free (helper); +} + +static FwupdClientHelper * +fwupd_client_helper_new (FwupdClient *self) +{ + FwupdClientHelper *helper; + helper = g_new0 (FwupdClientHelper, 1); + helper->context = fwupd_client_get_main_context (self); + helper->loop = g_main_loop_new (helper->context, FALSE); + g_main_context_push_thread_default (helper->context); + return helper; +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +G_DEFINE_AUTOPTR_CLEANUP_FUNC(FwupdClientHelper, fwupd_client_helper_free) +#pragma clang diagnostic pop + +static void +fwupd_client_connect_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_connect_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_connect: + * @self: A #FwupdClient + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Sets up the client ready for use. Most other methods call this + * for you, and do you only need to call this if you are just watching + * the client. + * + * Returns: %TRUE for success + * + * Since: 0.7.1 + **/ +gboolean +fwupd_client_connect (FwupdClient *self, GCancellable *cancellable, GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_connect_async (self, cancellable, fwupd_client_connect_cb, helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} + +static void +fwupd_client_get_devices_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->array = fwupd_client_get_devices_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_get_devices: + * @self: A #FwupdClient + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets all the devices registered with the daemon. + * + * Returns: (element-type FwupdDevice) (transfer container): results + * + * Since: 0.9.2 + **/ +GPtrArray * +fwupd_client_get_devices (FwupdClient *self, GCancellable *cancellable, GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_get_devices_async (self, cancellable, + fwupd_client_get_devices_cb, helper); + g_main_loop_run (helper->loop); + if (helper->array == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->array); +} + +static void +fwupd_client_get_plugins_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->array = fwupd_client_get_plugins_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_get_plugins: + * @self: A #FwupdClient + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets all the plugins being used the daemon. + * + * Returns: (element-type FwupdPlugin) (transfer container): results + * + * Since: 1.5.0 + **/ +GPtrArray * +fwupd_client_get_plugins (FwupdClient *self, GCancellable *cancellable, GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_get_plugins_async (self, cancellable, + fwupd_client_get_plugins_cb, helper); + g_main_loop_run (helper->loop); + if (helper->array == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->array); +} + +static void +fwupd_client_get_history_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->array = fwupd_client_get_history_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_get_history: + * @self: A #FwupdClient + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets all the history. + * + * Returns: (element-type FwupdDevice) (transfer container): results + * + * Since: 1.0.4 + **/ +GPtrArray * +fwupd_client_get_history (FwupdClient *self, GCancellable *cancellable, GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_get_history_async (self, cancellable, + fwupd_client_get_history_cb, helper); + g_main_loop_run (helper->loop); + if (helper->array == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->array); +} + +static void +fwupd_client_get_releases_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->array = fwupd_client_get_releases_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_get_releases: + * @self: A #FwupdClient + * @device_id: the device ID + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets all the releases for a specific device + * + * Returns: (element-type FwupdRelease) (transfer container): results + * + * Since: 0.9.3 + **/ +GPtrArray * +fwupd_client_get_releases (FwupdClient *self, const gchar *device_id, + GCancellable *cancellable, GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (device_id != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_get_releases_async (self, device_id, cancellable, + fwupd_client_get_releases_cb, helper); + g_main_loop_run (helper->loop); + if (helper->array == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->array); +} + +static void +fwupd_client_get_downgrades_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->array = fwupd_client_get_downgrades_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_get_downgrades: + * @self: A #FwupdClient + * @device_id: the device ID + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets all the downgrades for a specific device. + * + * Returns: (element-type FwupdRelease) (transfer container): results + * + * Since: 0.9.8 + **/ +GPtrArray * +fwupd_client_get_downgrades (FwupdClient *self, const gchar *device_id, + GCancellable *cancellable, GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (device_id != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_get_downgrades_async (self, device_id, cancellable, + fwupd_client_get_downgrades_cb, helper); + g_main_loop_run (helper->loop); + if (helper->array == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->array); +} + +static void +fwupd_client_get_upgrades_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->array = fwupd_client_get_upgrades_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_get_upgrades: + * @self: A #FwupdClient + * @device_id: the device ID + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets all the upgrades for a specific device. + * + * Returns: (element-type FwupdRelease) (transfer container): results + * + * Since: 0.9.8 + **/ +GPtrArray * +fwupd_client_get_upgrades (FwupdClient *self, const gchar *device_id, + GCancellable *cancellable, GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (device_id != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_get_upgrades_async (self, device_id, cancellable, + fwupd_client_get_upgrades_cb, helper); + g_main_loop_run (helper->loop); + if (helper->array == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->array); +} + +static void +fwupd_client_get_details_bytes_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->array = fwupd_client_get_details_bytes_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_get_details_bytes: + * @self: A #FwupdClient + * @bytes: the firmware blob, e.g. the contents of `firmware.cab` + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets details about a specific firmware file. + * + * Returns: (transfer container) (element-type FwupdDevice): an array of results + * + * Since: 1.5.0 + **/ +GPtrArray * +fwupd_client_get_details_bytes (FwupdClient *self, + GBytes *bytes, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (bytes != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_get_details_bytes_async (self, bytes, + cancellable, + fwupd_client_get_details_bytes_cb, + helper); + g_main_loop_run (helper->loop); + if (helper->array == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->array); +} + +#ifdef HAVE_GIO_UNIX +static void +fwupd_client_get_details_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->array = fwupd_client_get_details_bytes_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} +#endif + +/** + * fwupd_client_get_details: + * @self: A #FwupdClient + * @filename: the firmware filename, e.g. `firmware.cab` + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets details about a specific firmware file. + * + * Returns: (transfer container) (element-type FwupdDevice): an array of results + * + * Since: 1.0.0 + **/ +GPtrArray * +fwupd_client_get_details (FwupdClient *self, + const gchar *filename, + GCancellable *cancellable, + GError **error) +{ +#ifdef HAVE_GIO_UNIX + g_autoptr(GUnixInputStream) istr = NULL; + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (filename != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + istr = fwupd_unix_input_stream_from_fn (filename, error); + if (istr == NULL) + return NULL; + helper = fwupd_client_helper_new (self); + fwupd_client_get_details_stream_async (self, istr, cancellable, + fwupd_client_get_details_cb, + helper); + g_main_loop_run (helper->loop); + if (helper->array == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->array); +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as is unavailable"); + return NULL; +#endif +} + +static void +fwupd_client_verify_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_verify_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_verify: + * @self: A #FwupdClient + * @device_id: the device ID + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Verify a specific device. + * + * Returns: %TRUE for verification success + * + * Since: 0.7.0 + **/ +gboolean +fwupd_client_verify (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (device_id != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_verify_async (self, device_id, cancellable, + fwupd_client_verify_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} + +static void +fwupd_client_verify_update_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_verify_update_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_verify_update: + * @self: A #FwupdClient + * @device_id: the device ID + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Update the verification record for a specific device. + * + * Returns: %TRUE for verification success + * + * Since: 0.8.0 + **/ +gboolean +fwupd_client_verify_update (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (device_id != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_verify_update_async (self, device_id, cancellable, + fwupd_client_verify_update_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} + +static void +fwupd_client_unlock_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_unlock_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_unlock: + * @self: A #FwupdClient + * @device_id: the device ID + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Unlocks a specific device so firmware can be read or wrote. + * + * Returns: %TRUE for success + * + * Since: 0.7.0 + **/ +gboolean +fwupd_client_unlock (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (device_id != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_unlock_async (self, device_id, cancellable, + fwupd_client_unlock_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} +static void +fwupd_client_modify_config_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_modify_config_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_modify_config + * @self: A #FwupdClient + * @key: key, e.g. `DisabledPlugins` + * @value: value, e.g. `*` + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Modifies a daemon config option. + * The daemon will only respond to this request with proper permissions + * + * Returns: %TRUE for success + * + * Since: 1.2.8 + **/ +gboolean +fwupd_client_modify_config (FwupdClient *self, + const gchar *key, + const gchar *value, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (key != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_modify_config_async (self, key, value, + cancellable, + fwupd_client_modify_config_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} + +static void +fwupd_client_activate_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_activate_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_activate: + * @self: A #FwupdClient + * @cancellable: the #GCancellable, or %NULL + * @device_id: a device + * @error: the #GError, or %NULL + * + * Activates up a device, which normally means the device switches to a new + * firmware version. This should only be called when data loss cannot occur. + * + * Returns: %TRUE for success + * + * Since: 1.2.6 + **/ +gboolean +fwupd_client_activate (FwupdClient *self, + GCancellable *cancellable, + const gchar *device_id, /* yes, this is the wrong way around :/ */ + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (device_id != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_activate_async (self, device_id, + cancellable, + fwupd_client_activate_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} + +static void +fwupd_client_clear_results_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_clear_results_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_clear_results: + * @self: A #FwupdClient + * @device_id: the device ID + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Clears the results for a specific device. + * + * Returns: %TRUE for success + * + * Since: 0.7.0 + **/ +gboolean +fwupd_client_clear_results (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (device_id != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_clear_results_async (self, device_id, + cancellable, + fwupd_client_clear_results_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} + +static void +fwupd_client_get_results_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->device = fwupd_client_get_results_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_get_results: + * @self: A #FwupdClient + * @device_id: the device ID + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets the results of a previous firmware update for a specific device. + * + * Returns: (transfer full): a #FwupdDevice, or %NULL for failure + * + * Since: 0.7.0 + **/ +FwupdDevice * +fwupd_client_get_results (FwupdClient *self, const gchar *device_id, + GCancellable *cancellable, GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (device_id != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_get_results_async (self, device_id, cancellable, + fwupd_client_get_results_cb, helper); + g_main_loop_run (helper->loop); + if (helper->device == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->device); +} + +static void +fwupd_client_get_host_security_attrs_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->array = fwupd_client_get_host_security_attrs_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_get_host_security_attrs: + * @self: A #FwupdClient + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets all the host security attributes from the daemon. + * + * Returns: (element-type FwupdSecurityAttr) (transfer container): attributes + * + * Since: 1.5.0 + **/ +GPtrArray * +fwupd_client_get_host_security_attrs (FwupdClient *self, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_get_host_security_attrs_async (self, cancellable, + fwupd_client_get_host_security_attrs_cb, + helper); + g_main_loop_run (helper->loop); + if (helper->array == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->array); +} + +static void +fwupd_client_get_device_by_id_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->device = fwupd_client_get_device_by_id_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_get_device_by_id: + * @self: A #FwupdClient + * @device_id: the device ID, e.g. `usb:00:01:03:03` + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets a device by it's device ID. + * + * Returns: (transfer full): a #FwupdDevice or %NULL + * + * Since: 0.9.3 + **/ +FwupdDevice * +fwupd_client_get_device_by_id (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (device_id != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_get_device_by_id_async (self, device_id, cancellable, + fwupd_client_get_device_by_id_cb, + helper); + g_main_loop_run (helper->loop); + if (helper->device == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->device); +} + +static void +fwupd_client_get_devices_by_guid_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->array = fwupd_client_get_devices_by_guid_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_get_devices_by_guid: + * @self: A #FwupdClient + * @guid: the GUID, e.g. `e22c4520-43dc-5bb3-8245-5787fead9b63` + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets any devices that provide a specific GUID. An error is returned if no + * devices contains this GUID. + * + * Returns: (element-type FwupdDevice) (transfer container): devices or %NULL + * + * Since: 1.4.1 + **/ +GPtrArray * +fwupd_client_get_devices_by_guid (FwupdClient *self, const gchar *guid, + GCancellable *cancellable, GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (guid != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_get_devices_by_guid_async (self, guid, cancellable, + fwupd_client_get_devices_by_guid_cb, + helper); + g_main_loop_run (helper->loop); + if (helper->array == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->array); +} + +#ifdef HAVE_GIO_UNIX +static void +fwupd_client_install_fd_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_install_bytes_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} +#endif + +/** + * fwupd_client_install: + * @self: A #FwupdClient + * @device_id: the device ID + * @filename: the filename to install + * @install_flags: the #FwupdInstallFlags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Install a file onto a specific device. + * + * Returns: %TRUE for success + * + * Since: 0.7.0 + **/ +gboolean +fwupd_client_install (FwupdClient *self, + const gchar *device_id, + const gchar *filename, + FwupdInstallFlags install_flags, + GCancellable *cancellable, + GError **error) +{ +#ifdef HAVE_GIO_UNIX + g_autoptr(GUnixInputStream) istr = NULL; + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (device_id != NULL, FALSE); + g_return_val_if_fail (filename != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + /* move to a thread if this ever takes more than a few ms */ + istr = fwupd_unix_input_stream_from_fn (filename, error); + if (istr == NULL) + return FALSE; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_install_stream_async (self, device_id, istr, filename, + install_flags, cancellable, + fwupd_client_install_fd_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as is unavailable"); + return FALSE; +#endif +} + +static void +fwupd_client_install_bytes_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_install_bytes_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_install_bytes: + * @self: A #FwupdClient + * @device_id: the device ID + * @bytes: #GBytes + * @install_flags: the #FwupdInstallFlags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Install firmware onto a specific device. + * + * Returns: %TRUE for success + * + * Since: 1.4.5 + **/ +gboolean +fwupd_client_install_bytes (FwupdClient *self, + const gchar *device_id, + GBytes *bytes, + FwupdInstallFlags install_flags, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (device_id != NULL, FALSE); + g_return_val_if_fail (bytes != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_install_bytes_async (self, device_id, bytes, install_flags, + cancellable, + fwupd_client_install_bytes_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} +static void +fwupd_client_install_release_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_install_release_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_install_release2: + * @self: A #FwupdClient + * @device: A #FwupdDevice + * @release: A #FwupdRelease + * @install_flags: the #FwupdInstallFlags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL + * @download_flags: the #FwupdClientDownloadFlags, e.g. %FWUPD_CLIENT_DOWNLOAD_FLAG_NONE + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Installs a new release on a device, downloading the firmware if required. + * + * Returns: %TRUE for success + * + * Since: 1.5.6 + **/ +gboolean +fwupd_client_install_release2 (FwupdClient *self, + FwupdDevice *device, + FwupdRelease *release, + FwupdInstallFlags install_flags, + FwupdClientDownloadFlags download_flags, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (FWUPD_IS_DEVICE (device), FALSE); + g_return_val_if_fail (FWUPD_IS_RELEASE (release), FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_install_release2_async (self, device, release, + install_flags, download_flags, + cancellable, + fwupd_client_install_release_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} + +/** + * fwupd_client_install_release: + * @self: A #FwupdClient + * @device: A #FwupdDevice + * @release: A #FwupdRelease + * @install_flags: the #FwupdInstallFlags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Installs a new release on a device, downloading the firmware if required. + * + * Returns: %TRUE for success + * + * Since: 1.4.5 + * Deprecated: 1.5.6 + **/ +gboolean +fwupd_client_install_release (FwupdClient *self, + FwupdDevice *device, + FwupdRelease *release, + FwupdInstallFlags install_flags, + GCancellable *cancellable, + GError **error) +{ + return fwupd_client_install_release2 (self, device, release, install_flags, + FWUPD_CLIENT_DOWNLOAD_FLAG_NONE, + cancellable, error); +} + +#ifdef HAVE_GIO_UNIX +static void +fwupd_client_update_metadata_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_update_metadata_bytes_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} +#endif + +/** + * fwupd_client_update_metadata: + * @self: A #FwupdClient + * @remote_id: the remote ID, e.g. `lvfs-testing` + * @metadata_fn: the XML metadata filename + * @signature_fn: the GPG signature file + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Updates the metadata. This allows a session process to download the metadata + * and metadata signing file to be passed into the daemon to be checked and + * parsed. + * + * The @remote_id allows the firmware to be tagged so that the remote can be + * matched when the firmware is downloaded. + * + * Returns: %TRUE for success + * + * Since: 1.0.0 + **/ +gboolean +fwupd_client_update_metadata (FwupdClient *self, + const gchar *remote_id, + const gchar *metadata_fn, + const gchar *signature_fn, + GCancellable *cancellable, + GError **error) +{ +#ifdef HAVE_GIO_UNIX + g_autoptr(GUnixInputStream) istr = NULL; + g_autoptr(GUnixInputStream) istr_sig = NULL; + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (remote_id != NULL, FALSE); + g_return_val_if_fail (metadata_fn != NULL, FALSE); + g_return_val_if_fail (signature_fn != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + istr = fwupd_unix_input_stream_from_fn (metadata_fn, error); + if (istr == NULL) + return FALSE; + istr_sig = fwupd_unix_input_stream_from_fn (signature_fn, error); + if (istr_sig == NULL) + return FALSE; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_update_metadata_stream_async (self, remote_id, istr, istr_sig, cancellable, + fwupd_client_update_metadata_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as is unavailable"); + return FALSE; +#endif +} + +static void +fwupd_client_update_metadata_bytes_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_update_metadata_bytes_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_update_metadata_bytes: + * @self: A #FwupdClient + * @remote_id: remote ID, e.g. `lvfs-testing` + * @metadata: XML metadata data + * @signature: signature data + * @cancellable: #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Updates the metadata. This allows a session process to download the metadata + * and metadata signing file to be passed into the daemon to be checked and + * parsed. + * + * The @remote_id allows the firmware to be tagged so that the remote can be + * matched when the firmware is downloaded. + * + * Returns: %TRUE for success + * + * Since: 1.4.5 + **/ +gboolean +fwupd_client_update_metadata_bytes (FwupdClient *self, + const gchar *remote_id, + GBytes *metadata, + GBytes *signature, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (remote_id != NULL, FALSE); + g_return_val_if_fail (metadata != NULL, FALSE); + g_return_val_if_fail (signature != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_update_metadata_bytes_async (self, remote_id, metadata, signature, + cancellable, + fwupd_client_update_metadata_bytes_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} + +static void +fwupd_client_refresh_remote_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_refresh_remote_finish (FWUPD_CLIENT (source), + res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_refresh_remote: + * @self: A #FwupdClient + * @remote: A #FwupdRemote + * @cancellable: A #GCancellable, or %NULL + * @error: A #GError, or %NULL + * + * Refreshes a remote by downloading new metadata. + * + * Returns: %TRUE for success + * + * Since: 1.4.5 + **/ +gboolean +fwupd_client_refresh_remote (FwupdClient *self, + FwupdRemote *remote, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (FWUPD_IS_REMOTE (remote), FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_refresh_remote_async (self, remote, cancellable, + fwupd_client_refresh_remote_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} + +static void +fwupd_client_modify_remote_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_modify_remote_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_modify_remote: + * @self: A #FwupdClient + * @remote_id: the remote ID, e.g. `lvfs-testing` + * @key: the key, e.g. `Enabled` + * @value: the key, e.g. `true` + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Modifies a system remote in a specific way. + * + * NOTE: User authentication may be required to complete this action. + * + * Returns: %TRUE for success + * + * Since: 0.9.8 + **/ +gboolean +fwupd_client_modify_remote (FwupdClient *self, + const gchar *remote_id, + const gchar *key, + const gchar *value, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (remote_id != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_modify_remote_async (self, remote_id, key, value, + cancellable, + fwupd_client_modify_remote_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} + +static void +fwupd_client_get_report_metadata_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->hash = fwupd_client_get_report_metadata_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_get_report_metadata: + * @self: A #FwupdClient + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets all the report metadata from the daemon. + * + * Returns: (transfer container): attributes + * + * Since: 1.5.0 + **/ +GHashTable * +fwupd_client_get_report_metadata (FwupdClient *self, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_get_report_metadata_async (self, cancellable, + fwupd_client_get_report_metadata_cb, + helper); + g_main_loop_run (helper->loop); + if (helper->hash == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->hash); +} + +static void +fwupd_client_modify_device_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_modify_device_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_modify_device: + * @self: A #FwupdClient + * @device_id: the device ID + * @key: the key, e.g. `Flags` + * @value: the key, e.g. `reported` + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Modifies a device in a specific way. Not all properties on the #FwupdDevice + * are settable by the client, and some may have other restrictions on @value. + * + * NOTE: User authentication may be required to complete this action. + * + * Returns: %TRUE for success + * + * Since: 1.0.4 + **/ +gboolean +fwupd_client_modify_device (FwupdClient *self, + const gchar *device_id, + const gchar *key, + const gchar *value, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (device_id != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_modify_device_async (self, device_id, key, value, + cancellable, + fwupd_client_modify_device_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} + +static void +fwupd_client_get_remotes_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->array = fwupd_client_get_remotes_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_get_remotes: + * @self: A #FwupdClient + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets the list of remotes that have been configured for the system. + * + * Returns: (element-type FwupdRemote) (transfer container): list of remotes, or %NULL + * + * Since: 0.9.3 + **/ +GPtrArray * +fwupd_client_get_remotes (FwupdClient *self, GCancellable *cancellable, GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_get_remotes_async (self, cancellable, + fwupd_client_get_remotes_cb, helper); + g_main_loop_run (helper->loop); + if (helper->array == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->array); +} + +static FwupdRemote * +fwupd_client_get_remote_by_id_noref (GPtrArray *remotes, const gchar *remote_id) +{ + for (guint i = 0; i < remotes->len; i++) { + FwupdRemote *remote = g_ptr_array_index (remotes, i); + if (g_strcmp0 (remote_id, fwupd_remote_get_id (remote)) == 0) + return remote; + } + return NULL; +} + +/** + * fwupd_client_get_remote_by_id: + * @self: A #FwupdClient + * @remote_id: the remote ID, e.g. `lvfs-testing` + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets a specific remote that has been configured for the system. + * + * Returns: (transfer full): a #FwupdRemote, or %NULL if not found + * + * Since: 0.9.3 + **/ +FwupdRemote * +fwupd_client_get_remote_by_id (FwupdClient *self, + const gchar *remote_id, + GCancellable *cancellable, + GError **error) +{ + FwupdRemote *remote; + g_autoptr(GPtrArray) remotes = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (remote_id != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* find remote in list */ + remotes = fwupd_client_get_remotes (self, cancellable, error); + if (remotes == NULL) + return NULL; + remote = fwupd_client_get_remote_by_id_noref (remotes, remote_id); + if (remote == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "No remote '%s' found in search paths", + remote_id); + return NULL; + } + + /* success */ + return g_object_ref (remote); +} + +static void +fwupd_client_get_approved_firmware_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->array = fwupd_client_get_approved_firmware_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_get_approved_firmware: + * @self: A #FwupdClient + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets the list of approved firmware. + * + * Returns: (transfer full): checksums, or %NULL for error + * + * Since: 1.2.6 + **/ +gchar ** +fwupd_client_get_approved_firmware (FwupdClient *self, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + gchar **argv; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_get_approved_firmware_async (self, cancellable, + fwupd_client_get_approved_firmware_cb, + helper); + g_main_loop_run (helper->loop); + if (helper->array == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + argv = g_new0 (gchar *, helper->array->len + 1); + for (guint i = 0; i < helper->array->len; i++) { + const gchar *tmp = g_ptr_array_index (helper->array, i); + argv[i] = g_strdup (tmp); + } + return argv; +} + +static void +fwupd_client_set_approved_firmware_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_set_approved_firmware_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_set_approved_firmware: + * @self: A #FwupdClient + * @checksums: Array of checksums + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Sets the list of approved firmware. + * + * Returns: %TRUE for success + * + * Since: 1.2.6 + **/ +gboolean +fwupd_client_set_approved_firmware (FwupdClient *self, + gchar **checksums, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + g_autoptr(GPtrArray) array = g_ptr_array_new_with_free_func (g_free); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + /* convert */ + for (guint i = 0; checksums[i] != NULL; i++) + g_ptr_array_add (array, g_strdup (checksums[i])); + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_set_approved_firmware_async (self, array, cancellable, + fwupd_client_set_approved_firmware_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} + +static void +fwupd_client_get_blocked_firmware_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->array = fwupd_client_get_blocked_firmware_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_get_blocked_firmware: + * @self: A #FwupdClient + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets the list of blocked firmware. + * + * Returns: (transfer full): checksums, or %NULL for error + * + * Since: 1.4.6 + **/ +gchar ** +fwupd_client_get_blocked_firmware (FwupdClient *self, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + gchar **argv; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_get_blocked_firmware_async (self, cancellable, + fwupd_client_get_blocked_firmware_cb, + helper); + g_main_loop_run (helper->loop); + if (helper->array == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + argv = g_new0 (gchar *, helper->array->len + 1); + for (guint i = 0; i < helper->array->len; i++) { + const gchar *tmp = g_ptr_array_index (helper->array, i); + argv[i] = g_strdup (tmp); + } + return argv; +} + +static void +fwupd_client_set_blocked_firmware_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_set_blocked_firmware_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_set_blocked_firmware: + * @self: A #FwupdClient + * @checksums: Array of checksums + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Sets the list of approved firmware. + * + * Returns: %TRUE for success + * + * Since: 1.4.6 + **/ +gboolean +fwupd_client_set_blocked_firmware (FwupdClient *self, + gchar **checksums, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + g_autoptr(GPtrArray) array = g_ptr_array_new_with_free_func (g_free); + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (checksums != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + for (guint i = 0; checksums[i] != NULL; i++) + g_ptr_array_add (array, g_strdup (checksums[i])); + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_set_blocked_firmware_async (self, array, cancellable, + fwupd_client_set_blocked_firmware_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} + +static void +fwupd_client_set_feature_flags_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->ret = fwupd_client_set_feature_flags_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_set_feature_flags: + * @self: A #FwupdClient + * @feature_flags: #FwupdFeatureFlags, e.g. %FWUPD_FEATURE_FLAG_UPDATE_TEXT + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Sets the features the client supports. This allows firmware to depend on + * specific front-end features, for instance showing the user an image on + * how to detach the hardware. + * + * Clients can call this none or multiple times. + * + * Returns: %TRUE for success + * + * Since: 1.4.5 + **/ +gboolean +fwupd_client_set_feature_flags (FwupdClient *self, + FwupdFeatureFlags feature_flags, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return FALSE; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_set_feature_flags_async (self, feature_flags, cancellable, + fwupd_client_set_feature_flags_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return FALSE; + } + return TRUE; +} + +static void +fwupd_client_self_sign_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->str = fwupd_client_self_sign_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_self_sign: + * @self: A #FwupdClient + * @value: A string to sign, typically a JSON blob + * @flags: #FwupdSelfSignFlags, e.g. %FWUPD_SELF_SIGN_FLAG_ADD_TIMESTAMP + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Signs the data using the client self-signed certificate. + * + * Returns: a signature, or %NULL for failure + * + * Since: 1.2.6 + **/ +gchar * +fwupd_client_self_sign (FwupdClient *self, + const gchar *value, + FwupdSelfSignFlags flags, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (value != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_self_sign_async (self, value, flags, cancellable, + fwupd_client_self_sign_cb, + helper); + g_main_loop_run (helper->loop); + if (helper->str == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->str); +} + +static void +fwupd_client_download_bytes_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->bytes = fwupd_client_download_bytes_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_download_bytes: + * @self: A #FwupdClient + * @url: the remote URL + * @flags: #FwupdClientDownloadFlags, e.g. %FWUPD_CLIENT_DOWNLOAD_FLAG_NONE + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Downloads data from a remote server. The fwupd_client_set_user_agent() function + * should be called before this method is used. + * + * Returns: (transfer full): downloaded data, or %NULL for error + * + * Since: 1.4.5 + **/ +GBytes * +fwupd_client_download_bytes (FwupdClient *self, + const gchar *url, + FwupdClientDownloadFlags flags, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (url != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + g_return_val_if_fail (fwupd_client_get_user_agent (self) != NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_download_bytes_async (self, url, flags, cancellable, + fwupd_client_download_bytes_cb, helper); + g_main_loop_run (helper->loop); + if (helper->bytes == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->bytes); +} + +/** + * fwupd_client_download_file: + * @self: A #FwupdClient + * @url: the remote URL + * @file: a #GFile + * @flags: #FwupdClientDownloadFlags, e.g. %FWUPD_CLIENT_DOWNLOAD_FLAG_NONE + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Downloads data from a remote server. The fwupd_client_set_user_agent() function + * should be called before this method is used. + * + * Returns: %TRUE if the file was written, or %NULL for error + * + * Since: 1.5.2 + **/ +gboolean +fwupd_client_download_file (FwupdClient *self, + const gchar *url, + GFile *file, + FwupdClientDownloadFlags flags, + GCancellable *cancellable, + GError **error) +{ + gssize size; + g_autoptr(GBytes) bytes = NULL; + g_autoptr(GOutputStream) ostream = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), FALSE); + g_return_val_if_fail (url != NULL, FALSE); + g_return_val_if_fail (G_IS_FILE (file), FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + g_return_val_if_fail (fwupd_client_get_user_agent (self) != NULL, FALSE); + + /* download then write */ + bytes = fwupd_client_download_bytes (self, url, flags, cancellable, error); + if (bytes == NULL) + return FALSE; + ostream = G_OUTPUT_STREAM (g_file_replace (file, NULL, FALSE, + G_FILE_CREATE_NONE, NULL, error)); + if (ostream == NULL) + return FALSE; + size = g_output_stream_write_bytes (ostream, bytes, NULL, error); + if (size < 0) + return FALSE; + + /* success */ + return TRUE; +} + +static void +fwupd_client_upload_bytes_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *) user_data; + helper->bytes = fwupd_client_upload_bytes_finish (FWUPD_CLIENT (source), res, &helper->error); + g_main_loop_quit (helper->loop); +} + +/** + * fwupd_client_upload_bytes: + * @self: A #FwupdClient + * @url: the remote URL + * @payload: payload string + * @signature: (nullable): signature string + * @flags: #FwupdClientDownloadFlags, e.g. %FWUPD_CLIENT_DOWNLOAD_FLAG_NONE + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Uploads data to a remote server. The fwupd_client_set_user_agent() function + * should be called before this method is used. + * + * Returns: (transfer full): response data, or %NULL for error + * + * Since: 1.4.5 + **/ +GBytes * +fwupd_client_upload_bytes (FwupdClient *self, + const gchar *url, + const gchar *payload, + const gchar *signature, + FwupdClientUploadFlags flags, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (self), NULL); + g_return_val_if_fail (url != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (self, cancellable, error)) + return NULL; + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new (self); + fwupd_client_upload_bytes_async (self, url, payload, signature, flags, cancellable, + fwupd_client_upload_bytes_cb, helper); + g_main_loop_run (helper->loop); + if (helper->bytes == NULL) { + g_propagate_error (error, g_steal_pointer (&helper->error)); + return NULL; + } + return g_steal_pointer (&helper->bytes); +} diff -Nru fwupd-1.4.5/libfwupd/fwupd-client-sync.h fwupd-1.5.8/libfwupd/fwupd-client-sync.h --- fwupd-1.4.5/libfwupd/fwupd-client-sync.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupd/fwupd-client-sync.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2016 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fwupd-client.h" + +G_BEGIN_DECLS + +gboolean fwupd_client_connect (FwupdClient *self, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +GPtrArray *fwupd_client_get_devices (FwupdClient *self, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +GPtrArray *fwupd_client_get_plugins (FwupdClient *self, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +GPtrArray *fwupd_client_get_history (FwupdClient *self, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +GPtrArray *fwupd_client_get_releases (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +GPtrArray *fwupd_client_get_downgrades (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +GPtrArray *fwupd_client_get_upgrades (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +GPtrArray *fwupd_client_get_details (FwupdClient *self, + const gchar *filename, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +GPtrArray *fwupd_client_get_details_bytes (FwupdClient *self, + GBytes *bytes, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fwupd_client_verify (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fwupd_client_verify_update (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fwupd_client_unlock (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fwupd_client_modify_config (FwupdClient *self, + const gchar *key, + const gchar *value, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fwupd_client_activate (FwupdClient *self, + GCancellable *cancellable, + const gchar *device_id, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fwupd_client_clear_results (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +FwupdDevice *fwupd_client_get_results (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +GPtrArray *fwupd_client_get_host_security_attrs (FwupdClient *self, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +FwupdDevice *fwupd_client_get_device_by_id (FwupdClient *self, + const gchar *device_id, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +GPtrArray *fwupd_client_get_devices_by_guid (FwupdClient *self, + const gchar *guid, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fwupd_client_install (FwupdClient *self, + const gchar *device_id, + const gchar *filename, + FwupdInstallFlags install_flags, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fwupd_client_install_bytes (FwupdClient *self, + const gchar *device_id, + GBytes *bytes, + FwupdInstallFlags install_flags, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fwupd_client_install_release (FwupdClient *self, + FwupdDevice *device, + FwupdRelease *release, + FwupdInstallFlags install_flags, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT +G_DEPRECATED_FOR(fwupd_client_install_release2); +gboolean fwupd_client_install_release2 (FwupdClient *self, + FwupdDevice *device, + FwupdRelease *release, + FwupdInstallFlags install_flags, + FwupdClientDownloadFlags download_flags, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fwupd_client_update_metadata (FwupdClient *self, + const gchar *remote_id, + const gchar *metadata_fn, + const gchar *signature_fn, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fwupd_client_update_metadata_bytes (FwupdClient *self, + const gchar *remote_id, + GBytes *metadata, + GBytes *signature, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fwupd_client_refresh_remote (FwupdClient *self, + FwupdRemote *remote, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fwupd_client_modify_remote (FwupdClient *self, + const gchar *remote_id, + const gchar *key, + const gchar *value, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fwupd_client_modify_device (FwupdClient *self, + const gchar *device_id, + const gchar *key, + const gchar *value, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +GHashTable *fwupd_client_get_report_metadata (FwupdClient *self, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +GPtrArray *fwupd_client_get_remotes (FwupdClient *self, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +FwupdRemote *fwupd_client_get_remote_by_id (FwupdClient *self, + const gchar *remote_id, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gchar **fwupd_client_get_approved_firmware (FwupdClient *self, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fwupd_client_set_approved_firmware (FwupdClient *self, + gchar **checksums, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gchar **fwupd_client_get_blocked_firmware (FwupdClient *self, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fwupd_client_set_blocked_firmware (FwupdClient *self, + gchar **checksums, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gchar *fwupd_client_self_sign (FwupdClient *self, + const gchar *value, + FwupdSelfSignFlags flags, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fwupd_client_set_feature_flags (FwupdClient *self, + FwupdFeatureFlags feature_flags, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +GBytes *fwupd_client_download_bytes (FwupdClient *self, + const gchar *url, + FwupdClientDownloadFlags flags, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fwupd_client_download_file (FwupdClient *self, + const gchar *url, + GFile *file, + FwupdClientDownloadFlags flags, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +GBytes *fwupd_client_upload_bytes (FwupdClient *self, + const gchar *url, + const gchar *payload, + const gchar *signature, + FwupdClientUploadFlags flags, + GCancellable *cancellable, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; + +G_END_DECLS diff -Nru fwupd-1.4.5/libfwupd/fwupd-common.c fwupd-1.5.8/libfwupd/fwupd-common.c --- fwupd-1.4.5/libfwupd/fwupd-common.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupd/fwupd-common.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -158,6 +158,8 @@ g_autofree gchar *buf = NULL; g_auto(GStrv) lines = NULL; + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + /* TODO: Read the Windows version */ #ifdef _WIN32 hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); @@ -169,7 +171,6 @@ /* find the correct file */ for (guint i = 0; paths[i] != NULL; i++) { - g_debug ("looking for os-release at %s", paths[i]); if (g_file_test (paths[i], G_FILE_TEST_EXISTS)) { filename = paths[i]; break; @@ -349,6 +350,9 @@ g_autoptr(GChecksum) csum = NULL; gsize sz = 0; + g_return_val_if_fail (salt != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + /* one of these has to exist */ fns[0] = g_build_filename (FWUPD_SYSCONFDIR, "machine-id", NULL); fns[1] = g_build_filename (FWUPD_LOCALSTATEDIR, "lib", "dbus", "machine-id", NULL); @@ -530,6 +534,9 @@ g_autoptr(JsonGenerator) json_generator = NULL; g_autoptr(JsonNode) json_root = NULL; + g_return_val_if_fail (devices != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + /* get a hash that represents the machine */ machine_id = fwupd_build_machine_id ("fwupd", error); if (machine_id == NULL) @@ -613,19 +620,19 @@ /* mixed is bizaar, but specified as the DCE encoding */ if (flags & FWUPD_GUID_FLAG_MIXED_ENDIAN) { return g_strdup_printf ("%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", - GUINT32_FROM_LE(gnat.a), - GUINT16_FROM_LE(gnat.b), - GUINT16_FROM_LE(gnat.c), - GUINT16_FROM_BE(gnat.d), + (guint) GUINT32_FROM_LE(gnat.a), + (guint) GUINT16_FROM_LE(gnat.b), + (guint) GUINT16_FROM_LE(gnat.c), + (guint) GUINT16_FROM_BE(gnat.d), gnat.e[0], gnat.e[1], gnat.e[2], gnat.e[3], gnat.e[4], gnat.e[5]); } return g_strdup_printf ("%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", - GUINT32_FROM_BE(gnat.a), - GUINT16_FROM_BE(gnat.b), - GUINT16_FROM_BE(gnat.c), - GUINT16_FROM_BE(gnat.d), + (guint) GUINT32_FROM_BE(gnat.a), + (guint) GUINT16_FROM_BE(gnat.b), + (guint) GUINT16_FROM_BE(gnat.c), + (guint) GUINT16_FROM_BE(gnat.d), gnat.e[0], gnat.e[1], gnat.e[2], gnat.e[3], gnat.e[4], gnat.e[5]); @@ -723,6 +730,7 @@ g_auto(GStrv) split = NULL; g_return_val_if_fail (guidstr != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* split into sections */ if (strlen (guidstr) != 36) { @@ -941,6 +949,96 @@ return hash; } +static void +fwupd_input_stream_read_bytes_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + GByteArray *bufarr; + GInputStream *stream = G_INPUT_STREAM (source); + g_autoptr(GBytes) bytes = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GTask) task = G_TASK (user_data); +#if GLIB_CHECK_VERSION(2, 64, 0) + guint8 *buf; + gsize bufsz = 0; +#endif + + /* read buf */ + bytes = g_input_stream_read_bytes_finish (stream, res, &error); + if (bytes == NULL) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + /* add bytes to buffer */ + bufarr = g_task_get_task_data (task); + if (g_bytes_get_size (bytes) > 0) { + GCancellable *cancellable = g_task_get_cancellable (task); + g_debug ("add %u", (guint) g_bytes_get_size (bytes)); + g_byte_array_append (bufarr, + g_bytes_get_data (bytes, NULL), + g_bytes_get_size (bytes)); + g_input_stream_read_bytes_async (g_steal_pointer (&stream), + 256 * 1024, /* bigger chunk */ + G_PRIORITY_DEFAULT, + cancellable, + fwupd_input_stream_read_bytes_cb, + g_steal_pointer (&task)); + return; + } + + /* success */ +#if GLIB_CHECK_VERSION(2, 64, 0) + buf = g_byte_array_steal (bufarr, &bufsz); + g_task_return_pointer (task, + g_bytes_new_take (buf, bufsz), + (GDestroyNotify) g_bytes_unref); +#else + g_task_return_pointer (task, + g_bytes_new (bufarr->data, bufarr->len), + (GDestroyNotify) g_bytes_unref); +#endif +} + +/** + * fwupd_input_stream_read_bytes_async: (skip): + **/ +void +fwupd_input_stream_read_bytes_async (GInputStream *stream, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + g_autoptr(GTask) task = NULL; + + g_return_if_fail (G_IS_INPUT_STREAM (stream)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + task = g_task_new (stream, cancellable, callback, callback_data); + g_task_set_task_data (task, g_byte_array_new (), (GDestroyNotify) g_byte_array_unref); + g_input_stream_read_bytes_async (stream, + 64 * 1024, /* small */ + G_PRIORITY_DEFAULT, + cancellable, + fwupd_input_stream_read_bytes_cb, + g_steal_pointer (&task)); +} + +/** + * fwupd_input_stream_read_bytes_finish: (skip): + **/ +GBytes * +fwupd_input_stream_read_bytes_finish (GInputStream *stream, + GAsyncResult *res, + GError **error) +{ + g_return_val_if_fail (G_IS_INPUT_STREAM (stream), NULL); + g_return_val_if_fail (g_task_is_valid (res, stream), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return g_task_propagate_pointer (G_TASK(res), error); +} + #ifdef HAVE_GIO_UNIX /** * fwupd_unix_input_stream_from_bytes: (skip): @@ -948,6 +1046,7 @@ GUnixInputStream * fwupd_unix_input_stream_from_bytes (GBytes *bytes, GError **error) { +#ifdef HAVE_MEMFD_CREATE gint fd; gssize rc; @@ -975,6 +1074,13 @@ return NULL; } return G_UNIX_INPUT_STREAM (g_unix_input_stream_new (fd, TRUE)); +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "memfd_create() not available"); + return NULL; +#endif } /** diff -Nru fwupd-1.4.5/libfwupd/fwupd-common.h fwupd-1.5.8/libfwupd/fwupd-common.h --- fwupd-1.4.5/libfwupd/fwupd-common.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupd/fwupd-common.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2018 Richard Hughes + * Copyright (C) 2015 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/libfwupd/fwupd-common-private.h fwupd-1.5.8/libfwupd/fwupd-common-private.h --- fwupd-1.4.5/libfwupd/fwupd-common-private.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupd/fwupd-common-private.h 2021-03-31 20:08:32.000000000 +0000 @@ -6,7 +6,7 @@ #pragma once -#include +#include #ifdef HAVE_GIO_UNIX #include @@ -21,11 +21,22 @@ GHashTable *fwupd_variant_to_hash_kv (GVariant *dict); gchar *fwupd_build_user_agent_system (void); +void fwupd_input_stream_read_bytes_async (GInputStream *stream, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +GBytes *fwupd_input_stream_read_bytes_finish (GInputStream *stream, + GAsyncResult *res, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; + #ifdef HAVE_GIO_UNIX GUnixInputStream *fwupd_unix_input_stream_from_bytes (GBytes *bytes, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; GUnixInputStream *fwupd_unix_input_stream_from_fn (const gchar *fn, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; #endif G_END_DECLS diff -Nru fwupd-1.4.5/libfwupd/fwupd-context-test.c fwupd-1.5.8/libfwupd/fwupd-context-test.c --- fwupd-1.4.5/libfwupd/fwupd-context-test.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupd/fwupd-context-test.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2020 Philip Withnall + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include + +typedef struct { + GApplication *app; + FwupdClient *client; + GThread *main_thread; + GThread *worker_thread; +} FuThreadTestSelf; + +static gboolean +fwupd_thread_test_exit_idle_cb (gpointer user_data) +{ + FuThreadTestSelf *self = user_data; + g_application_release (self->app); + return G_SOURCE_REMOVE; +} + +static gpointer +fwupd_thread_test_thread_cb (gpointer user_data) +{ + FuThreadTestSelf *self = user_data; + g_autoptr(GError) error_local = NULL; + g_autoptr(GMainContext) context = g_main_context_new (); + g_autoptr(GMainContextPusher) pusher = g_main_context_pusher_new (context); + + g_assert (pusher != NULL); + g_message ("Calling fwupd_client_get_devices() in thread %p with main context %p", + g_thread_self (), g_main_context_get_thread_default ()); + if (!fwupd_client_connect (self->client, NULL, &error_local)) + g_warning ("%s", error_local->message); + g_idle_add (fwupd_thread_test_exit_idle_cb, self); + return NULL; +} + +static gboolean +fwupd_thread_test_idle_cb (gpointer user_data) +{ + FuThreadTestSelf *self = user_data; + g_message ("fwupd_thread_test_idle_cb() in thread %p with main context %p", + g_thread_self (), g_main_context_get_thread_default ()); + self->worker_thread = g_thread_new ("worker00", + fwupd_thread_test_thread_cb, + self); + return G_SOURCE_REMOVE; +} + +static void +fwupd_thread_test_activate_cb (GApplication *app, gpointer user_data) +{ + FuThreadTestSelf *self = user_data; + g_application_hold (self->app); + g_idle_add (fwupd_thread_test_idle_cb, self); +} + +static void +fwupd_thread_test_notify_cb (GObject *object, GParamSpec *pspec, gpointer user_data) +{ + FuThreadTestSelf *self = user_data; + g_message ("fwupd_thread_test_notify_cb() in thread %p with main context %p", + g_thread_self (), g_main_context_get_thread_default ()); + g_assert (g_thread_self () == self->main_thread); + g_assert (g_main_context_get_thread_default () == NULL); +} + +static gboolean +fwupd_thread_test_has_system_bus (void) +{ + g_autoptr(GDBusConnection) conn = NULL; + conn = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL); + return conn != NULL; +} + +int +main (void) +{ + gint retval; + g_autoptr(FwupdClient) client = fwupd_client_new (); + g_autoptr(GApplication) app = g_application_new ("org.fwupd.ContextTest", G_APPLICATION_FLAGS_NONE); + g_autoptr(GThread) worker_thread = NULL; + FuThreadTestSelf self = { + .app = app, + .client = client, + .worker_thread = worker_thread, + .main_thread = g_thread_self (), + }; + + /* only some of the CI targets have a DBus daemon */ + if (!fwupd_thread_test_has_system_bus ()) { + g_message ("D-Bus system bus unavailable, skipping tests."); + return 0; + } + g_message ("Created FwupdClient in thread %p with main context %p", + g_thread_self (), g_main_context_get_thread_default ()); + g_signal_connect (client, "notify::status", + G_CALLBACK (fwupd_thread_test_notify_cb), &self); + g_signal_connect (app, "activate", + G_CALLBACK (fwupd_thread_test_activate_cb), &self); + retval = g_application_run (app, 0, NULL); + if (self.worker_thread != NULL) + g_thread_join (g_steal_pointer (&self.worker_thread)); + + return retval; +} diff -Nru fwupd-1.4.5/libfwupd/fwupd-device.c fwupd-1.5.8/libfwupd/fwupd-device.c --- fwupd-1.4.5/libfwupd/fwupd-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupd/fwupd-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2017 Richard Hughes + * Copyright (C) 2015 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -34,14 +34,17 @@ guint64 modified; guint64 flags; GPtrArray *guids; + GPtrArray *vendor_ids; + GPtrArray *protocols; GPtrArray *instance_ids; GPtrArray *icons; gchar *name; gchar *serial; gchar *summary; + gchar *branch; gchar *description; gchar *vendor; - gchar *vendor_id; + gchar *vendor_id; /* for compat only */ gchar *homepage; gchar *plugin; gchar *protocol; @@ -62,7 +65,7 @@ gchar *update_image; FwupdStatus status; GPtrArray *releases; - FwupdDevice *parent; + FwupdDevice *parent; /* noref */ } FwupdDevicePrivate; enum { @@ -71,6 +74,8 @@ PROP_FLAGS, PROP_PROTOCOL, PROP_STATUS, + PROP_PARENT, + PROP_UPDATE_STATE, PROP_LAST }; @@ -168,11 +173,57 @@ { FwupdDevicePrivate *priv = GET_PRIVATE (device); g_return_if_fail (FWUPD_IS_DEVICE (device)); + + /* not changed */ + if (g_strcmp0 (priv->summary, summary) == 0) + return; + g_free (priv->summary); priv->summary = g_strdup (summary); } /** + * fwupd_device_get_branch: + * @device: A #FwupdDevice + * + * Gets the current device branch. + * + * Returns: the device branch, or %NULL if unset + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_device_get_branch (FwupdDevice *device) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + g_return_val_if_fail (FWUPD_IS_DEVICE (device), NULL); + return priv->branch; +} + +/** + * fwupd_device_set_branch: + * @device: A #FwupdDevice + * @branch: the device one line branch + * + * Sets the current device branch. + * + * Since: 1.5.0 + **/ +void +fwupd_device_set_branch (FwupdDevice *device, const gchar *branch) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + g_return_if_fail (FWUPD_IS_DEVICE (device)); + + /* not changed */ + if (g_strcmp0 (priv->branch, branch) == 0) + return; + + g_free (priv->branch); + priv->branch = g_strdup (branch); +} + +/** * fwupd_device_get_serial: * @device: A #FwupdDevice * @@ -204,6 +255,11 @@ { FwupdDevicePrivate *priv = GET_PRIVATE (device); g_return_if_fail (FWUPD_IS_DEVICE (device)); + + /* not changed */ + if (g_strcmp0 (priv->serial, serial) == 0) + return; + g_free (priv->serial); priv->serial = g_strdup (serial); } @@ -240,6 +296,11 @@ { FwupdDevicePrivate *priv = GET_PRIVATE (device); g_return_if_fail (FWUPD_IS_DEVICE (device)); + + /* not changed */ + if (g_strcmp0 (priv->id, id) == 0) + return; + g_free (priv->id); priv->id = g_strdup (id); } @@ -276,6 +337,11 @@ { FwupdDevicePrivate *priv = GET_PRIVATE (device); g_return_if_fail (FWUPD_IS_DEVICE (device)); + + /* not changed */ + if (g_strcmp0 (priv->parent_id, parent_id) == 0) + return; + g_free (priv->parent_id); priv->parent_id = g_strdup (parent_id); } @@ -311,10 +377,56 @@ fwupd_device_set_parent (FwupdDevice *device, FwupdDevice *parent) { FwupdDevicePrivate *priv = GET_PRIVATE (device); - FwupdDevicePrivate *priv_parent = GET_PRIVATE (parent); g_return_if_fail (FWUPD_IS_DEVICE (device)); - g_set_object (&priv->parent, parent); - g_ptr_array_add (priv_parent->children, g_object_ref (device)); + + if (priv->parent != NULL) + g_object_remove_weak_pointer (G_OBJECT (priv->parent), (gpointer *) &priv->parent); + if (parent != NULL) + g_object_add_weak_pointer (G_OBJECT (parent), (gpointer *) &priv->parent); + priv->parent = parent; + + /* this is what goes over D-Bus */ + fwupd_device_set_parent_id (device, parent != NULL ? fwupd_device_get_id (parent) : NULL); +} + +static void +fwupd_device_child_finalized_cb (gpointer data, GObject *where_the_object_was) +{ + FwupdDevice *device = FWUPD_DEVICE (data); + g_critical ("FuDevice child %p was finalized while still having parent %s [%s]!", + where_the_object_was, + fwupd_device_get_name (device), + fwupd_device_get_id (device)); +} + +/** + * fwupd_device_add_child: + * @device: A #FwupdDevice + * @child: Another #FwupdDevice + * + * Adds a child device. An child device is logically linked to the primary + * device in some way. + * + * NOTE: You should never call this function from user code, it is for daemon + * use only. Only use fwupd_device_set_parent() to set up a logical tree. + * + * Since: 1.5.1 + **/ +void +fwupd_device_add_child (FwupdDevice *device, FwupdDevice *child) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + + /* add if the child does not already exist */ + for (guint i = 0; i < priv->children->len; i++) { + FwupdDevice *devtmp = g_ptr_array_index (priv->children, i); + if (devtmp == child) + return; + } + g_object_weak_ref (G_OBJECT (child), + fwupd_device_child_finalized_cb, + device); + g_ptr_array_add (priv->children, g_object_ref (child)); } /** @@ -547,6 +659,11 @@ { FwupdDevicePrivate *priv = GET_PRIVATE (device); g_return_if_fail (FWUPD_IS_DEVICE (device)); + + /* not changed */ + if (g_strcmp0 (priv->name, name) == 0) + return; + g_free (priv->name); priv->name = g_strdup (name); } @@ -583,6 +700,11 @@ { FwupdDevicePrivate *priv = GET_PRIVATE (device); g_return_if_fail (FWUPD_IS_DEVICE (device)); + + /* not changed */ + if (g_strcmp0 (priv->vendor, vendor) == 0) + return; + g_free (priv->vendor); priv->vendor = g_strdup (vendor); } @@ -591,11 +713,13 @@ * fwupd_device_get_vendor_id: * @device: A #FwupdDevice * - * Gets the device vendor ID. + * Gets the combined device vendor ID. * - * Returns: the device vendor, e.g. 'USB:0x1234', or %NULL if unset + * Returns: the device vendor, e.g. 'USB:0x1234|PCI:0x5678', or %NULL if unset * * Since: 0.9.4 + * + * Deprecated: 1.5.5: Use fwupd_device_get_vendor_ids() instead. **/ const gchar * fwupd_device_get_vendor_id (FwupdDevice *device) @@ -608,19 +732,103 @@ /** * fwupd_device_set_vendor_id: * @device: A #FwupdDevice - * @vendor_id: the ID, e.g. 'USB:0x1234' + * @vendor_id: the ID, e.g. 'USB:0x1234' or 'USB:0x1234|PCI:0x5678' * * Sets the device vendor ID. * * Since: 0.9.4 + * + * Deprecated: 1.5.5: Use fwupd_device_add_vendor_id() instead. **/ void fwupd_device_set_vendor_id (FwupdDevice *device, const gchar *vendor_id) { + g_auto(GStrv) vendor_ids = NULL; + + g_return_if_fail (FWUPD_IS_DEVICE (device)); + g_return_if_fail (vendor_id != NULL); + + /* add all */ + vendor_ids = g_strsplit (vendor_id, "|", -1); + for (guint i = 0; vendor_ids[i] != NULL; i++) + fwupd_device_add_vendor_id (device, vendor_ids[i]); +} + +/** + * fwupd_device_get_vendor_ids: + * @device: A #FwupdDevice + * + * Gets the device vendor ID. + * + * Returns: (element-type utf8) (transfer none): the device vendor ID + * + * Since: 1.5.5 + **/ +GPtrArray * +fwupd_device_get_vendor_ids (FwupdDevice *device) +{ FwupdDevicePrivate *priv = GET_PRIVATE (device); + g_return_val_if_fail (FWUPD_IS_DEVICE (device), NULL); + return priv->vendor_ids; +} + +/** + * fwupd_device_has_vendor_id: + * @device: A #FwupdDevice + * @vendor_id: the ID, e.g. 'USB:0x1234' + * + * Finds out if the device has this specific vendor ID. + * + * Returns: %TRUE if the ID is found + * + * Since: 1.5.5 + **/ +gboolean +fwupd_device_has_vendor_id (FwupdDevice *device, const gchar *vendor_id) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + + g_return_val_if_fail (FWUPD_IS_DEVICE (device), FALSE); + g_return_val_if_fail (vendor_id != NULL, FALSE); + + for (guint i = 0; i < priv->vendor_ids->len; i++) { + const gchar *vendor_id_tmp = g_ptr_array_index (priv->vendor_ids, i); + if (g_strcmp0 (vendor_id, vendor_id_tmp) == 0) + return TRUE; + } + return FALSE; +} + +/** + * fwupd_device_add_vendor_id: + * @device: A #FwupdDevice + * @vendor_id: the ID, e.g. 'USB:0x1234' + * + * Adds a device vendor ID. + * + * Since: 1.5.5 + **/ +void +fwupd_device_add_vendor_id (FwupdDevice *device, const gchar *vendor_id) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + g_auto(GStrv) vendor_ids_tmp = NULL; + g_return_if_fail (FWUPD_IS_DEVICE (device)); + g_return_if_fail (vendor_id != NULL); + + if (fwupd_device_has_vendor_id (device, vendor_id)) + return; + g_ptr_array_add (priv->vendor_ids, g_strdup (vendor_id)); + + /* build for compatibility */ + vendor_ids_tmp = g_new0 (gchar *, priv->vendor_ids->len + 1); + for (guint i = 0; i < priv->vendor_ids->len; i++) { + const gchar *vendor_id_tmp = g_ptr_array_index (priv->vendor_ids, i); + vendor_ids_tmp[i] = g_strdup (vendor_id_tmp); + } g_free (priv->vendor_id); - priv->vendor_id = g_strdup (vendor_id); + priv->vendor_id = g_strjoinv ("|", vendor_ids_tmp); } /** @@ -655,6 +863,11 @@ { FwupdDevicePrivate *priv = GET_PRIVATE (device); g_return_if_fail (FWUPD_IS_DEVICE (device)); + + /* not changed */ + if (g_strcmp0 (priv->description, description) == 0) + return; + g_free (priv->description); priv->description = g_strdup (description); } @@ -691,6 +904,11 @@ { FwupdDevicePrivate *priv = GET_PRIVATE (device); g_return_if_fail (FWUPD_IS_DEVICE (device)); + + /* not changed */ + if (g_strcmp0 (priv->version, version) == 0) + return; + g_free (priv->version); priv->version = g_strdup (version); } @@ -727,6 +945,11 @@ { FwupdDevicePrivate *priv = GET_PRIVATE (device); g_return_if_fail (FWUPD_IS_DEVICE (device)); + + /* not changed */ + if (g_strcmp0 (priv->version_lowest, version_lowest) == 0) + return; + g_free (priv->version_lowest); priv->version_lowest = g_strdup (version_lowest); } @@ -798,6 +1021,11 @@ { FwupdDevicePrivate *priv = GET_PRIVATE (device); g_return_if_fail (FWUPD_IS_DEVICE (device)); + + /* not changed */ + if (g_strcmp0 (priv->version_bootloader, version_bootloader) == 0) + return; + g_free (priv->version_bootloader); priv->version_bootloader = g_strdup (version_bootloader); } @@ -939,6 +1167,11 @@ { FwupdDevicePrivate *priv = GET_PRIVATE (device); g_return_if_fail (FWUPD_IS_DEVICE (device)); + + /* not changed */ + if (g_strcmp0 (priv->plugin, plugin) == 0) + return; + g_free (priv->plugin); priv->plugin = g_strdup (plugin); } @@ -952,6 +1185,8 @@ * Returns: the protocol name, or %NULL if unset * * Since: 1.3.6 + * + * Deprecated: 1.5.8: Use fwupd_device_get_protocols() instead. **/ const gchar * fwupd_device_get_protocol (FwupdDevice *device) @@ -969,14 +1204,98 @@ * Sets the protocol that is used to update the device. * * Since: 1.3.6 + * + * Deprecated: 1.5.8: Use fwupd_device_add_protocol() instead. **/ void fwupd_device_set_protocol (FwupdDevice *device, const gchar *protocol) { + g_auto(GStrv) protocols = NULL; + + g_return_if_fail (FWUPD_IS_DEVICE (device)); + g_return_if_fail (protocol != NULL); + + /* add all */ + protocols = g_strsplit (protocol, "|", -1); + for (guint i = 0; protocols[i] != NULL; i++) + fwupd_device_add_protocol (device, protocols[i]); +} + +/** + * fwupd_device_get_protocols: + * @device: A #FwupdDevice + * + * Gets the device protocol. + * + * Returns: (element-type utf8) (transfer none): the device protocol + * + * Since: 1.5.8 + **/ +GPtrArray * +fwupd_device_get_protocols (FwupdDevice *device) +{ FwupdDevicePrivate *priv = GET_PRIVATE (device); + g_return_val_if_fail (FWUPD_IS_DEVICE (device), NULL); + return priv->protocols; +} + +/** + * fwupd_device_has_protocol: + * @device: A #FwupdDevice + * @protocol: the ID, e.g. 'USB:0x1234' + * + * Finds out if the device has this specific protocol. + * + * Returns: %TRUE if the ID is found + * + * Since: 1.5.8 + **/ +gboolean +fwupd_device_has_protocol (FwupdDevice *device, const gchar *protocol) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + + g_return_val_if_fail (FWUPD_IS_DEVICE (device), FALSE); + g_return_val_if_fail (protocol != NULL, FALSE); + + for (guint i = 0; i < priv->protocols->len; i++) { + const gchar *protocol_tmp = g_ptr_array_index (priv->protocols, i); + if (g_strcmp0 (protocol, protocol_tmp) == 0) + return TRUE; + } + return FALSE; +} + +/** + * fwupd_device_add_protocol: + * @device: A #FwupdDevice + * @protocol: the ID, e.g. 'USB:0x1234' + * + * Adds a device protocol. + * + * Since: 1.5.8 + **/ +void +fwupd_device_add_protocol (FwupdDevice *device, const gchar *protocol) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + g_auto(GStrv) protocols_tmp = NULL; + g_return_if_fail (FWUPD_IS_DEVICE (device)); + g_return_if_fail (protocol != NULL); + + if (fwupd_device_has_protocol (device, protocol)) + return; + g_ptr_array_add (priv->protocols, g_strdup (protocol)); + + /* build for compatibility */ + protocols_tmp = g_new0 (gchar *, priv->protocols->len + 1); + for (guint i = 0; i < priv->protocols->len; i++) { + const gchar *protocol_tmp = g_ptr_array_index (priv->protocols, i); + protocols_tmp[i] = g_strdup (protocol_tmp); + } g_free (priv->protocol); - priv->protocol = g_strdup (protocol); + priv->protocol = g_strjoinv ("|", protocols_tmp); } /** @@ -1033,7 +1352,7 @@ g_return_if_fail (FWUPD_IS_DEVICE (device)); if (flag == 0) return; - if ((priv->flags & flag) > 0) + if ((priv->flags | flag) == priv->flags) return; priv->flags |= flag; g_object_notify (G_OBJECT (device), "flags"); @@ -1098,7 +1417,6 @@ return priv->created; } - /** * fwupd_device_set_created: * @device: A #FwupdDevice @@ -1166,8 +1484,7 @@ FwupdDevicePrivate *priv = GET_PRIVATE (self); FwupdDevicePrivate *priv_donor = GET_PRIVATE (donor); - if (priv->flags == 0) - fwupd_device_add_flag (self, priv_donor->flags); + fwupd_device_add_flag (self, priv_donor->flags); if (priv->created == 0) fwupd_device_set_created (self, priv_donor->created); if (priv->modified == 0) @@ -1190,14 +1507,20 @@ fwupd_device_set_serial (self, priv_donor->serial); if (priv->summary == NULL) fwupd_device_set_summary (self, priv_donor->summary); + if (priv->branch == NULL) + fwupd_device_set_branch (self, priv_donor->branch); if (priv->vendor == NULL) fwupd_device_set_vendor (self, priv_donor->vendor); - if (priv->vendor_id == NULL) - fwupd_device_set_vendor_id (self, priv_donor->vendor_id); + for (guint i = 0; i < priv_donor->vendor_ids->len; i++) { + const gchar *tmp = g_ptr_array_index (priv_donor->vendor_ids, i); + fwupd_device_add_vendor_id (self, tmp); + } if (priv->plugin == NULL) fwupd_device_set_plugin (self, priv_donor->plugin); - if (priv->protocol == NULL) - fwupd_device_set_protocol (self, priv_donor->protocol); + for (guint i = 0; i < priv_donor->protocols->len; i++) { + const gchar *tmp = g_ptr_array_index (priv_donor->protocols, i); + fwupd_device_add_protocol (self, tmp); + } if (priv->update_error == NULL) fwupd_device_set_update_error (self, priv_donor->update_error); if (priv->update_message == NULL) @@ -1294,10 +1617,17 @@ FWUPD_RESULT_KEY_VENDOR, g_variant_new_string (priv->vendor)); } - if (priv->vendor_id != NULL) { + if (priv->vendor_ids->len > 0) { + g_autoptr(GString) str = g_string_new (NULL); + for (guint i = 0; i < priv->vendor_ids->len; i++) { + const gchar *tmp = g_ptr_array_index (priv->vendor_ids, i); + g_string_append_printf (str, "%s|", tmp); + } + if (str->len > 0) + g_string_truncate (str, str->len - 1); g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_VENDOR_ID, - g_variant_new_string (priv->vendor_id)); + g_variant_new_string (str->str)); } if (priv->flags > 0) { g_variant_builder_add (&builder, "{sv}", @@ -1325,6 +1655,11 @@ FWUPD_RESULT_KEY_SUMMARY, g_variant_new_string (priv->summary)); } + if (priv->branch != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_BRANCH, + g_variant_new_string (priv->branch)); + } if (priv->checksums->len > 0) { g_autoptr(GString) str = g_string_new (""); for (guint i = 0; i < priv->checksums->len; i++) { @@ -1342,10 +1677,17 @@ FWUPD_RESULT_KEY_PLUGIN, g_variant_new_string (priv->plugin)); } - if (priv->protocol != NULL) { + if (priv->protocols->len > 0) { + g_autoptr(GString) str = g_string_new (NULL); + for (guint i = 0; i < priv->protocols->len; i++) { + const gchar *tmp = g_ptr_array_index (priv->protocols, i); + g_string_append_printf (str, "%s|", tmp); + } + if (str->len > 0) + g_string_truncate (str, str->len - 1); g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_PROTOCOL, - g_variant_new_string (priv->protocol)); + g_variant_new_string (str->str)); } if (priv->version != NULL) { g_variant_builder_add (&builder, "{sv}", @@ -1526,7 +1868,10 @@ return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_VENDOR_ID) == 0) { - fwupd_device_set_vendor_id (device, g_variant_get_string (value, NULL)); + g_auto(GStrv) vendor_ids = NULL; + vendor_ids = g_strsplit (g_variant_get_string (value, NULL), "|", -1); + for (guint i = 0; vendor_ids[i] != NULL; i++) + fwupd_device_add_vendor_id (device, vendor_ids[i]); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_SERIAL) == 0) { @@ -1537,6 +1882,10 @@ fwupd_device_set_summary (device, g_variant_get_string (value, NULL)); return; } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_BRANCH) == 0) { + fwupd_device_set_branch (device, g_variant_get_string (value, NULL)); + return; + } if (g_strcmp0 (key, FWUPD_RESULT_KEY_DESCRIPTION) == 0) { fwupd_device_set_description (device, g_variant_get_string (value, NULL)); return; @@ -1555,7 +1904,10 @@ return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_PROTOCOL) == 0) { - fwupd_device_set_protocol (device, g_variant_get_string (value, NULL)); + g_auto(GStrv) protocols = NULL; + protocols = g_strsplit (g_variant_get_string (value, NULL), "|", -1); + for (guint i = 0; protocols[i] != NULL; i++) + fwupd_device_add_protocol (device, protocols[i]); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_VERSION) == 0) { @@ -1705,7 +2057,10 @@ { FwupdDevicePrivate *priv = GET_PRIVATE (device); g_return_if_fail (FWUPD_IS_DEVICE (device)); + if (priv->update_state == update_state) + return; priv->update_state = update_state; + g_object_notify (G_OBJECT (device), "update-state"); } /** @@ -1810,6 +2165,11 @@ { FwupdDevicePrivate *priv = GET_PRIVATE (device); g_return_if_fail (FWUPD_IS_DEVICE (device)); + + /* not changed */ + if (g_strcmp0 (priv->update_message, update_message) == 0) + return; + g_free (priv->update_message); priv->update_message = g_strdup (update_message); } @@ -1846,6 +2206,11 @@ { FwupdDevicePrivate *priv = GET_PRIVATE (device); g_return_if_fail (FWUPD_IS_DEVICE (device)); + + /* not changed */ + if (g_strcmp0 (priv->update_image, update_image) == 0) + return; + g_free (priv->update_image); priv->update_image = g_strdup (update_image); } @@ -1882,6 +2247,11 @@ { FwupdDevicePrivate *priv = GET_PRIVATE (device); g_return_if_fail (FWUPD_IS_DEVICE (device)); + + /* not changed */ + if (g_strcmp0 (priv->update_error, update_error) == 0) + return; + g_free (priv->update_error); priv->update_error = g_strdup (update_error); } @@ -2037,8 +2407,18 @@ fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_SERIAL, priv->serial); fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_SUMMARY, priv->summary); fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_DESCRIPTION, priv->description); + fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_BRANCH, priv->branch); fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_PLUGIN, priv->plugin); fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_PROTOCOL, priv->protocol); + if (priv->protocols->len > 1) { /* --> 0 when bumping API */ + json_builder_set_member_name (builder, "VendorIds"); + json_builder_begin_array (builder); + for (guint i = 0; i < priv->protocols->len; i++) { + const gchar *tmp = g_ptr_array_index (priv->protocols, i); + json_builder_add_string_value (builder, tmp); + } + json_builder_end_array (builder); + } if (priv->flags != FWUPD_DEVICE_FLAG_NONE) { json_builder_set_member_name (builder, FWUPD_RESULT_KEY_FLAGS); json_builder_begin_array (builder); @@ -2062,6 +2442,15 @@ } fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_VENDOR, priv->vendor); fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_VENDOR_ID, priv->vendor_id); + if (priv->vendor_ids->len > 1) { /* --> 0 when bumping API */ + json_builder_set_member_name (builder, "VendorIds"); + json_builder_begin_array (builder); + for (guint i = 0; i < priv->vendor_ids->len; i++) { + const gchar *tmp = g_ptr_array_index (priv->vendor_ids, i); + json_builder_add_string_value (builder, tmp); + } + json_builder_end_array (builder); + } fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_VERSION, priv->version); fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_VERSION_LOWEST, priv->version_lowest); fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_VERSION_BOOTLOADER, priv->version_bootloader); @@ -2173,8 +2562,12 @@ fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_SERIAL, priv->serial); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_SUMMARY, priv->summary); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_DESCRIPTION, priv->description); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_BRANCH, priv->branch); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_PLUGIN, priv->plugin); - fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_PROTOCOL, priv->protocol); + for (guint i = 0; i < priv->protocols->len; i++) { + const gchar *tmp = g_ptr_array_index (priv->protocols, i); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_PROTOCOL, tmp); + } fwupd_pad_kv_dfl (str, FWUPD_RESULT_KEY_FLAGS, priv->flags); for (guint i = 0; i < priv->checksums->len; i++) { const gchar *checksum = g_ptr_array_index (priv->checksums, i); @@ -2182,7 +2575,10 @@ fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_CHECKSUM, checksum_display); } fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_VENDOR, priv->vendor); - fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_VENDOR_ID, priv->vendor_id); + for (guint i = 0; i < priv->vendor_ids->len; i++) { + const gchar *tmp = g_ptr_array_index (priv->vendor_ids, i); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_VENDOR_ID, tmp); + } fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_VERSION, priv->version); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_VERSION_LOWEST, priv->version_lowest); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_VERSION_BOOTLOADER, priv->version_bootloader); @@ -2248,6 +2644,12 @@ case PROP_STATUS: g_value_set_uint (value, priv->status); break; + case PROP_PARENT: + g_value_set_object (value, priv->parent); + break; + case PROP_UPDATE_STATE: + g_value_set_uint (value, priv->update_state); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -2267,11 +2669,17 @@ fwupd_device_set_flags (self, g_value_get_uint64 (value)); break; case PROP_PROTOCOL: - fwupd_device_set_protocol (self, g_value_get_string (value)); + fwupd_device_add_protocol (self, g_value_get_string (value)); break; case PROP_STATUS: fwupd_device_set_status (self, g_value_get_uint (value)); break; + case PROP_PARENT: + fwupd_device_set_parent (self, g_value_get_object (value)); + break; + case PROP_UPDATE_STATE: + fwupd_device_set_update_state (self, g_value_get_uint (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -2316,6 +2724,21 @@ G_PARAM_READWRITE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_STATUS, pspec); + + pspec = g_param_spec_object ("parent", NULL, NULL, + FWUPD_TYPE_DEVICE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_PARENT, pspec); + + pspec = g_param_spec_uint ("update-state", NULL, NULL, + FWUPD_UPDATE_STATE_UNKNOWN, + FWUPD_UPDATE_STATE_LAST, + FWUPD_UPDATE_STATE_UNKNOWN, + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_UPDATE_STATE, pspec); } static void @@ -2326,6 +2749,8 @@ priv->instance_ids = g_ptr_array_new_with_free_func (g_free); priv->icons = g_ptr_array_new_with_free_func (g_free); priv->checksums = g_ptr_array_new_with_free_func (g_free); + priv->vendor_ids = g_ptr_array_new_with_free_func (g_free); + priv->protocols = g_ptr_array_new_with_free_func (g_free); priv->children = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); priv->releases = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); } @@ -2337,13 +2762,21 @@ FwupdDevicePrivate *priv = GET_PRIVATE (device); if (priv->parent != NULL) - g_object_unref (priv->parent); + g_object_remove_weak_pointer (G_OBJECT (priv->parent), (gpointer *) &priv->parent); + for (guint i = 0; i < priv->children->len; i++) { + FwupdDevice *child = g_ptr_array_index (priv->children, i); + g_object_weak_unref (G_OBJECT (child), + fwupd_device_child_finalized_cb, + device); + } + g_free (priv->description); g_free (priv->id); g_free (priv->parent_id); g_free (priv->name); g_free (priv->serial); g_free (priv->summary); + g_free (priv->branch); g_free (priv->vendor); g_free (priv->vendor_id); g_free (priv->plugin); @@ -2355,6 +2788,8 @@ g_free (priv->version_lowest); g_free (priv->version_bootloader); g_ptr_array_unref (priv->guids); + g_ptr_array_unref (priv->vendor_ids); + g_ptr_array_unref (priv->protocols); g_ptr_array_unref (priv->instance_ids); g_ptr_array_unref (priv->icons); g_ptr_array_unref (priv->checksums); diff -Nru fwupd-1.4.5/libfwupd/fwupd-device.h fwupd-1.5.8/libfwupd/fwupd-device.h --- fwupd-1.4.5/libfwupd/fwupd-device.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupd/fwupd-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2017 Richard Hughes + * Copyright (C) 2015 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -41,6 +41,8 @@ FwupdDevice *fwupd_device_get_parent (FwupdDevice *device); void fwupd_device_set_parent (FwupdDevice *device, FwupdDevice *parent); +void fwupd_device_add_child (FwupdDevice *device, + FwupdDevice *child); GPtrArray *fwupd_device_get_children (FwupdDevice *device); const gchar *fwupd_device_get_name (FwupdDevice *device); void fwupd_device_set_name (FwupdDevice *device, @@ -51,6 +53,9 @@ const gchar *fwupd_device_get_summary (FwupdDevice *device); void fwupd_device_set_summary (FwupdDevice *device, const gchar *summary); +const gchar *fwupd_device_get_branch (FwupdDevice *device); +void fwupd_device_set_branch (FwupdDevice *device, + const gchar *branch); const gchar *fwupd_device_get_description (FwupdDevice *device); void fwupd_device_set_description (FwupdDevice *device, const gchar *description); @@ -102,15 +107,29 @@ const gchar *fwupd_device_get_plugin (FwupdDevice *device); void fwupd_device_set_plugin (FwupdDevice *device, const gchar *plugin); +G_DEPRECATED_FOR(fwupd_device_get_protocols) const gchar *fwupd_device_get_protocol (FwupdDevice *device); +G_DEPRECATED_FOR(fwupd_device_add_protocol) void fwupd_device_set_protocol (FwupdDevice *device, const gchar *protocol); +void fwupd_device_add_protocol (FwupdDevice *device, + const gchar *protocol); +gboolean fwupd_device_has_protocol (FwupdDevice *device, + const gchar *protocol); +GPtrArray *fwupd_device_get_protocols (FwupdDevice *device); const gchar *fwupd_device_get_vendor (FwupdDevice *device); void fwupd_device_set_vendor (FwupdDevice *device, const gchar *vendor); +G_DEPRECATED_FOR(fwupd_device_get_vendor_ids) const gchar *fwupd_device_get_vendor_id (FwupdDevice *device); +G_DEPRECATED_FOR(fwupd_device_add_vendor_id) void fwupd_device_set_vendor_id (FwupdDevice *device, const gchar *vendor_id); +void fwupd_device_add_vendor_id (FwupdDevice *device, + const gchar *vendor_id); +gboolean fwupd_device_has_vendor_id (FwupdDevice *device, + const gchar *vendor_id); +GPtrArray *fwupd_device_get_vendor_ids (FwupdDevice *device); void fwupd_device_add_guid (FwupdDevice *device, const gchar *guid); gboolean fwupd_device_has_guid (FwupdDevice *device, diff -Nru fwupd-1.4.5/libfwupd/fwupd-enums.c fwupd-1.5.8/libfwupd/fwupd-enums.c --- fwupd-1.4.5/libfwupd/fwupd-enums.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupd/fwupd-enums.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2018 Richard Hughes + * Copyright (C) 2015 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -189,6 +189,8 @@ return "md-set-name-category"; if (device_flag == FWUPD_DEVICE_FLAG_MD_SET_VERFMT) return "md-set-verfmt"; + if (device_flag == FWUPD_DEVICE_FLAG_MD_SET_ICON) + return "md-set-icon"; if (device_flag == FWUPD_DEVICE_FLAG_ADD_COUNTERPART_GUIDS) return "add-counterpart-guids"; if (device_flag == FWUPD_DEVICE_FLAG_NO_GUID_MATCHING) @@ -197,6 +199,10 @@ return "updatable-hidden"; if (device_flag == FWUPD_DEVICE_FLAG_SKIPS_RESTART) return "skips-restart"; + if (device_flag == FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES) + return "has-multiple-branches"; + if (device_flag == FWUPD_DEVICE_FLAG_BACKUP_BEFORE_INSTALL) + return "backup-before-install"; if (device_flag == FWUPD_DEVICE_FLAG_UNKNOWN) return "unknown"; return NULL; @@ -287,6 +293,8 @@ return FWUPD_DEVICE_FLAG_MD_SET_NAME_CATEGORY; if (g_strcmp0 (device_flag, "md-set-verfmt") == 0) return FWUPD_DEVICE_FLAG_MD_SET_VERFMT; + if (g_strcmp0 (device_flag, "md-set-icon") == 0) + return FWUPD_DEVICE_FLAG_MD_SET_ICON; if (g_strcmp0 (device_flag, "add-counterpart-guids") == 0) return FWUPD_DEVICE_FLAG_ADD_COUNTERPART_GUIDS; if (g_strcmp0 (device_flag, "no-guid-matching") == 0) @@ -295,6 +303,92 @@ return FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN; if (g_strcmp0 (device_flag, "skips-restart") == 0) return FWUPD_DEVICE_FLAG_SKIPS_RESTART; + if (g_strcmp0 (device_flag, "has-multiple-branches") == 0) + return FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES; + if (g_strcmp0 (device_flag, "backup-before-install") == 0) + return FWUPD_DEVICE_FLAG_BACKUP_BEFORE_INSTALL; + return FWUPD_DEVICE_FLAG_UNKNOWN; +} + +/** + * fwupd_plugin_flag_to_string: + * @plugin_flag: A #FwupdPluginFlags, e.g. %FWUPD_DEVICE_FLAG_REQUIRE_AC + * + * Converts a #FwupdDeviceFlags to a string. + * + * Return value: identifier string + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_plugin_flag_to_string (FwupdPluginFlags plugin_flag) +{ + if (plugin_flag == FWUPD_DEVICE_FLAG_NONE) + return "none"; + if (plugin_flag == FWUPD_PLUGIN_FLAG_DISABLED) + return "disabled"; + if (plugin_flag == FWUPD_PLUGIN_FLAG_USER_WARNING) + return "user-warning"; + if (plugin_flag == FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE) + return "clear-updatable"; + if (plugin_flag == FWUPD_PLUGIN_FLAG_NO_HARDWARE) + return "no-hardware"; + if (plugin_flag == FWUPD_PLUGIN_FLAG_CAPSULES_UNSUPPORTED) + return "capsules-unsupported"; + if (plugin_flag == FWUPD_PLUGIN_FLAG_UNLOCK_REQUIRED) + return "unlock-required"; + if (plugin_flag == FWUPD_PLUGIN_FLAG_EFIVAR_NOT_MOUNTED) + return "efivar-not-mounted"; + if (plugin_flag == FWUPD_PLUGIN_FLAG_ESP_NOT_FOUND) + return "esp-not-found"; + if (plugin_flag == FWUPD_PLUGIN_FLAG_LEGACY_BIOS) + return "legacy-bios"; + if (plugin_flag == FWUPD_PLUGIN_FLAG_FAILED_OPEN) + return "failed-open"; + if (plugin_flag == FWUPD_PLUGIN_FLAG_REQUIRE_HWID) + return "require-hwid"; + if (plugin_flag == FWUPD_DEVICE_FLAG_UNKNOWN) + return "unknown"; + return NULL; +} + +/** + * fwupd_plugin_flag_from_string: + * @plugin_flag: A string, e.g. `require-ac` + * + * Converts a string to a #FwupdPluginFlags. + * + * Return value: enumerated value + * + * Since: 1.5.0 + **/ +FwupdPluginFlags +fwupd_plugin_flag_from_string (const gchar *plugin_flag) +{ + if (g_strcmp0 (plugin_flag, "none") == 0) + return FWUPD_DEVICE_FLAG_NONE; + if (g_strcmp0 (plugin_flag, "disabled") == 0) + return FWUPD_PLUGIN_FLAG_DISABLED; + if (g_strcmp0 (plugin_flag, "user-warning") == 0) + return FWUPD_PLUGIN_FLAG_USER_WARNING; + if (g_strcmp0 (plugin_flag, "clear-updatable") == 0) + return FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE; + if (g_strcmp0 (plugin_flag, "no-hardware") == 0) + return FWUPD_PLUGIN_FLAG_NO_HARDWARE; + if (g_strcmp0 (plugin_flag, "capsules-unsupported") == 0) + return FWUPD_PLUGIN_FLAG_CAPSULES_UNSUPPORTED; + if (g_strcmp0 (plugin_flag, "unlock-required") == 0) + return FWUPD_PLUGIN_FLAG_UNLOCK_REQUIRED; + if (g_strcmp0 (plugin_flag, "efivar-not-mounted") == 0) + return FWUPD_PLUGIN_FLAG_EFIVAR_NOT_MOUNTED; + if (g_strcmp0 (plugin_flag, "esp-not-found") == 0) + return FWUPD_PLUGIN_FLAG_ESP_NOT_FOUND; + if (g_strcmp0 (plugin_flag, "legacy-bios") == 0) + return FWUPD_PLUGIN_FLAG_LEGACY_BIOS; + if (g_strcmp0 (plugin_flag, "failed-open") == 0) + return FWUPD_PLUGIN_FLAG_FAILED_OPEN; + if (g_strcmp0 (plugin_flag, "require-hwid") == 0) + return FWUPD_PLUGIN_FLAG_REQUIRE_HWID; return FWUPD_DEVICE_FLAG_UNKNOWN; } @@ -419,6 +513,8 @@ return "detach-action"; if (feature_flag == FWUPD_FEATURE_FLAG_UPDATE_ACTION) return "update-action"; + if (feature_flag == FWUPD_FEATURE_FLAG_SWITCH_BRANCH) + return "switch-branch"; return NULL; } @@ -443,6 +539,8 @@ return FWUPD_FEATURE_FLAG_DETACH_ACTION; if (g_strcmp0 (feature_flag, "update-action") == 0) return FWUPD_FEATURE_FLAG_UPDATE_ACTION; + if (g_strcmp0 (feature_flag, "switch-branch") == 0) + return FWUPD_FEATURE_FLAG_SWITCH_BRANCH; return FWUPD_FEATURE_FLAG_LAST; } @@ -521,6 +619,8 @@ return "blocked-version"; if (release_flag == FWUPD_RELEASE_FLAG_BLOCKED_APPROVAL) return "blocked-approval"; + if (release_flag == FWUPD_RELEASE_FLAG_IS_ALTERNATE_BRANCH) + return "is-alternate-branch"; return NULL; } @@ -549,6 +649,8 @@ return FWUPD_RELEASE_FLAG_BLOCKED_VERSION; if (g_strcmp0 (release_flag, "blocked-approval") == 0) return FWUPD_RELEASE_FLAG_BLOCKED_APPROVAL; + if (g_strcmp0 (release_flag, "is-alternate-branch") == 0) + return FWUPD_RELEASE_FLAG_IS_ALTERNATE_BRANCH; return FWUPD_RELEASE_FLAG_NONE; } @@ -578,7 +680,7 @@ /** * fwupd_release_urgency_from_string: - * @release_urgency: A string, e.g. `trusted-payload` + * @release_urgency: A string, e.g. `low` * * Converts a string to an enumerated value. * diff -Nru fwupd-1.4.5/libfwupd/fwupd-enums.h fwupd-1.5.8/libfwupd/fwupd-enums.h --- fwupd-1.4.5/libfwupd/fwupd-enums.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupd/fwupd-enums.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2018 Richard Hughes + * Copyright (C) 2015 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -70,6 +70,7 @@ * @FWUPD_FEATURE_FLAG_CAN_REPORT: Can upload a report of the update back to the server * @FWUPD_FEATURE_FLAG_DETACH_ACTION: Can perform detach action, typically showing text * @FWUPD_FEATURE_FLAG_UPDATE_ACTION: Can perform update action, typically showing text + * @FWUPD_FEATURE_FLAG_SWITCH_BRANCH: Can switch the firmware branch * * The flags to the feature capabilities of the front-end client. **/ @@ -78,6 +79,7 @@ FWUPD_FEATURE_FLAG_CAN_REPORT = 1 << 0, /* Since: 1.4.5 */ FWUPD_FEATURE_FLAG_DETACH_ACTION = 1 << 1, /* Since: 1.4.5 */ FWUPD_FEATURE_FLAG_UPDATE_ACTION = 1 << 2, /* Since: 1.4.5 */ + FWUPD_FEATURE_FLAG_SWITCH_BRANCH = 1 << 3, /* Since: 1.5.0 */ /*< private >*/ FWUPD_FEATURE_FLAG_LAST } FwupdFeatureFlags; @@ -88,7 +90,7 @@ * @FWUPD_DEVICE_FLAG_INTERNAL: Device cannot be removed easily * @FWUPD_DEVICE_FLAG_UPDATABLE: Device is updatable in this or any other mode * @FWUPD_DEVICE_FLAG_ONLY_OFFLINE: Update can only be done from offline mode - * @FWUPD_DEVICE_FLAG_REQUIRE_AC: Requires AC power + * @FWUPD_DEVICE_FLAG_REQUIRE_AC: System requires external power source * @FWUPD_DEVICE_FLAG_LOCKED: Is locked and can be unlocked * @FWUPD_DEVICE_FLAG_SUPPORTED: Is found in current metadata * @FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER: Requires a bootloader mode to be manually enabled by the user @@ -104,11 +106,11 @@ * @FWUPD_DEVICE_FLAG_TRUSTED: Extra metadata can be exposed about this device * @FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN: Requires system shutdown to apply firmware * @FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED: Requires the update to be retried with a new plugin - * @FWUPD_DEVICE_FLAG_NO_AUTO_INSTANCE_IDS: Do not add instance IDs from the device baseclass + * @FWUPD_DEVICE_FLAG_NO_AUTO_INSTANCE_IDS: Deprecated, no not use * @FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION: Device update needs to be separately activated * @FWUPD_DEVICE_FLAG_HISTORICAL Device is for historical data only - * @FWUPD_DEVICE_FLAG_ENSURE_SEMVER: Ensure the version is a valid semantic version, e.g. numbers separated with dots - * @FWUPD_DEVICE_FLAG_ONLY_SUPPORTED: Only devices supported in the metadata will be opened + * @FWUPD_DEVICE_FLAG_ENSURE_SEMVER: Deprecated, no not use + * @FWUPD_DEVICE_FLAG_ONLY_SUPPORTED: Deprecated, no not use * @FWUPD_DEVICE_FLAG_WILL_DISAPPEAR: Device will disappear after update and can't be verified * @FWUPD_DEVICE_FLAG_CAN_VERIFY: Device checksums can be compared against metadata * @FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE: Image can be dumped from device for verification @@ -117,13 +119,16 @@ * @FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE: Device remains usable while fwupd flashes or schedules the update * @FWUPD_DEVICE_FLAG_VERSION_CHECK_REQUIRED: All firmware updates for this device require a firmware version check * @FWUPD_DEVICE_FLAG_INSTALL_ALL_RELEASES: Install each intermediate release rather than jumping direct to newest - * @FWUPD_DEVICE_FLAG_MD_SET_NAME: Set the device name from the metadata if available - * @FWUPD_DEVICE_FLAG_MD_SET_NAME_CATEGORY: Set the device name from the metadata if available - * @FWUPD_DEVICE_FLAG_MD_SET_VERFMT: Set the device version format from the metadata if available + * @FWUPD_DEVICE_FLAG_MD_SET_NAME: Deprecated, no not use + * @FWUPD_DEVICE_FLAG_MD_SET_NAME_CATEGORY: Deprecated, no not use + * @FWUPD_DEVICE_FLAG_MD_SET_VERFMT: Deprecated, no not use * @FWUPD_DEVICE_FLAG_ADD_COUNTERPART_GUIDS: Add counterpart GUIDs from an alternate mode like bootloader - * @FWUPD_DEVICE_FLAG_NO_GUID_MATCHING: Force an explicit ID match when adding devices to the device list + * @FWUPD_DEVICE_FLAG_NO_GUID_MATCHING: Deprecated, no not use * @FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN: Device is updatable but should not be called by the client * @FWUPD_DEVICE_FLAG_SKIPS_RESTART: Device relies upon activation or power cycle to load firmware + * @FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES: Device supports switching to a different stream of firmware + * @FWUPD_DEVICE_FLAG_BACKUP_BEFORE_INSTALL: Device firmware should be saved before installing firmware + * @FWUPD_DEVICE_FLAG_MD_SET_ICON: Deprecated, no not use * * The device flags. **/ @@ -147,11 +152,11 @@ #define FWUPD_DEVICE_FLAG_TRUSTED (1u << 16) /* Since: 1.1.2 */ #define FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN (1u << 17) /* Since: 1.2.4 */ #define FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED (1u << 18) /* Since: 1.2.5 */ -#define FWUPD_DEVICE_FLAG_NO_AUTO_INSTANCE_IDS (1u << 19) /* Since: 1.2.5 */ +#define FWUPD_DEVICE_FLAG_NO_AUTO_INSTANCE_IDS (1u << 19) /* Since: 1.2.5; Deprecated: 1.5.5 */ #define FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION (1u << 20) /* Since: 1.2.6 */ -#define FWUPD_DEVICE_FLAG_ENSURE_SEMVER (1u << 21) /* Since: 1.2.9 */ +#define FWUPD_DEVICE_FLAG_ENSURE_SEMVER (1u << 21) /* Since: 1.2.9; Deprecated: 1.5.5 */ #define FWUPD_DEVICE_FLAG_HISTORICAL (1u << 22) /* Since: 1.3.2 */ -#define FWUPD_DEVICE_FLAG_ONLY_SUPPORTED (1u << 23) /* Since: 1.3.3 */ +#define FWUPD_DEVICE_FLAG_ONLY_SUPPORTED (1u << 23) /* Since: 1.3.3; Deprecated: 1.5.5 */ #define FWUPD_DEVICE_FLAG_WILL_DISAPPEAR (1u << 24) /* Since: 1.3.3 */ #define FWUPD_DEVICE_FLAG_CAN_VERIFY (1u << 25) /* Since: 1.3.3 */ #define FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE (1u << 26) /* Since: 1.3.3 */ @@ -160,13 +165,16 @@ #define FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE (1u << 29) /* Since: 1.3.3 */ #define FWUPD_DEVICE_FLAG_VERSION_CHECK_REQUIRED (1u << 30) /* Since: 1.3.7 */ #define FWUPD_DEVICE_FLAG_INSTALL_ALL_RELEASES (1u << 31) /* Since: 1.3.7 */ -#define FWUPD_DEVICE_FLAG_MD_SET_NAME (1llu << 32) /* Since: 1.4.0 */ -#define FWUPD_DEVICE_FLAG_MD_SET_NAME_CATEGORY (1llu << 33) /* Since: 1.4.0 */ -#define FWUPD_DEVICE_FLAG_MD_SET_VERFMT (1llu << 34) /* Since: 1.4.0 */ +#define FWUPD_DEVICE_FLAG_MD_SET_NAME (1llu << 32) /* Since: 1.4.0; Deprecated: 1.5.5 */ +#define FWUPD_DEVICE_FLAG_MD_SET_NAME_CATEGORY (1llu << 33) /* Since: 1.4.0; Deprecated: 1.5.5 */ +#define FWUPD_DEVICE_FLAG_MD_SET_VERFMT (1llu << 34) /* Since: 1.4.0; Deprecated: 1.5.5 */ #define FWUPD_DEVICE_FLAG_ADD_COUNTERPART_GUIDS (1llu << 35) /* Since: 1.4.0 */ -#define FWUPD_DEVICE_FLAG_NO_GUID_MATCHING (1llu << 36) /* Since: 1.4.1 */ +#define FWUPD_DEVICE_FLAG_NO_GUID_MATCHING (1llu << 36) /* Since: 1.4.1; Deprecated: 1.5.8 */ #define FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN (1llu << 37) /* Since: 1.4.1 */ -#define FWUPD_DEVICE_FLAG_SKIPS_RESTART (1llu << 38) /* Since: 1.4.5 */ +#define FWUPD_DEVICE_FLAG_SKIPS_RESTART (1llu << 38) /* Since: 1.5.0 */ +#define FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES (1llu << 39) /* Since: 1.5.0 */ +#define FWUPD_DEVICE_FLAG_BACKUP_BEFORE_INSTALL (1llu << 40) /* Since: 1.5.0 */ +#define FWUPD_DEVICE_FLAG_MD_SET_ICON (1llu << 41) /* Since: 1.5.2; Deprecated: 1.5.5 */ #define FWUPD_DEVICE_FLAG_UNKNOWN G_MAXUINT64 /* Since: 0.7.3 */ typedef guint64 FwupdDeviceFlags; @@ -179,6 +187,7 @@ * @FWUPD_RELEASE_FLAG_IS_DOWNGRADE: Is older than the device version * @FWUPD_RELEASE_FLAG_BLOCKED_VERSION: Blocked as below device version-lowest * @FWUPD_RELEASE_FLAG_BLOCKED_APPROVAL: Blocked as release not approved + * @FWUPD_RELEASE_FLAG_IS_ALTERNATE_BRANCH: Is an alternate branch of firmware * * The release flags. **/ @@ -189,6 +198,7 @@ #define FWUPD_RELEASE_FLAG_IS_DOWNGRADE (1u << 3) /* Since: 1.2.6 */ #define FWUPD_RELEASE_FLAG_BLOCKED_VERSION (1u << 4) /* Since: 1.2.6 */ #define FWUPD_RELEASE_FLAG_BLOCKED_APPROVAL (1u << 5) /* Since: 1.2.6 */ +#define FWUPD_RELEASE_FLAG_IS_ALTERNATE_BRANCH (1u << 6) /* Since: 1.5.0 */ #define FWUPD_RELEASE_FLAG_UNKNOWN G_MAXUINT64 /* Since: 1.2.6 */ typedef guint64 FwupdReleaseFlags; @@ -213,6 +223,38 @@ } FwupdReleaseUrgency; /** + * FwupdPluginFlags: + * @FWUPD_PLUGIN_FLAG_NONE: No flags set + * @FWUPD_PLUGIN_FLAG_DISABLED: Disabled + * @FWUPD_PLUGIN_FLAG_USER_WARNING: Show the user a warning + * @FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE: Clear the UPDATABLE flag from devices + * @FWUPD_PLUGIN_FLAG_NO_HARDWARE: No hardware is found + * @FWUPD_PLUGIN_FLAG_CAPSULES_UNSUPPORTED: UEFI UpdateCapsule are unsupported + * @FWUPD_PLUGIN_FLAG_UNLOCK_REQUIRED: Hardware unlock is required + * @FWUPD_PLUGIN_FLAG_EFIVAR_NOT_MOUNTED: The efivar filesystem is not found + * @FWUPD_PLUGIN_FLAG_ESP_NOT_FOUND: The EFI ESP not found + * @FWUPD_PLUGIN_FLAG_LEGACY_BIOS: System running in legacy CSM mode + * @FWUPD_PLUGIN_FLAG_FAILED_OPEN: Failed to open plugin (missing dependency) + * @FWUPD_PLUGIN_FLAG_REQUIRE_HWID: A specific HWID is required + * + * The plugin flags. + **/ +#define FWUPD_PLUGIN_FLAG_NONE (0u) /* Since: 1.5.0 */ +#define FWUPD_PLUGIN_FLAG_DISABLED (1u << 0) /* Since: 1.5.0 */ +#define FWUPD_PLUGIN_FLAG_USER_WARNING (1u << 1) /* Since: 1.5.0 */ +#define FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE (1u << 2) /* Since: 1.5.0 */ +#define FWUPD_PLUGIN_FLAG_NO_HARDWARE (1u << 3) /* Since: 1.5.0 */ +#define FWUPD_PLUGIN_FLAG_CAPSULES_UNSUPPORTED (1u << 4) /* Since: 1.5.0 */ +#define FWUPD_PLUGIN_FLAG_UNLOCK_REQUIRED (1u << 5) /* Since: 1.5.0 */ +#define FWUPD_PLUGIN_FLAG_EFIVAR_NOT_MOUNTED (1u << 6) /* Since: 1.5.0 */ +#define FWUPD_PLUGIN_FLAG_ESP_NOT_FOUND (1u << 7) /* Since: 1.5.0 */ +#define FWUPD_PLUGIN_FLAG_LEGACY_BIOS (1u << 8) /* Since: 1.5.0 */ +#define FWUPD_PLUGIN_FLAG_FAILED_OPEN (1u << 9) /* Since: 1.5.0 */ +#define FWUPD_PLUGIN_FLAG_REQUIRE_HWID (1u << 10) /* Since: 1.5.8 */ +#define FWUPD_PLUGIN_FLAG_UNKNOWN G_MAXUINT64 /* Since: 1.5.0 */ +typedef guint64 FwupdPluginFlags; + +/** * FwupdInstallFlags: * @FWUPD_INSTALL_FLAG_NONE: No flags set * @FWUPD_INSTALL_FLAG_OFFLINE: Schedule this for next boot @@ -220,8 +262,13 @@ * @FWUPD_INSTALL_FLAG_ALLOW_OLDER: Allow downgrading firmware * @FWUPD_INSTALL_FLAG_FORCE: Force the update even if not a good idea * @FWUPD_INSTALL_FLAG_NO_HISTORY: Do not write to the history database + * @FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH: Allow firmware branch switching + * @FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM: Ignore firmware CRCs and checksums + * @FWUPD_INSTALL_FLAG_IGNORE_VID_PID: Ignore firmware vendor and project checks + * @FWUPD_INSTALL_FLAG_IGNORE_POWER: Ignore requirement of external power source + * @FWUPD_INSTALL_FLAG_NO_SEARCH: Do not use heuristics when parsing the image * - * Flags to set when performing the firwmare update or install. + * Flags to set when performing the firmware update or install. **/ typedef enum { FWUPD_INSTALL_FLAG_NONE = 0, /* Since: 0.7.0 */ @@ -230,6 +277,11 @@ FWUPD_INSTALL_FLAG_ALLOW_OLDER = 1 << 2, /* Since: 0.7.0 */ FWUPD_INSTALL_FLAG_FORCE = 1 << 3, /* Since: 0.7.1 */ FWUPD_INSTALL_FLAG_NO_HISTORY = 1 << 4, /* Since: 1.0.8 */ + FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH = 1 << 5, /* Since: 1.5.0 */ + FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM = 1 << 6, /* Since: 1.5.0 */ + FWUPD_INSTALL_FLAG_IGNORE_VID_PID = 1 << 7, /* Since: 1.5.0 */ + FWUPD_INSTALL_FLAG_IGNORE_POWER = 1 << 8, /* Since: 1.5.0 */ + FWUPD_INSTALL_FLAG_NO_SEARCH = 1 << 9, /* Since: 1.5.0 */ /*< private >*/ FWUPD_INSTALL_FLAG_LAST } FwupdInstallFlags; @@ -240,7 +292,7 @@ * @FWUPD_SELF_SIGN_FLAG_ADD_TIMESTAMP: Add the timestamp to the detached signature * @FWUPD_SELF_SIGN_FLAG_ADD_CERT: Add the certificate to the detached signature * - * Flags to set when performing the firwmare update or install. + * Flags to set when performing the firmware update or install. **/ typedef enum { FWUPD_SELF_SIGN_FLAG_NONE = 0, /* Since: 1.2.6 */ @@ -335,6 +387,8 @@ FwupdStatus fwupd_status_from_string (const gchar *status); const gchar *fwupd_device_flag_to_string (FwupdDeviceFlags device_flag); FwupdDeviceFlags fwupd_device_flag_from_string (const gchar *device_flag); +const gchar *fwupd_plugin_flag_to_string (FwupdPluginFlags plugin_flag); +FwupdPluginFlags fwupd_plugin_flag_from_string (const gchar *plugin_flag); const gchar *fwupd_release_flag_to_string (FwupdReleaseFlags release_flag); FwupdReleaseFlags fwupd_release_flag_from_string (const gchar *release_flag); const gchar *fwupd_release_urgency_to_string (FwupdReleaseUrgency release_urgency); diff -Nru fwupd-1.4.5/libfwupd/fwupd-enums-private.h fwupd-1.5.8/libfwupd/fwupd-enums-private.h --- fwupd-1.4.5/libfwupd/fwupd-enums-private.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupd/fwupd-enums-private.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,11 +1,13 @@ /* - * Copyright (C) 2016-2018 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ #pragma once +#include + G_BEGIN_DECLS #define FWUPD_RESULT_KEY_APPSTREAM_ID "AppstreamId" /* s */ @@ -23,6 +25,8 @@ #define FWUPD_RESULT_KEY_FLAGS "Flags" /* t */ #define FWUPD_RESULT_KEY_FLASHES_LEFT "FlashesLeft" /* u */ #define FWUPD_RESULT_KEY_URGENCY "Urgency" /* u */ +#define FWUPD_RESULT_KEY_HSI_LEVEL "HsiLevel" /* u */ +#define FWUPD_RESULT_KEY_HSI_RESULT "HsiResult" /* u */ #define FWUPD_RESULT_KEY_INSTALL_DURATION "InstallDuration" /* u */ #define FWUPD_RESULT_KEY_GUID "Guid" /* as */ #define FWUPD_RESULT_KEY_INSTANCE_IDS "InstanceIds" /* as */ @@ -43,12 +47,14 @@ #define FWUPD_RESULT_KEY_SIZE "Size" /* t */ #define FWUPD_RESULT_KEY_STATUS "Status" /* u */ #define FWUPD_RESULT_KEY_SUMMARY "Summary" /* s */ +#define FWUPD_RESULT_KEY_BRANCH "Branch" /* s */ #define FWUPD_RESULT_KEY_TRUST_FLAGS "TrustFlags" /* t */ #define FWUPD_RESULT_KEY_UPDATE_MESSAGE "UpdateMessage" /* s */ #define FWUPD_RESULT_KEY_UPDATE_IMAGE "UpdateImage" /* s */ #define FWUPD_RESULT_KEY_UPDATE_ERROR "UpdateError" /* s */ #define FWUPD_RESULT_KEY_UPDATE_STATE "UpdateState" /* u */ #define FWUPD_RESULT_KEY_URI "Uri" /* s */ +#define FWUPD_RESULT_KEY_LOCATIONS "Locations" /* as */ #define FWUPD_RESULT_KEY_VENDOR_ID "VendorId" /* s */ #define FWUPD_RESULT_KEY_VENDOR "Vendor" /* s */ #define FWUPD_RESULT_KEY_VENDOR "Vendor" /* s */ diff -Nru fwupd-1.4.5/libfwupd/fwupd.h fwupd-1.5.8/libfwupd/fwupd.h --- fwupd-1.4.5/libfwupd/fwupd.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupd/fwupd.h 2021-03-31 20:08:32.000000000 +0000 @@ -14,10 +14,13 @@ #define __FWUPD_H_INSIDE__ #include +#include #include #include +#include #include #include +#include #include #include #include diff -Nru fwupd-1.4.5/libfwupd/fwupd.map fwupd-1.5.8/libfwupd/fwupd.map --- fwupd-1.4.5/libfwupd/fwupd.map 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupd/fwupd.map 2021-03-31 20:08:32.000000000 +0000 @@ -468,3 +468,191 @@ fwupd_remote_load_signature_bytes; local: *; } LIBFWUPD_1.4.1; + +LIBFWUPD_1.4.6 { + global: + fwupd_client_get_blocked_firmware; + fwupd_client_set_blocked_firmware; + local: *; +} LIBFWUPD_1.4.5; + +LIBFWUPD_1.5.0 { + global: + fwupd_client_activate_async; + fwupd_client_activate_finish; + fwupd_client_clear_results_async; + fwupd_client_clear_results_finish; + fwupd_client_connect_async; + fwupd_client_connect_finish; + fwupd_client_download_bytes_async; + fwupd_client_download_bytes_finish; + fwupd_client_get_approved_firmware_async; + fwupd_client_get_approved_firmware_finish; + fwupd_client_get_blocked_firmware_async; + fwupd_client_get_blocked_firmware_finish; + fwupd_client_get_details_bytes; + fwupd_client_get_details_bytes_async; + fwupd_client_get_details_bytes_finish; + fwupd_client_get_device_by_id_async; + fwupd_client_get_device_by_id_finish; + fwupd_client_get_devices_async; + fwupd_client_get_devices_by_guid_async; + fwupd_client_get_devices_by_guid_finish; + fwupd_client_get_devices_finish; + fwupd_client_get_downgrades_async; + fwupd_client_get_downgrades_finish; + fwupd_client_get_history_async; + fwupd_client_get_history_finish; + fwupd_client_get_host_security_attrs; + fwupd_client_get_host_security_attrs_async; + fwupd_client_get_host_security_attrs_finish; + fwupd_client_get_host_security_id; + fwupd_client_get_plugins; + fwupd_client_get_plugins_async; + fwupd_client_get_plugins_finish; + fwupd_client_get_releases_async; + fwupd_client_get_releases_finish; + fwupd_client_get_remote_by_id_async; + fwupd_client_get_remote_by_id_finish; + fwupd_client_get_remotes_async; + fwupd_client_get_remotes_finish; + fwupd_client_get_report_metadata; + fwupd_client_get_report_metadata_async; + fwupd_client_get_report_metadata_finish; + fwupd_client_get_results_async; + fwupd_client_get_results_finish; + fwupd_client_get_upgrades_async; + fwupd_client_get_upgrades_finish; + fwupd_client_install_async; + fwupd_client_install_bytes_async; + fwupd_client_install_bytes_finish; + fwupd_client_install_finish; + fwupd_client_install_release_async; + fwupd_client_install_release_finish; + fwupd_client_modify_config_async; + fwupd_client_modify_config_finish; + fwupd_client_modify_device_async; + fwupd_client_modify_device_finish; + fwupd_client_modify_remote_async; + fwupd_client_modify_remote_finish; + fwupd_client_refresh_remote_async; + fwupd_client_refresh_remote_finish; + fwupd_client_self_sign_async; + fwupd_client_self_sign_finish; + fwupd_client_set_approved_firmware_async; + fwupd_client_set_approved_firmware_finish; + fwupd_client_set_blocked_firmware_async; + fwupd_client_set_blocked_firmware_finish; + fwupd_client_set_feature_flags_async; + fwupd_client_set_feature_flags_finish; + fwupd_client_unlock_async; + fwupd_client_unlock_finish; + fwupd_client_update_metadata_bytes_async; + fwupd_client_update_metadata_bytes_finish; + fwupd_client_upload_bytes_async; + fwupd_client_upload_bytes_finish; + fwupd_client_verify_async; + fwupd_client_verify_finish; + fwupd_client_verify_update_async; + fwupd_client_verify_update_finish; + fwupd_device_get_branch; + fwupd_device_set_branch; + fwupd_plugin_add_flag; + fwupd_plugin_array_from_variant; + fwupd_plugin_flag_from_string; + fwupd_plugin_flag_to_string; + fwupd_plugin_from_variant; + fwupd_plugin_get_flags; + fwupd_plugin_get_name; + fwupd_plugin_get_type; + fwupd_plugin_has_flag; + fwupd_plugin_new; + fwupd_plugin_remove_flag; + fwupd_plugin_set_flags; + fwupd_plugin_set_name; + fwupd_plugin_to_json; + fwupd_plugin_to_string; + fwupd_plugin_to_variant; + fwupd_release_get_branch; + fwupd_release_set_branch; + fwupd_remote_get_automatic_security_reports; + fwupd_remote_get_security_report_uri; + fwupd_security_attr_add_flag; + fwupd_security_attr_add_metadata; + fwupd_security_attr_add_obsolete; + fwupd_security_attr_array_from_variant; + fwupd_security_attr_flag_to_string; + fwupd_security_attr_flag_to_suffix; + fwupd_security_attr_from_variant; + fwupd_security_attr_get_appstream_id; + fwupd_security_attr_get_flags; + fwupd_security_attr_get_level; + fwupd_security_attr_get_metadata; + fwupd_security_attr_get_name; + fwupd_security_attr_get_obsoletes; + fwupd_security_attr_get_plugin; + fwupd_security_attr_get_result; + fwupd_security_attr_get_type; + fwupd_security_attr_get_url; + fwupd_security_attr_has_flag; + fwupd_security_attr_has_obsolete; + fwupd_security_attr_new; + fwupd_security_attr_result_to_string; + fwupd_security_attr_set_appstream_id; + fwupd_security_attr_set_flags; + fwupd_security_attr_set_level; + fwupd_security_attr_set_name; + fwupd_security_attr_set_plugin; + fwupd_security_attr_set_result; + fwupd_security_attr_set_url; + fwupd_security_attr_to_json; + fwupd_security_attr_to_string; + fwupd_security_attr_to_variant; + local: *; +} LIBFWUPD_1.4.6; + +LIBFWUPD_1.5.1 { + global: + fwupd_device_add_child; + local: *; +} LIBFWUPD_1.5.0; + +LIBFWUPD_1.5.2 { + global: + fwupd_client_download_file; + fwupd_client_get_user_agent; + local: *; +} LIBFWUPD_1.5.1; + +LIBFWUPD_1.5.3 { + global: + fwupd_client_get_main_context; + fwupd_client_set_main_context; + fwupd_remote_set_keyring_kind; + local: *; +} LIBFWUPD_1.5.2; + +LIBFWUPD_1.5.5 { + global: + fwupd_device_add_vendor_id; + fwupd_device_get_vendor_ids; + fwupd_device_has_vendor_id; + local: *; +} LIBFWUPD_1.5.3; + +LIBFWUPD_1.5.6 { + global: + fwupd_client_install_release2; + fwupd_client_install_release2_async; + fwupd_release_add_location; + fwupd_release_get_locations; + local: *; +} LIBFWUPD_1.5.5; + +LIBFWUPD_1.5.8 { + global: + fwupd_device_add_protocol; + fwupd_device_get_protocols; + fwupd_device_has_protocol; + local: *; +} LIBFWUPD_1.5.6; diff -Nru fwupd-1.4.5/libfwupd/fwupd-plugin.c fwupd-1.5.8/libfwupd/fwupd-plugin.c --- fwupd-1.4.5/libfwupd/fwupd-plugin.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupd/fwupd-plugin.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,491 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fwupd-enums-private.h" +#include "fwupd-plugin-private.h" + +/** + * SECTION:fwupd-plugin + * @short_description: a hardware plugin + * + * An object that represents a fwupd plugin. + * + * See also: #FwupdRelease + */ + +static void fwupd_plugin_finalize (GObject *object); + +typedef struct { + gchar *name; + guint64 flags; +} FwupdPluginPrivate; + +enum { + PROP_0, + PROP_NAME, + PROP_FLAGS, + PROP_LAST +}; + +G_DEFINE_TYPE_WITH_PRIVATE (FwupdPlugin, fwupd_plugin, G_TYPE_OBJECT) +#define GET_PRIVATE(o) (fwupd_plugin_get_instance_private (o)) + +/** + * fwupd_plugin_get_name: + * @plugin: A #FwupdPlugin + * + * Gets the plugin name. + * + * Returns: the plugin name, or %NULL if unset + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_plugin_get_name (FwupdPlugin *plugin) +{ + FwupdPluginPrivate *priv = GET_PRIVATE (plugin); + g_return_val_if_fail (FWUPD_IS_PLUGIN (plugin), NULL); + return priv->name; +} + +/** + * fwupd_plugin_set_name: + * @plugin: A #FwupdPlugin + * @name: the plugin name, e.g. `bios` + * + * Sets the plugin name. + * + * Since: 1.5.0 + **/ +void +fwupd_plugin_set_name (FwupdPlugin *plugin, const gchar *name) +{ + FwupdPluginPrivate *priv = GET_PRIVATE (plugin); + g_return_if_fail (FWUPD_IS_PLUGIN (plugin)); + g_return_if_fail (name != NULL); + + /* not changed */ + if (g_strcmp0 (priv->name, name) == 0) + return; + + g_free (priv->name); + priv->name = g_strdup (name); + g_object_notify (G_OBJECT (plugin), "name"); +} + +/** + * fwupd_plugin_get_flags: + * @plugin: A #FwupdPlugin + * + * Gets the plugin flags. + * + * Returns: the plugin flags, or 0 if unset + * + * Since: 1.5.0 + **/ +guint64 +fwupd_plugin_get_flags (FwupdPlugin *plugin) +{ + FwupdPluginPrivate *priv = GET_PRIVATE (plugin); + g_return_val_if_fail (FWUPD_IS_PLUGIN (plugin), 0); + return priv->flags; +} + +/** + * fwupd_plugin_set_flags: + * @plugin: A #FwupdPlugin + * @flags: the plugin flags, e.g. %FWUPD_PLUGIN_FLAG_CAPSULES_UNSUPPORTED + * + * Sets the plugin flags. + * + * Since: 1.5.0 + **/ +void +fwupd_plugin_set_flags (FwupdPlugin *plugin, guint64 flags) +{ + FwupdPluginPrivate *priv = GET_PRIVATE (plugin); + g_return_if_fail (FWUPD_IS_PLUGIN (plugin)); + if (priv->flags == flags) + return; + priv->flags = flags; + g_object_notify (G_OBJECT (plugin), "flags"); +} + +/** + * fwupd_plugin_add_flag: + * @plugin: A #FwupdPlugin + * @flag: the #FwupdPluginFlags + * + * Adds a specific plugin flag to the plugin. + * + * Since: 1.5.0 + **/ +void +fwupd_plugin_add_flag (FwupdPlugin *plugin, FwupdPluginFlags flag) +{ + FwupdPluginPrivate *priv = GET_PRIVATE (plugin); + g_return_if_fail (FWUPD_IS_PLUGIN (plugin)); + if (flag == 0) + return; + if ((priv->flags & flag) > 0) + return; + priv->flags |= flag; + g_object_notify (G_OBJECT (plugin), "flags"); +} + +/** + * fwupd_plugin_remove_flag: + * @plugin: A #FwupdPlugin + * @flag: the #FwupdPluginFlags + * + * Removes a specific plugin flag from the plugin. + * + * Since: 1.5.0 + **/ +void +fwupd_plugin_remove_flag (FwupdPlugin *plugin, FwupdPluginFlags flag) +{ + FwupdPluginPrivate *priv = GET_PRIVATE (plugin); + g_return_if_fail (FWUPD_IS_PLUGIN (plugin)); + if (flag == 0) + return; + if ((priv->flags & flag) == 0) + return; + priv->flags &= ~flag; + g_object_notify (G_OBJECT (plugin), "flags"); +} + +/** + * fwupd_plugin_has_flag: + * @plugin: A #FwupdPlugin + * @flag: the #FwupdPluginFlags + * + * Finds if the plugin has a specific plugin flag. + * + * Returns: %TRUE if the flag is set + * + * Since: 1.5.0 + **/ +gboolean +fwupd_plugin_has_flag (FwupdPlugin *plugin, FwupdPluginFlags flag) +{ + FwupdPluginPrivate *priv = GET_PRIVATE (plugin); + g_return_val_if_fail (FWUPD_IS_PLUGIN (plugin), FALSE); + return (priv->flags & flag) > 0; +} + +/** + * fwupd_plugin_to_variant: + * @plugin: A #FwupdPlugin + * + * Creates a GVariant from the plugin data omitting sensitive fields + * + * Returns: the GVariant, or %NULL for error + * + * Since: 1.5.0 + **/ +GVariant * +fwupd_plugin_to_variant (FwupdPlugin *plugin) +{ + FwupdPluginPrivate *priv = GET_PRIVATE (plugin); + GVariantBuilder builder; + + g_return_val_if_fail (FWUPD_IS_PLUGIN (plugin), NULL); + + /* create an array with all the metadata in */ + g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); + if (priv->name != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_NAME, + g_variant_new_string (priv->name)); + } + if (priv->flags > 0) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_FLAGS, + g_variant_new_uint64 (priv->flags)); + } + return g_variant_new ("a{sv}", &builder); +} + +static void +fwupd_plugin_from_key_value (FwupdPlugin *plugin, const gchar *key, GVariant *value) +{ + if (g_strcmp0 (key, FWUPD_RESULT_KEY_NAME) == 0) { + fwupd_plugin_set_name (plugin, g_variant_get_string (value, NULL)); + return; + } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_FLAGS) == 0) { + fwupd_plugin_set_flags (plugin, g_variant_get_uint64 (value)); + return; + } +} + +static void +fwupd_pad_kv_str (GString *str, const gchar *key, const gchar *value) +{ + /* ignore */ + if (key == NULL || value == NULL) + return; + g_string_append_printf (str, " %s: ", key); + for (gsize i = strlen (key); i < 20; i++) + g_string_append (str, " "); + g_string_append_printf (str, "%s\n", value); +} + +static void +fwupd_pad_kv_dfl (GString *str, const gchar *key, guint64 plugin_flags) +{ + g_autoptr(GString) tmp = g_string_new (""); + for (guint i = 0; i < 64; i++) { + if ((plugin_flags & ((guint64) 1 << i)) == 0) + continue; + g_string_append_printf (tmp, "%s|", + fwupd_plugin_flag_to_string ((guint64) 1 << i)); + } + if (tmp->len == 0) { + g_string_append (tmp, fwupd_plugin_flag_to_string (0)); + } else { + g_string_truncate (tmp, tmp->len - 1); + } + fwupd_pad_kv_str (str, key, tmp->str); +} + +static void +fwupd_plugin_json_add_string (JsonBuilder *builder, const gchar *key, const gchar *str) +{ + if (str == NULL) + return; + json_builder_set_member_name (builder, key); + json_builder_add_string_value (builder, str); +} + +/** + * fwupd_plugin_to_json: + * @plugin: A #FwupdPlugin + * @builder: A #JsonBuilder + * + * Adds a fwupd plugin to a JSON builder + * + * Since: 1.5.0 + **/ +void +fwupd_plugin_to_json (FwupdPlugin *plugin, JsonBuilder *builder) +{ + FwupdPluginPrivate *priv = GET_PRIVATE (plugin); + + g_return_if_fail (FWUPD_IS_PLUGIN (plugin)); + g_return_if_fail (builder != NULL); + + fwupd_plugin_json_add_string (builder, FWUPD_RESULT_KEY_NAME, priv->name); + if (priv->flags != FWUPD_PLUGIN_FLAG_NONE) { + json_builder_set_member_name (builder, FWUPD_RESULT_KEY_FLAGS); + json_builder_begin_array (builder); + for (guint i = 0; i < 64; i++) { + const gchar *tmp; + if ((priv->flags & ((guint64) 1 << i)) == 0) + continue; + tmp = fwupd_plugin_flag_to_string ((guint64) 1 << i); + json_builder_add_string_value (builder, tmp); + } + json_builder_end_array (builder); + } +} + +/** + * fwupd_plugin_to_string: + * @plugin: A #FwupdPlugin + * + * Builds a text representation of the object. + * + * Returns: text, or %NULL for invalid + * + * Since: 1.5.0 + **/ +gchar * +fwupd_plugin_to_string (FwupdPlugin *plugin) +{ + FwupdPluginPrivate *priv = GET_PRIVATE (plugin); + GString *str; + + g_return_val_if_fail (FWUPD_IS_PLUGIN (plugin), NULL); + + str = g_string_new (NULL); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_NAME, priv->name); + fwupd_pad_kv_dfl (str, FWUPD_RESULT_KEY_FLAGS, priv->flags); + return g_string_free (str, FALSE); +} + +static void +fwupd_plugin_get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + FwupdPlugin *self = FWUPD_PLUGIN (object); + FwupdPluginPrivate *priv = GET_PRIVATE (self); + switch (prop_id) { + case PROP_NAME: + g_value_set_string (value, priv->name); + break; + case PROP_FLAGS: + g_value_set_uint64 (value, priv->flags); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +fwupd_plugin_set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + FwupdPlugin *self = FWUPD_PLUGIN (object); + switch (prop_id) { + case PROP_NAME: + fwupd_plugin_set_name (self, g_value_get_string (value)); + break; + case PROP_FLAGS: + fwupd_plugin_set_flags (self, g_value_get_uint64 (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +fwupd_plugin_class_init (FwupdPluginClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GParamSpec *pspec; + + object_class->finalize = fwupd_plugin_finalize; + object_class->get_property = fwupd_plugin_get_property; + object_class->set_property = fwupd_plugin_set_property; + + pspec = g_param_spec_string ("name", NULL, NULL, NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_NAME, pspec); + + pspec = g_param_spec_uint64 ("flags", NULL, NULL, + FWUPD_PLUGIN_FLAG_NONE, + FWUPD_PLUGIN_FLAG_UNKNOWN, + FWUPD_PLUGIN_FLAG_NONE, + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_FLAGS, pspec); +} + +static void +fwupd_plugin_init (FwupdPlugin *plugin) +{ +} + +static void +fwupd_plugin_finalize (GObject *object) +{ + FwupdPlugin *plugin = FWUPD_PLUGIN (object); + FwupdPluginPrivate *priv = GET_PRIVATE (plugin); + g_free (priv->name); + G_OBJECT_CLASS (fwupd_plugin_parent_class)->finalize (object); +} + +static void +fwupd_plugin_set_from_variant_iter (FwupdPlugin *plugin, GVariantIter *iter) +{ + GVariant *value; + const gchar *key; + while (g_variant_iter_next (iter, "{&sv}", &key, &value)) { + fwupd_plugin_from_key_value (plugin, key, value); + g_variant_unref (value); + } +} + +/** + * fwupd_plugin_from_variant: + * @value: a #GVariant + * + * Creates a new plugin using packed data. + * + * Returns: (transfer full): a new #FwupdPlugin, or %NULL if @value was invalid + * + * Since: 1.5.0 + **/ +FwupdPlugin * +fwupd_plugin_from_variant (GVariant *value) +{ + FwupdPlugin *plugin = NULL; + const gchar *type_string; + g_autoptr(GVariantIter) iter = NULL; + + /* format from GetDetails */ + type_string = g_variant_get_type_string (value); + if (g_strcmp0 (type_string, "(a{sv})") == 0) { + plugin = fwupd_plugin_new (); + g_variant_get (value, "(a{sv})", &iter); + fwupd_plugin_set_from_variant_iter (plugin, iter); + } else if (g_strcmp0 (type_string, "a{sv}") == 0) { + plugin = fwupd_plugin_new (); + g_variant_get (value, "a{sv}", &iter); + fwupd_plugin_set_from_variant_iter (plugin, iter); + } else { + g_warning ("type %s not known", type_string); + } + return plugin; +} + +/** + * fwupd_plugin_array_from_variant: + * @value: a #GVariant + * + * Creates an array of new plugins using packed data. + * + * Returns: (transfer container) (element-type FwupdPlugin): plugins, or %NULL if @value was invalid + * + * Since: 1.5.0 + **/ +GPtrArray * +fwupd_plugin_array_from_variant (GVariant *value) +{ + GPtrArray *array = NULL; + gsize sz; + g_autoptr(GVariant) untuple = NULL; + + array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + untuple = g_variant_get_child_value (value, 0); + sz = g_variant_n_children (untuple); + for (guint i = 0; i < sz; i++) { + FwupdPlugin *plugin; + g_autoptr(GVariant) data = NULL; + data = g_variant_get_child_value (untuple, i); + plugin = fwupd_plugin_from_variant (data); + if (plugin == NULL) + continue; + g_ptr_array_add (array, plugin); + } + return array; +} + +/** + * fwupd_plugin_new: + * + * Creates a new plugin. + * + * Returns: a new #FwupdPlugin + * + * Since: 1.5.0 + **/ +FwupdPlugin * +fwupd_plugin_new (void) +{ + FwupdPlugin *plugin; + plugin = g_object_new (FWUPD_TYPE_PLUGIN, NULL); + return FWUPD_PLUGIN (plugin); +} diff -Nru fwupd-1.4.5/libfwupd/fwupd-plugin.h fwupd-1.5.8/libfwupd/fwupd-plugin.h --- fwupd-1.4.5/libfwupd/fwupd-plugin.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupd/fwupd-plugin.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#include "fwupd-enums.h" + +G_BEGIN_DECLS + +#define FWUPD_TYPE_PLUGIN (fwupd_plugin_get_type ()) +G_DECLARE_DERIVABLE_TYPE (FwupdPlugin, fwupd_plugin, FWUPD, PLUGIN, GObject) + +struct _FwupdPluginClass +{ + GObjectClass parent_class; + /*< private >*/ + void (*_fwupd_reserved1) (void); + void (*_fwupd_reserved2) (void); + void (*_fwupd_reserved3) (void); + void (*_fwupd_reserved4) (void); + void (*_fwupd_reserved5) (void); + void (*_fwupd_reserved6) (void); + void (*_fwupd_reserved7) (void); +}; + +FwupdPlugin *fwupd_plugin_new (void); +gchar *fwupd_plugin_to_string (FwupdPlugin *plugin); + +const gchar *fwupd_plugin_get_name (FwupdPlugin *plugin); +void fwupd_plugin_set_name (FwupdPlugin *plugin, + const gchar *name); +guint64 fwupd_plugin_get_flags (FwupdPlugin *plugin); +void fwupd_plugin_set_flags (FwupdPlugin *plugin, + guint64 flags); +void fwupd_plugin_add_flag (FwupdPlugin *plugin, + FwupdPluginFlags flag); +void fwupd_plugin_remove_flag (FwupdPlugin *plugin, + FwupdPluginFlags flag); +gboolean fwupd_plugin_has_flag (FwupdPlugin *plugin, + FwupdPluginFlags flag); + +FwupdPlugin *fwupd_plugin_from_variant (GVariant *value); +GPtrArray *fwupd_plugin_array_from_variant (GVariant *value); + +G_END_DECLS diff -Nru fwupd-1.4.5/libfwupd/fwupd-plugin-private.h fwupd-1.5.8/libfwupd/fwupd-plugin-private.h --- fwupd-1.4.5/libfwupd/fwupd-plugin-private.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupd/fwupd-plugin-private.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#include "fwupd-plugin.h" + +G_BEGIN_DECLS + +GVariant *fwupd_plugin_to_variant (FwupdPlugin *plugin); +void fwupd_plugin_to_json (FwupdPlugin *plugin, + JsonBuilder *builder); + +G_END_DECLS + diff -Nru fwupd-1.4.5/libfwupd/fwupd-release.c fwupd-1.5.8/libfwupd/fwupd-release.c --- fwupd-1.4.5/libfwupd/fwupd-release.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupd/fwupd-release.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2018 Richard Hughes + * Copyright (C) 2015 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -46,7 +46,8 @@ gchar *name; gchar *name_variant_suffix; gchar *summary; - gchar *uri; + gchar *branch; + GPtrArray *locations; gchar *vendor; gchar *version; gchar *remote_id; @@ -98,6 +99,11 @@ { FwupdReleasePrivate *priv = GET_PRIVATE (release); g_return_if_fail (FWUPD_IS_RELEASE (release)); + + /* not changed */ + if (g_strcmp0 (priv->remote_id, remote_id) == 0) + return; + g_free (priv->remote_id); priv->remote_id = g_strdup (remote_id); } @@ -134,6 +140,11 @@ { FwupdReleasePrivate *priv = GET_PRIVATE (release); g_return_if_fail (FWUPD_IS_RELEASE (release)); + + /* not changed */ + if (g_strcmp0 (priv->version, version) == 0) + return; + g_free (priv->version); priv->version = g_strdup (version); } @@ -170,6 +181,11 @@ { FwupdReleasePrivate *priv = GET_PRIVATE (release); g_return_if_fail (FWUPD_IS_RELEASE (release)); + + /* not changed */ + if (g_strcmp0 (priv->filename, filename) == 0) + return; + g_free (priv->filename); priv->filename = g_strdup (filename); } @@ -206,6 +222,11 @@ { FwupdReleasePrivate *priv = GET_PRIVATE (release); g_return_if_fail (FWUPD_IS_RELEASE (release)); + + /* not changed */ + if (g_strcmp0 (priv->update_message, update_message) == 0) + return; + g_free (priv->update_message); priv->update_message = g_strdup (update_message); } @@ -242,6 +263,11 @@ { FwupdReleasePrivate *priv = GET_PRIVATE (release); g_return_if_fail (FWUPD_IS_RELEASE (release)); + + /* not changed */ + if (g_strcmp0 (priv->update_image, update_image) == 0) + return; + g_free (priv->update_image); priv->update_image = g_strdup (update_image); } @@ -278,6 +304,11 @@ { FwupdReleasePrivate *priv = GET_PRIVATE (release); g_return_if_fail (FWUPD_IS_RELEASE (release)); + + /* not changed */ + if (g_strcmp0 (priv->protocol, protocol) == 0) + return; + g_free (priv->protocol); priv->protocol = g_strdup (protocol); } @@ -544,18 +575,21 @@ * fwupd_release_get_uri: * @release: A #FwupdRelease * - * Gets the update uri. + * Gets the default update URI. * - * Returns: the update uri, or %NULL if unset + * Returns: the update URI, or %NULL if unset * * Since: 0.9.3 + * Deprecated: 1.5.6: Use fwupd_release_get_locations() instead. **/ const gchar * fwupd_release_get_uri (FwupdRelease *release) { FwupdReleasePrivate *priv = GET_PRIVATE (release); g_return_val_if_fail (FWUPD_IS_RELEASE (release), NULL); - return priv->uri; + if (priv->locations->len == 0) + return NULL; + return (const gchar *) g_ptr_array_index (priv->locations, 0); } /** @@ -563,17 +597,62 @@ * @release: A #FwupdRelease * @uri: the update URI * - * Sets the update uri, i.e. where you can download the firmware from. + * Sets the update URI, i.e. where you can download the firmware from. * * Since: 0.9.3 + * Deprecated: 1.5.6: Use fwupd_release_add_location() instead. **/ void fwupd_release_set_uri (FwupdRelease *release, const gchar *uri) { FwupdReleasePrivate *priv = GET_PRIVATE (release); g_return_if_fail (FWUPD_IS_RELEASE (release)); - g_free (priv->uri); - priv->uri = g_strdup (uri); + g_ptr_array_set_size (priv->locations, 0); + g_ptr_array_add (priv->locations, g_strdup (uri)); +} + +/** + * fwupd_release_get_locations: + * @release: A #FwupdRelease + * + * Gets the update URI, i.e. where you can download the firmware from. + * + * Typically the first URI will be the main HTTP mirror, but all URIs may not + * be valid HTTP URIs. For example, "ipns://QmSrPmba" is valid here. + * + * Returns: (element-type utf8) (transfer none): the URIs + * + * Since: 1.5.6 + **/ +GPtrArray * +fwupd_release_get_locations (FwupdRelease *release) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_val_if_fail (FWUPD_IS_RELEASE (release), NULL); + return priv->locations; +} + +/** + * fwupd_release_add_location: + * @release: A #FwupdRelease + * @location: the update URI + * + * Adds an update URI, i.e. where you can download the firmware from. + * + * Since: 1.5.6 + **/ +void +fwupd_release_add_location (FwupdRelease *release, const gchar *location) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_if_fail (FWUPD_IS_RELEASE (release)); + g_return_if_fail (location != NULL); + for (guint i = 0; i < priv->locations->len; i++) { + const gchar *location_tmp = g_ptr_array_index (priv->locations, i); + if (g_strcmp0 (location_tmp, location) == 0) + return; + } + g_ptr_array_add (priv->locations, g_strdup (location)); } /** @@ -608,6 +687,11 @@ { FwupdReleasePrivate *priv = GET_PRIVATE (release); g_return_if_fail (FWUPD_IS_RELEASE (release)); + + /* not changed */ + if (g_strcmp0 (priv->homepage, homepage) == 0) + return; + g_free (priv->homepage); priv->homepage = g_strdup (homepage); } @@ -644,6 +728,11 @@ { FwupdReleasePrivate *priv = GET_PRIVATE (release); g_return_if_fail (FWUPD_IS_RELEASE (release)); + + /* not changed */ + if (g_strcmp0 (priv->details_url, details_url) == 0) + return; + g_free (priv->details_url); priv->details_url = g_strdup (details_url); } @@ -680,6 +769,11 @@ { FwupdReleasePrivate *priv = GET_PRIVATE (release); g_return_if_fail (FWUPD_IS_RELEASE (release)); + + /* not changed */ + if (g_strcmp0 (priv->source_url, source_url) == 0) + return; + g_free (priv->source_url); priv->source_url = g_strdup (source_url); } @@ -716,6 +810,11 @@ { FwupdReleasePrivate *priv = GET_PRIVATE (release); g_return_if_fail (FWUPD_IS_RELEASE (release)); + + /* not changed */ + if (g_strcmp0 (priv->description, description) == 0) + return; + g_free (priv->description); priv->description = g_strdup (description); } @@ -752,6 +851,11 @@ { FwupdReleasePrivate *priv = GET_PRIVATE (release); g_return_if_fail (FWUPD_IS_RELEASE (release)); + + /* not changed */ + if (g_strcmp0 (priv->appstream_id, appstream_id) == 0) + return; + g_free (priv->appstream_id); priv->appstream_id = g_strdup (appstream_id); } @@ -788,6 +892,11 @@ { FwupdReleasePrivate *priv = GET_PRIVATE (release); g_return_if_fail (FWUPD_IS_RELEASE (release)); + + /* not changed */ + if (g_strcmp0 (priv->detach_caption, detach_caption) == 0) + return; + g_free (priv->detach_caption); priv->detach_caption = g_strdup (detach_caption); } @@ -824,6 +933,11 @@ { FwupdReleasePrivate *priv = GET_PRIVATE (release); g_return_if_fail (FWUPD_IS_RELEASE (release)); + + /* not changed */ + if (g_strcmp0 (priv->detach_image, detach_image) == 0) + return; + g_free (priv->detach_image); priv->detach_image = g_strdup (detach_image); } @@ -930,11 +1044,57 @@ { FwupdReleasePrivate *priv = GET_PRIVATE (release); g_return_if_fail (FWUPD_IS_RELEASE (release)); + + /* not changed */ + if (g_strcmp0 (priv->summary, summary) == 0) + return; + g_free (priv->summary); priv->summary = g_strdup (summary); } /** + * fwupd_release_get_branch: + * @release: A #FwupdRelease + * + * Gets the update branch. + * + * Returns: the alternate branch, or %NULL if unset + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_release_get_branch (FwupdRelease *release) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_val_if_fail (FWUPD_IS_RELEASE (release), NULL); + return priv->branch; +} + +/** + * fwupd_release_set_branch: + * @release: A #FwupdRelease + * @branch: the update one line branch + * + * Sets the alternate branch. + * + * Since: 1.5.0 + **/ +void +fwupd_release_set_branch (FwupdRelease *release, const gchar *branch) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_if_fail (FWUPD_IS_RELEASE (release)); + + /* not changed */ + if (g_strcmp0 (priv->branch, branch) == 0) + return; + + g_free (priv->branch); + priv->branch = g_strdup (branch); +} + +/** * fwupd_release_get_vendor: * @release: A #FwupdRelease * @@ -966,6 +1126,11 @@ { FwupdReleasePrivate *priv = GET_PRIVATE (release); g_return_if_fail (FWUPD_IS_RELEASE (release)); + + /* not changed */ + if (g_strcmp0 (priv->vendor, vendor) == 0) + return; + g_free (priv->vendor); priv->vendor = g_strdup (vendor); } @@ -1002,6 +1167,11 @@ { FwupdReleasePrivate *priv = GET_PRIVATE (release); g_return_if_fail (FWUPD_IS_RELEASE (release)); + + /* not changed */ + if (g_strcmp0 (priv->license, license) == 0) + return; + g_free (priv->license); priv->license = g_strdup (license); } @@ -1038,6 +1208,11 @@ { FwupdReleasePrivate *priv = GET_PRIVATE (release); g_return_if_fail (FWUPD_IS_RELEASE (release)); + + /* not changed */ + if (g_strcmp0 (priv->name, name) == 0) + return; + g_free (priv->name); priv->name = g_strdup (name); } @@ -1074,6 +1249,11 @@ { FwupdReleasePrivate *priv = GET_PRIVATE (release); g_return_if_fail (FWUPD_IS_RELEASE (release)); + + /* not changed */ + if (g_strcmp0 (priv->name_variant_suffix, name_variant_suffix) == 0) + return; + g_free (priv->name_variant_suffix); priv->name_variant_suffix = g_strdup (name_variant_suffix); } @@ -1354,6 +1534,11 @@ FWUPD_RESULT_KEY_SUMMARY, g_variant_new_string (priv->summary)); } + if (priv->branch != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_BRANCH, + g_variant_new_string (priv->branch)); + } if (priv->description != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_DESCRIPTION, @@ -1387,10 +1572,15 @@ FWUPD_RESULT_KEY_CHECKSUM, g_variant_new_string (str->str)); } - if (priv->uri != NULL) { + if (priv->locations->len > 0) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_LOCATIONS, + g_variant_new_strv ((const gchar * const*) priv->locations->pdata, + priv->locations->len)); + /* for compatibilty */ g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_URI, - g_variant_new_string (priv->uri)); + g_variant_new_string (g_ptr_array_index (priv->locations, 0))); } if (priv->homepage != NULL) { g_variant_builder_add (&builder, "{sv}", @@ -1492,6 +1682,10 @@ fwupd_release_set_summary (release, g_variant_get_string (value, NULL)); return; } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_BRANCH) == 0) { + fwupd_release_set_branch (release, g_variant_get_string (value, NULL)); + return; + } if (g_strcmp0 (key, FWUPD_RESULT_KEY_DESCRIPTION) == 0) { fwupd_release_set_description (release, g_variant_get_string (value, NULL)); return; @@ -1515,8 +1709,14 @@ fwupd_release_add_checksum (release, split[i]); return; } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_LOCATIONS) == 0) { + g_autofree const gchar **strv = g_variant_get_strv (value, NULL); + for (guint i = 0; strv[i] != NULL; i++) + fwupd_release_add_location (release, strv[i]); + return; + } if (g_strcmp0 (key, FWUPD_RESULT_KEY_URI) == 0) { - fwupd_release_set_uri (release, g_variant_get_string (value, NULL)); + fwupd_release_add_location (release, g_variant_get_string (value, NULL)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_HOMEPAGE) == 0) { @@ -1675,6 +1875,7 @@ fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_REMOTE_ID, priv->remote_id); fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_SUMMARY, priv->summary); fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_DESCRIPTION, priv->description); + fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_BRANCH, priv->branch); fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_VERSION, priv->version); fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_FILENAME, priv->filename); fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_PROTOCOL, priv->protocol); @@ -1708,7 +1909,18 @@ fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_LICENSE, priv->license); fwupd_release_json_add_int (builder, FWUPD_RESULT_KEY_SIZE, priv->size); fwupd_release_json_add_int (builder, FWUPD_RESULT_KEY_CREATED, priv->created); - fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_URI, priv->uri); + if (priv->locations->len > 0) { + json_builder_set_member_name (builder, FWUPD_RESULT_KEY_LOCATIONS); + json_builder_begin_array (builder); + for (guint i = 0; i < priv->locations->len; i++) { + const gchar *location = g_ptr_array_index (priv->locations, i); + json_builder_add_string_value (builder, location); + } + json_builder_end_array (builder); + /* for compatibilty */ + fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_URI, + (const gchar *) g_ptr_array_index (priv->locations, 0)); + } fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_HOMEPAGE, priv->homepage); fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_DETAILS_URL, priv->details_url); fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_SOURCE_URL, priv->source_url); @@ -1764,6 +1976,7 @@ fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_REMOTE_ID, priv->remote_id); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_SUMMARY, priv->summary); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_DESCRIPTION, priv->description); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_BRANCH, priv->branch); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_VERSION, priv->version); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_FILENAME, priv->filename); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_PROTOCOL, priv->protocol); @@ -1783,7 +1996,10 @@ fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_LICENSE, priv->license); fwupd_pad_kv_siz (str, FWUPD_RESULT_KEY_SIZE, priv->size); fwupd_pad_kv_unx (str, FWUPD_RESULT_KEY_CREATED, priv->created); - fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_URI, priv->uri); + for (guint i = 0; i < priv->locations->len; i++) { + const gchar *location = g_ptr_array_index (priv->locations, i); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_URI, location); + } fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_HOMEPAGE, priv->homepage); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_DETAILS_URL, priv->details_url); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_SOURCE_URL, priv->source_url); @@ -1798,7 +2014,7 @@ fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_DETACH_IMAGE, priv->detach_image); if (priv->update_message != NULL) fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_UPDATE_MESSAGE, priv->update_message); - if (priv->update_message != NULL) + if (priv->update_image != NULL) fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_UPDATE_IMAGE, priv->update_image); /* metadata */ keys = g_hash_table_get_keys (priv->metadata); @@ -1825,6 +2041,7 @@ priv->categories = g_ptr_array_new_with_free_func (g_free); priv->issues = g_ptr_array_new_with_free_func (g_free); priv->checksums = g_ptr_array_new_with_free_func (g_free); + priv->locations = g_ptr_array_new_with_free_func (g_free); priv->metadata = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); } @@ -1844,7 +2061,8 @@ g_free (priv->name); g_free (priv->name_variant_suffix); g_free (priv->summary); - g_free (priv->uri); + g_free (priv->branch); + g_ptr_array_unref (priv->locations); g_free (priv->homepage); g_free (priv->details_url); g_free (priv->source_url); diff -Nru fwupd-1.4.5/libfwupd/fwupd-release.h fwupd-1.5.8/libfwupd/fwupd-release.h --- fwupd-1.4.5/libfwupd/fwupd-release.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupd/fwupd-release.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2018 Richard Hughes + * Copyright (C) 2015 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -34,9 +34,14 @@ const gchar *fwupd_release_get_version (FwupdRelease *release); void fwupd_release_set_version (FwupdRelease *release, const gchar *version); +G_DEPRECATED_FOR(fwupd_release_get_locations) const gchar *fwupd_release_get_uri (FwupdRelease *release); +G_DEPRECATED_FOR(fwupd_release_add_location) void fwupd_release_set_uri (FwupdRelease *release, const gchar *uri); +GPtrArray *fwupd_release_get_locations (FwupdRelease *release); +void fwupd_release_add_location (FwupdRelease *release, + const gchar *location); GPtrArray *fwupd_release_get_issues (FwupdRelease *release); void fwupd_release_add_issue (FwupdRelease *release, const gchar *issue); @@ -90,6 +95,9 @@ const gchar *fwupd_release_get_summary (FwupdRelease *release); void fwupd_release_set_summary (FwupdRelease *release, const gchar *summary); +const gchar *fwupd_release_get_branch (FwupdRelease *release); +void fwupd_release_set_branch (FwupdRelease *release, + const gchar *branch); const gchar *fwupd_release_get_description (FwupdRelease *release); void fwupd_release_set_description (FwupdRelease *release, const gchar *description); diff -Nru fwupd-1.4.5/libfwupd/fwupd-remote.c fwupd-1.5.8/libfwupd/fwupd-remote.c --- fwupd-1.4.5/libfwupd/fwupd-remote.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupd/fwupd-remote.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,12 +1,14 @@ /* - * Copyright (C) 2017-2018 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" -#include +#ifdef HAVE_LIBCURL +#include +#endif #include #include "fwupd-deprecated.h" @@ -32,6 +34,7 @@ gchar *id; gchar *firmware_base_uri; gchar *report_uri; + gchar *security_report_uri; gchar *metadata_uri; gchar *metadata_uri_sig; gchar *username; @@ -50,6 +53,7 @@ gchar **order_before; gchar *remotes_dir; gboolean automatic_reports; + gboolean automatic_security_reports; } FwupdRemotePrivate; enum { @@ -58,12 +62,19 @@ PROP_ENABLED, PROP_APPROVAL_REQUIRED, PROP_AUTOMATIC_REPORTS, + PROP_AUTOMATIC_SECURITY_REPORTS, PROP_LAST }; G_DEFINE_TYPE_WITH_PRIVATE (FwupdRemote, fwupd_remote, G_TYPE_OBJECT) #define GET_PRIVATE(o) (fwupd_remote_get_instance_private (o)) +#ifdef HAVE_LIBCURL_7_62_0 +typedef gchar curlptr; +G_DEFINE_AUTOPTR_CLEANUP_FUNC(curlptr, curl_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(CURLU, curl_url_cleanup) +#endif + static void fwupd_remote_set_username (FwupdRemote *self, const gchar *username) { @@ -77,6 +88,11 @@ fwupd_remote_set_title (FwupdRemote *self, const gchar *title) { FwupdRemotePrivate *priv = GET_PRIVATE (self); + + /* not changed */ + if (g_strcmp0 (priv->title, title) == 0) + return; + g_free (priv->title); priv->title = g_strdup (title); } @@ -94,6 +110,11 @@ fwupd_remote_set_agreement (FwupdRemote *self, const gchar *agreement) { FwupdRemotePrivate *priv = GET_PRIVATE (self); + + /* not changed */ + if (g_strcmp0 (priv->agreement, agreement) == 0) + return; + g_free (priv->agreement); priv->agreement = g_strdup (agreement); } @@ -102,6 +123,11 @@ fwupd_remote_set_checksum (FwupdRemote *self, const gchar *checksum) { FwupdRemotePrivate *priv = GET_PRIVATE (self); + + /* not changed */ + if (g_strcmp0 (priv->checksum, checksum) == 0) + return; + g_free (priv->checksum); priv->checksum = g_strdup (checksum); } @@ -110,8 +136,14 @@ fwupd_remote_set_password (FwupdRemote *self, const gchar *password) { FwupdRemotePrivate *priv = GET_PRIVATE (self); + + /* not changed */ + if (g_strcmp0 (priv->password, password) == 0) + return; + if (password != NULL && password[0] == '\0') password = NULL; + g_free (priv->password); priv->password = g_strdup (password); } @@ -122,7 +154,16 @@ priv->kind = kind; } -static void +/** + * fwupd_remote_set_keyring_kind: + * @self: A #FwupdRemote + * @keyring_kind: #FwupdKeyringKind e.g. #FWUPD_KEYRING_KIND_PKCS7 + * + * Sets the keyring kind + * + * Since: 1.5.3 + **/ +void fwupd_remote_set_keyring_kind (FwupdRemote *self, FwupdKeyringKind keyring_kind) { FwupdRemotePrivate *priv = GET_PRIVATE (self); @@ -134,6 +175,11 @@ fwupd_remote_set_id (FwupdRemote *self, const gchar *id) { FwupdRemotePrivate *priv = GET_PRIVATE (self); + + /* not changed */ + if (g_strcmp0 (priv->id, id) == 0) + return; + g_free (priv->id); priv->id = g_strdup (id); g_strdelimit (priv->id, ".", '\0'); @@ -143,64 +189,71 @@ fwupd_remote_set_filename_source (FwupdRemote *self, const gchar *filename_source) { FwupdRemotePrivate *priv = GET_PRIVATE (self); + if (priv->filename_source == filename_source) + return; g_free (priv->filename_source); priv->filename_source = g_strdup (filename_source); } -static SoupURI * +static const gchar * +fwupd_remote_get_suffix_for_keyring_kind (FwupdKeyringKind keyring_kind) +{ + if (keyring_kind == FWUPD_KEYRING_KIND_JCAT) + return ".jcat"; + if (keyring_kind == FWUPD_KEYRING_KIND_GPG) + return ".asc"; + if (keyring_kind == FWUPD_KEYRING_KIND_PKCS7) + return ".p7b"; + return NULL; +} + +static gchar * fwupd_remote_build_uri (FwupdRemote *self, const gchar *url, GError **error) { FwupdRemotePrivate *priv = GET_PRIVATE (self); - SoupURI *uri; - - g_return_val_if_fail (FWUPD_IS_REMOTE (self), NULL); - g_return_val_if_fail (url != NULL, NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); +#ifdef HAVE_LIBCURL_7_62_0 + g_autoptr(curlptr) tmp_uri = NULL; + g_autoptr(CURLU) uri = curl_url (); /* create URI, substituting if required */ if (priv->firmware_base_uri != NULL) { - g_autoptr(SoupURI) uri_tmp = NULL; g_autofree gchar *basename = NULL; - g_autofree gchar *url2 = NULL; - uri_tmp = soup_uri_new (url); - if (uri_tmp == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Failed to parse URI '%s'", url); - return NULL; - } - basename = g_path_get_basename (soup_uri_get_path (uri_tmp)); - url2 = g_build_filename (priv->firmware_base_uri, basename, NULL); - uri = soup_uri_new (url2); - if (uri == NULL) { + g_autofree gchar *path_new = NULL; + g_autoptr(curlptr) path = NULL; + g_autoptr(CURLU) uri_tmp = curl_url (); + if (curl_url_set (uri_tmp, CURLUPART_URL, url, 0) != CURLUE_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "Failed to parse URI '%s'", url2); + "Failed to parse url '%s'", url); return NULL; } + curl_url_get (uri_tmp, CURLUPART_PATH, &path, 0); + basename = g_path_get_basename (path); + path_new = g_build_filename (priv->firmware_base_uri, basename, NULL); + curl_url_set (uri, CURLUPART_URL, path_new, 0); /* use the base URI of the metadata to build the full path */ } else if (g_strstr_len (url, -1, "/") == NULL) { g_autofree gchar *basename = NULL; - g_autofree gchar *path = NULL; - uri = soup_uri_new (priv->metadata_uri); - if (uri == NULL) { + g_autofree gchar *path_new = NULL; + g_autoptr(curlptr) path = NULL; + if (curl_url_set (uri, CURLUPART_URL, priv->metadata_uri, 0) != CURLUE_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "Failed to parse metadata URI '%s'", url); + "Failed to parse url '%s'", + priv->metadata_uri); return NULL; } - basename = g_path_get_dirname (soup_uri_get_path (uri)); - path = g_build_filename (basename, url, NULL); - soup_uri_set_path (uri, path); + curl_url_get (uri, CURLUPART_PATH, &path, 0); + basename = g_path_get_dirname (path); + path_new = g_build_filename (basename, url, NULL); + curl_url_set (uri, CURLUPART_URL, path_new, 0); /* a normal URI */ } else { - uri = soup_uri_new (url); - if (uri == NULL) { + if (curl_url_set (uri, CURLUPART_URL, url, 0) != CURLUE_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, @@ -211,10 +264,22 @@ /* set the username and password */ if (priv->username != NULL) - soup_uri_set_user (uri, priv->username); + curl_url_set (uri, CURLUPART_USER, priv->username, 0); if (priv->password != NULL) - soup_uri_set_password (uri, priv->password); - return uri; + curl_url_set (uri, CURLUPART_PASSWORD, priv->password, 0); + curl_url_get (uri, CURLUPART_URL, &tmp_uri, 0); + return g_strdup (tmp_uri); +#else + if (priv->firmware_base_uri != NULL) { + g_autofree gchar *basename = g_path_get_basename (url); + return g_build_filename (priv->firmware_base_uri, basename, NULL); + } + if (g_strstr_len (url, -1, "/") == NULL) { + g_autofree gchar *basename = g_path_get_dirname (priv->metadata_uri); + return g_build_filename (basename, url, NULL); + } + return g_strdup (url); +#endif } /* note, this has to be set before username and password */ @@ -222,19 +287,15 @@ fwupd_remote_set_metadata_uri (FwupdRemote *self, const gchar *metadata_uri) { FwupdRemotePrivate *priv = GET_PRIVATE (self); - g_autoptr(SoupURI) uri = NULL; - - /* build the URI */ - uri = soup_uri_new (metadata_uri); - if (uri == NULL) - return; + const gchar *suffix; /* save this so we can export the object as a GVariant */ priv->metadata_uri = g_strdup (metadata_uri); /* generate the signature URI too */ - if (priv->keyring_kind == FWUPD_KEYRING_KIND_JCAT) - priv->metadata_uri_sig = g_strconcat (metadata_uri, ".jcat", NULL); + suffix = fwupd_remote_get_suffix_for_keyring_kind (priv->keyring_kind); + if (suffix != NULL) + priv->metadata_uri_sig = g_strconcat (metadata_uri, suffix, NULL); } /* note, this has to be set after MetadataURI */ @@ -252,6 +313,13 @@ priv->report_uri = g_strdup (report_uri); } +static void +fwupd_remote_set_security_report_uri (FwupdRemote *self, const gchar *security_report_uri) +{ + FwupdRemotePrivate *priv = GET_PRIVATE (self); + priv->security_report_uri = g_strdup (security_report_uri); +} + /** * fwupd_remote_kind_from_string: * @kind: a string, e.g. `download` @@ -300,16 +368,22 @@ fwupd_remote_set_filename_cache (FwupdRemote *self, const gchar *filename) { FwupdRemotePrivate *priv = GET_PRIVATE (self); + const gchar *suffix; g_return_if_fail (FWUPD_IS_REMOTE (self)); + /* not changed */ + if (g_strcmp0 (priv->filename_cache, filename) == 0) + return; + g_free (priv->filename_cache); priv->filename_cache = g_strdup (filename); /* create for all remote types */ - if (priv->keyring_kind == FWUPD_KEYRING_KIND_JCAT) { + suffix = fwupd_remote_get_suffix_for_keyring_kind (priv->keyring_kind); + if (suffix != NULL) { g_free (priv->filename_cache_sig); - priv->filename_cache_sig = g_strconcat (filename, ".jcat", NULL); + priv->filename_cache_sig = g_strconcat (filename, suffix, NULL); } } @@ -343,6 +417,7 @@ g_autofree gchar *order_after = NULL; g_autofree gchar *order_before = NULL; g_autofree gchar *report_uri = NULL; + g_autofree gchar *security_report_uri = NULL; g_autoptr(GKeyFile) kf = NULL; g_return_val_if_fail (FWUPD_IS_REMOTE (self), FALSE); @@ -373,11 +448,6 @@ keyring_kind); return FALSE; } - if (priv->keyring_kind == FWUPD_KEYRING_KIND_GPG || - priv->keyring_kind == FWUPD_KEYRING_KIND_PKCS7) { - g_debug ("converting Keyring value to Jcat"); - priv->keyring_kind = FWUPD_KEYRING_KIND_JCAT; - } } /* all remotes need a URI, even if it's file:// to the cache */ @@ -394,7 +464,9 @@ else priv->kind = FWUPD_REMOTE_KIND_LOCAL; } else if (g_str_has_prefix (metadata_uri, "http://") || - g_str_has_prefix (metadata_uri, "https://")) { + g_str_has_prefix (metadata_uri, "https://") || + g_str_has_prefix (metadata_uri, "ipfs://") || + g_str_has_prefix (metadata_uri, "ipns://")) { priv->kind = FWUPD_REMOTE_KIND_DOWNLOAD; } else { g_set_error (error, @@ -415,8 +487,14 @@ if (report_uri != NULL && report_uri[0] != '\0') fwupd_remote_set_report_uri (self, report_uri); + /* security reporting is optional */ + security_report_uri = g_key_file_get_string (kf, group, "SecurityReportURI", NULL); + if (security_report_uri != NULL && security_report_uri[0] != '\0') + fwupd_remote_set_security_report_uri (self, security_report_uri); + /* automatic report uploading */ priv->automatic_reports = g_key_file_get_boolean (kf, group, "AutomaticReports", NULL); + priv->automatic_security_reports = g_key_file_get_boolean (kf, group, "AutomaticSecurityReports", NULL); /* DOWNLOAD-type remotes */ if (priv->kind == FWUPD_REMOTE_KIND_DOWNLOAD) { @@ -693,6 +771,11 @@ { FwupdRemotePrivate *priv = GET_PRIVATE (self); g_return_if_fail (FWUPD_IS_REMOTE (self)); + + /* not changed */ + if (g_strcmp0 (priv->remotes_dir, directory) == 0) + return; + g_free (priv->remotes_dir); priv->remotes_dir = g_strdup (directory); } @@ -855,10 +938,10 @@ gchar * fwupd_remote_build_firmware_uri (FwupdRemote *self, const gchar *url, GError **error) { - g_autoptr(SoupURI) uri = fwupd_remote_build_uri (self, url, error); - if (uri == NULL) - return NULL; - return soup_uri_to_string (uri, FALSE); + g_return_val_if_fail (FWUPD_IS_REMOTE (self), NULL); + g_return_val_if_fail (url != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return fwupd_remote_build_uri (self, url, error); } /** @@ -880,6 +963,24 @@ } /** + * fwupd_remote_get_security_report_uri: + * @self: A #FwupdRemote + * + * Gets the URI for the security report. + * + * Returns: (transfer none): a URI, or %NULL for invalid. + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_remote_get_security_report_uri (FwupdRemote *self) +{ + FwupdRemotePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_REMOTE (self), NULL); + return priv->security_report_uri; +} + +/** * fwupd_remote_get_metadata_uri: * @self: A #FwupdRemote * @@ -948,6 +1049,9 @@ * * Parses the signature, updating the metadata URI as appropriate. * + * This can only be called for remotes with `Keyring=jcat` which is + * the default for most remotes. + * * Returns: %TRUE for success * * Since: 1.4.5 @@ -955,6 +1059,7 @@ gboolean fwupd_remote_load_signature_bytes (FwupdRemote *self, GBytes *bytes, GError **error) { + FwupdRemotePrivate *priv = GET_PRIVATE (self); g_autoptr(GInputStream) istr = NULL; g_autoptr(JcatFile) jcat_file = jcat_file_new (); @@ -962,6 +1067,15 @@ g_return_val_if_fail (bytes != NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + /* sanity check */ + if (priv->keyring_kind != FWUPD_KEYRING_KIND_JCAT) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "only supported for JCat remotes"); + return FALSE; + } + istr = g_memory_input_stream_new_from_bytes (bytes); if (!jcat_file_import_stream (jcat_file, istr, JCAT_IMPORT_FLAG_NONE, NULL, error)) return FALSE; @@ -1070,6 +1184,24 @@ } /** + * fwupd_remote_get_automatic_security_reports: + * @self: A #FwupdRemote + * + * Gets if security reports should be automatically uploaded to this remote + * + * Returns: a #TRUE if the remote should have reports uploaded automatically + * + * Since: 1.5.0 + **/ +gboolean +fwupd_remote_get_automatic_security_reports (FwupdRemote *self) +{ + FwupdRemotePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_REMOTE (self), FALSE); + return priv->automatic_security_reports; +} + +/** * fwupd_remote_get_approval_required: * @self: A #FwupdRemote * @@ -1133,6 +1265,8 @@ fwupd_remote_set_filename_source (self, g_variant_get_string (value, NULL)); if (g_strcmp0 (key, "ReportUri") == 0) fwupd_remote_set_report_uri (self, g_variant_get_string (value, NULL)); + if (g_strcmp0 (key, "SecurityReportUri") == 0) + fwupd_remote_set_security_report_uri (self, g_variant_get_string (value, NULL)); } while (g_variant_iter_loop (iter3, "{sv}", &key, &value)) { if (g_strcmp0 (key, "Username") == 0) { @@ -1157,6 +1291,8 @@ fwupd_remote_set_firmware_base_uri (self, g_variant_get_string (value, NULL)); } else if (g_strcmp0 (key, "AutomaticReports") == 0) { priv->automatic_reports = g_variant_get_boolean (value); + } else if (g_strcmp0 (key, "AutomaticSecurityReports") == 0) { + priv->automatic_security_reports = g_variant_get_boolean (value); } } } @@ -1213,6 +1349,10 @@ g_variant_builder_add (&builder, "{sv}", "ReportUri", g_variant_new_string (priv->report_uri)); } + if (priv->security_report_uri != NULL) { + g_variant_builder_add (&builder, "{sv}", "SecurityReportUri", + g_variant_new_string (priv->security_report_uri)); + } if (priv->firmware_base_uri != NULL) { g_variant_builder_add (&builder, "{sv}", "FirmwareBaseUri", g_variant_new_string (priv->firmware_base_uri)); @@ -1251,6 +1391,8 @@ g_variant_new_boolean (priv->approval_required)); g_variant_builder_add (&builder, "{sv}", "AutomaticReports", g_variant_new_boolean (priv->automatic_reports)); + g_variant_builder_add (&builder, "{sv}", "AutomaticSecurityReports", + g_variant_new_boolean (priv->automatic_security_reports)); return g_variant_new ("a{sv}", &builder); } @@ -1274,6 +1416,9 @@ case PROP_AUTOMATIC_REPORTS: g_value_set_boolean (value, priv->automatic_reports); break; + case PROP_AUTOMATIC_SECURITY_REPORTS: + g_value_set_boolean (value, priv->automatic_security_reports); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); break; @@ -1300,6 +1445,9 @@ case PROP_AUTOMATIC_REPORTS: priv->automatic_reports = g_value_get_boolean (value); break; + case PROP_AUTOMATIC_SECURITY_REPORTS: + priv->automatic_security_reports = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); break; @@ -1360,6 +1508,17 @@ FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_AUTOMATIC_REPORTS, pspec); + /** + * FwupdRemote:automatic-security-reports: + * + * The behavior for auto-uploading security reports. + * + * Since: 1.5.0 + */ + pspec = g_param_spec_boolean ("automatic-security-reports", NULL, NULL, + FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_AUTOMATIC_SECURITY_REPORTS, pspec); + } static void @@ -1378,6 +1537,7 @@ g_free (priv->metadata_uri_sig); g_free (priv->firmware_base_uri); g_free (priv->report_uri); + g_free (priv->security_report_uri); g_free (priv->username); g_free (priv->password); g_free (priv->title); diff -Nru fwupd-1.4.5/libfwupd/fwupd-remote.h fwupd-1.5.8/libfwupd/fwupd-remote.h --- fwupd-1.4.5/libfwupd/fwupd-remote.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupd/fwupd-remote.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -60,24 +60,29 @@ const gchar *fwupd_remote_get_filename_source (FwupdRemote *self); const gchar *fwupd_remote_get_firmware_base_uri (FwupdRemote *self); const gchar *fwupd_remote_get_report_uri (FwupdRemote *self); +const gchar *fwupd_remote_get_security_report_uri (FwupdRemote *self); const gchar *fwupd_remote_get_metadata_uri (FwupdRemote *self); const gchar *fwupd_remote_get_metadata_uri_sig (FwupdRemote *self); gboolean fwupd_remote_get_enabled (FwupdRemote *self); gboolean fwupd_remote_get_approval_required (FwupdRemote *self); gboolean fwupd_remote_get_automatic_reports (FwupdRemote *self); +gboolean fwupd_remote_get_automatic_security_reports (FwupdRemote *self); gint fwupd_remote_get_priority (FwupdRemote *self); guint64 fwupd_remote_get_age (FwupdRemote *self); FwupdRemoteKind fwupd_remote_get_kind (FwupdRemote *self); FwupdKeyringKind fwupd_remote_get_keyring_kind (FwupdRemote *self); gchar *fwupd_remote_build_firmware_uri (FwupdRemote *self, const gchar *url, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fwupd_remote_load_signature (FwupdRemote *self, const gchar *filename, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fwupd_remote_load_signature_bytes (FwupdRemote *self, GBytes *bytes, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; FwupdRemote *fwupd_remote_from_variant (GVariant *value); GPtrArray *fwupd_remote_array_from_variant (GVariant *value); diff -Nru fwupd-1.4.5/libfwupd/fwupd-remote-private.h fwupd-1.5.8/libfwupd/fwupd-remote-private.h --- fwupd-1.4.5/libfwupd/fwupd-remote-private.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupd/fwupd-remote-private.h 2021-03-31 20:08:32.000000000 +0000 @@ -26,4 +26,7 @@ void fwupd_remote_set_remotes_dir (FwupdRemote *self, const gchar *directory); +void fwupd_remote_set_keyring_kind (FwupdRemote *self, + FwupdKeyringKind keyring_kind); + G_END_DECLS diff -Nru fwupd-1.4.5/libfwupd/fwupd-security-attr.c fwupd-1.5.8/libfwupd/fwupd-security-attr.c --- fwupd-1.4.5/libfwupd/fwupd-security-attr.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupd/fwupd-security-attr.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,936 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include + +#include "fwupd-common-private.h" +#include "fwupd-enums-private.h" +#include "fwupd-security-attr-private.h" + +/** + * SECTION:fwupd-security-attr + * + * An object that represents an Host Security ID attribute. + */ + +static void fwupd_security_attr_finalize (GObject *object); + +typedef struct { + gchar *appstream_id; + GPtrArray *obsoletes; + GHashTable *metadata; /* (nullable) */ + gchar *name; + gchar *plugin; + gchar *url; + FwupdSecurityAttrLevel level; + FwupdSecurityAttrResult result; + FwupdSecurityAttrFlags flags; +} FwupdSecurityAttrPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (FwupdSecurityAttr, fwupd_security_attr, G_TYPE_OBJECT) +#define GET_PRIVATE(o) (fwupd_security_attr_get_instance_private (o)) + +/** + * fwupd_security_attr_flag_to_string: + * @flag: A #FwupdSecurityAttrFlags, e.g. %FWUPD_SECURITY_ATTR_FLAG_SUCCESS + * + * Returns the printable string for the flag. + * + * Returns: string, or %NULL + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_security_attr_flag_to_string (FwupdSecurityAttrFlags flag) +{ + if (flag == FWUPD_SECURITY_ATTR_FLAG_NONE) + return "none"; + if (flag == FWUPD_SECURITY_ATTR_FLAG_SUCCESS) + return "success"; + if (flag == FWUPD_SECURITY_ATTR_FLAG_OBSOLETED) + return "obsoleted"; + if (flag == FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES) + return "runtime-updates"; + if (flag == FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION) + return "runtime-attestation"; + if (flag == FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE) + return "runtime-issue"; + return NULL; +} + +/** + * fwupd_security_attr_result_to_string: + * @result: A #FwupdSecurityAttrResult, e.g. %FWUPD_SECURITY_ATTR_RESULT_ENABLED + * + * Returns the printable string for the result enum. + * + * Returns: string, or %NULL + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_security_attr_result_to_string (FwupdSecurityAttrResult result) +{ + if (result == FWUPD_SECURITY_ATTR_RESULT_VALID) + return "valid"; + if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_VALID) + return "not-valid"; + if (result == FWUPD_SECURITY_ATTR_RESULT_ENABLED) + return "enabled"; + if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED) + return "not-enabled"; + if (result == FWUPD_SECURITY_ATTR_RESULT_LOCKED) + return "locked"; + if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED) + return "not-locked"; + if (result == FWUPD_SECURITY_ATTR_RESULT_ENCRYPTED) + return "encrypted"; + if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_ENCRYPTED) + return "not-encrypted"; + if (result == FWUPD_SECURITY_ATTR_RESULT_TAINTED) + return "tainted"; + if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_TAINTED) + return "not-tainted"; + if (result == FWUPD_SECURITY_ATTR_RESULT_FOUND) + return "found"; + if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND) + return "not-found"; + if (result == FWUPD_SECURITY_ATTR_RESULT_SUPPORTED) + return "supported"; + if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED) + return "not-supported"; + return NULL; +} + +/** + * fwupd_security_attr_flag_to_suffix: + * @flag: A #FwupdSecurityAttrFlags, e.g. %FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES + * + * Returns the string suffix for the flag. + * + * Returns: string, or %NULL + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_security_attr_flag_to_suffix (FwupdSecurityAttrFlags flag) +{ + if (flag == FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES) + return "U"; + if (flag == FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION) + return "A"; + if (flag == FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE) + return "!"; + return NULL; +} + +/** + * fwupd_security_attr_get_obsoletes: + * @self: A #FwupdSecurityAttr + * + * Gets the list of attribute obsoletes. The obsoleted attributes will not + * contribute to the calculated HSI value or be visible in command line tools. + * + * Returns: (element-type utf8) (transfer none): the obsoletes, which may be empty + * + * Since: 1.5.0 + **/ +GPtrArray * +fwupd_security_attr_get_obsoletes (FwupdSecurityAttr *self) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), NULL); + return priv->obsoletes; +} + +/** + * fwupd_security_attr_add_obsolete: + * @self: A #FwupdSecurityAttr + * @appstream_id: the appstream_id or plugin name + * + * Adds an attribute appstream_id to obsolete. The obsoleted attribute will not + * contribute to the calculated HSI value or be visible in command line tools. + * + * Since: 1.5.0 + **/ +void +fwupd_security_attr_add_obsolete (FwupdSecurityAttr *self, const gchar *appstream_id) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); + g_return_if_fail (appstream_id != NULL); + if (fwupd_security_attr_has_obsolete (self, appstream_id)) + return; + g_ptr_array_add (priv->obsoletes, g_strdup (appstream_id)); +} + +/** + * fwupd_security_attr_has_obsolete: + * @self: A #FwupdSecurityAttr + * @appstream_id: the attribute appstream_id + * + * Finds out if the attribute obsoletes a specific appstream_id. + * + * Returns: %TRUE if the self matches + * + * Since: 1.5.0 + **/ +gboolean +fwupd_security_attr_has_obsolete (FwupdSecurityAttr *self, const gchar *appstream_id) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), FALSE); + g_return_val_if_fail (appstream_id != NULL, FALSE); + for (guint i = 0; i < priv->obsoletes->len; i++) { + const gchar *obsolete_tmp = g_ptr_array_index (priv->obsoletes, i); + if (g_strcmp0 (obsolete_tmp, appstream_id) == 0) + return TRUE; + } + return FALSE; +} + +/** + * fwupd_security_attr_get_appstream_id: + * @self: A #FwupdSecurityAttr + * + * Gets the AppStream ID. + * + * Returns: the AppStream ID, or %NULL if unset + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_security_attr_get_appstream_id (FwupdSecurityAttr *self) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), NULL); + return priv->appstream_id; +} + +/** + * fwupd_security_attr_set_appstream_id: + * @self: A #FwupdSecurityAttr + * @appstream_id: the AppStream component ID, e.g. `com.intel.BiosGuard` + * + * Sets the AppStream ID. + * + * Since: 1.5.0 + **/ +void +fwupd_security_attr_set_appstream_id (FwupdSecurityAttr *self, const gchar *appstream_id) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); + + /* not changed */ + if (g_strcmp0 (priv->appstream_id, appstream_id) == 0) + return; + + /* sanity check */ + if (!g_str_has_prefix (appstream_id, "org.fwupd.hsi.")) + g_critical ("HSI attributes need to have a 'org.fwupd.hsi.' prefix"); + + g_free (priv->appstream_id); + priv->appstream_id = g_strdup (appstream_id); +} + +/** + * fwupd_security_attr_get_url: + * @self: A #FwupdSecurityAttr + * + * Gets the attribute URL. + * + * Returns: the attribute result, or %NULL if unset + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_security_attr_get_url (FwupdSecurityAttr *self) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), NULL); + return priv->url; +} + +/** + * fwupd_security_attr_set_name: + * @self: A #FwupdSecurityAttr + * @name: the attribute name + * + * Sets the attribute name. + * + * Since: 1.5.0 + **/ +void +fwupd_security_attr_set_name (FwupdSecurityAttr *self, const gchar *name) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); + + /* not changed */ + if (g_strcmp0 (priv->name, name) == 0) + return; + + g_free (priv->name); + priv->name = g_strdup (name); +} + +/** + * fwupd_security_attr_set_plugin: + * @self: A #FwupdSecurityAttr + * @plugin: the plugin name + * + * Sets the plugin that created the attribute. + * + * Since: 1.5.0 + **/ +void +fwupd_security_attr_set_plugin (FwupdSecurityAttr *self, const gchar *plugin) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); + + /* not changed */ + if (g_strcmp0 (priv->plugin, plugin) == 0) + return; + + g_free (priv->plugin); + priv->plugin = g_strdup (plugin); +} + +/** + * fwupd_security_attr_set_url: + * @self: A #FwupdSecurityAttr + * @url: the attribute URL + * + * Sets the attribute result. + * + * Since: 1.5.0 + **/ +void +fwupd_security_attr_set_url (FwupdSecurityAttr *self, const gchar *url) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); + + /* not changed */ + if (g_strcmp0 (priv->url, url) == 0) + return; + + g_free (priv->url); + priv->url = g_strdup (url); +} + +/** + * fwupd_security_attr_get_name: + * @self: A #FwupdSecurityAttr + * + * Gets the attribute name. + * + * Returns: the attribute name, or %NULL if unset + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_security_attr_get_name (FwupdSecurityAttr *self) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), NULL); + return priv->name; +} + +/** + * fwupd_security_attr_get_plugin: + * @self: A #FwupdSecurityAttr + * + * Gets the plugin that created the attribute. + * + * Returns: the plugin name, or %NULL if unset + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_security_attr_get_plugin (FwupdSecurityAttr *self) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), NULL); + return priv->plugin; +} + +/** + * fwupd_security_attr_get_flags: + * @self: A #FwupdSecurityAttr + * + * Gets the self flags. + * + * Returns: the self flags, or 0 if unset + * + * Since: 1.5.0 + **/ +FwupdSecurityAttrFlags +fwupd_security_attr_get_flags (FwupdSecurityAttr *self) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), 0); + return priv->flags; +} + +/** + * fwupd_security_attr_set_flags: + * @self: A #FwupdSecurityAttr + * @flags: the self flags, e.g. %FWUPD_SECURITY_ATTR_FLAG_OBSOLETED + * + * Sets the self flags. + * + * Since: 1.5.0 + **/ +void +fwupd_security_attr_set_flags (FwupdSecurityAttr *self, FwupdSecurityAttrFlags flags) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); + priv->flags = flags; +} + +/** + * fwupd_security_attr_add_flag: + * @self: A #FwupdSecurityAttr + * @flag: the #FwupdSecurityAttrFlags + * + * Adds a specific self flag to the self. + * + * Since: 1.5.0 + **/ +void +fwupd_security_attr_add_flag (FwupdSecurityAttr *self, FwupdSecurityAttrFlags flag) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); + priv->flags |= flag; +} + +/** + * fwupd_security_attr_has_flag: + * @self: A #FwupdSecurityAttr + * @flag: the #FwupdSecurityAttrFlags + * + * Finds if the self has a specific self flag. + * + * Returns: %TRUE if the flag is set + * + * Since: 1.5.0 + **/ +gboolean +fwupd_security_attr_has_flag (FwupdSecurityAttr *self, FwupdSecurityAttrFlags flag) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), FALSE); + return (priv->flags & flag) > 0; +} + +/** + * fwupd_security_attr_get_level: + * @self: A #FwupdSecurityAttr + * + * Gets the HSI level. + * + * Returns: the #FwupdSecurityAttrLevel, or %FWUPD_SECURITY_ATTR_LEVEL_NONE if unset + * + * Since: 1.5.0 + **/ +FwupdSecurityAttrLevel +fwupd_security_attr_get_level (FwupdSecurityAttr *self) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), 0); + return priv->level; +} + +/** + * fwupd_security_attr_set_level: + * @self: A #FwupdSecurityAttr + * @level: A #FwupdSecurityAttrLevel, e.g. %FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT + * + * Sets the HSI level. A @level of %FWUPD_SECURITY_ATTR_LEVEL_NONE is not used + * for the HSI calculation. + * + * Since: 1.5.0 + **/ +void +fwupd_security_attr_set_level (FwupdSecurityAttr *self, FwupdSecurityAttrLevel level) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); + priv->level = level; +} + +/** + * fwupd_security_attr_set_result: + * @self: A #FwupdSecurityAttr + * @result: A #FwupdSecurityAttrResult, e.g. %FWUPD_SECURITY_ATTR_LEVEL_LOCKED + * + * Sets the optional HSI result. This is required because some attributes may + * be a "success" when something is `locked` or may be "failed" if `found`. + * + * Since: 1.5.0 + **/ +void +fwupd_security_attr_set_result (FwupdSecurityAttr *self, FwupdSecurityAttrResult result) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); + priv->result = result; +} + +/** + * fwupd_security_attr_get_result: + * @self: A #FwupdSecurityAttr + * + * Gets the optional HSI result. + * + * Returns: the #FwupdSecurityAttrResult, e.g %FWUPD_SECURITY_ATTR_LEVEL_LOCKED + * + * Since: 1.5.0 + **/ +FwupdSecurityAttrResult +fwupd_security_attr_get_result (FwupdSecurityAttr *self) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), 0); + return priv->result; +} + +/** + * fwupd_security_attr_to_variant: + * @self: A #FwupdSecurityAttr + * + * Creates a GVariant from the self data. + * + * Returns: the GVariant, or %NULL for error + * + * Since: 1.5.0 + **/ +GVariant * +fwupd_security_attr_to_variant (FwupdSecurityAttr *self) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + GVariantBuilder builder; + + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), NULL); + + g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); + if (priv->appstream_id != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_APPSTREAM_ID, + g_variant_new_string (priv->appstream_id)); + } + if (priv->name != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_NAME, + g_variant_new_string (priv->name)); + } + if (priv->url != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_URI, + g_variant_new_string (priv->url)); + } + if (priv->obsoletes->len > 0) { + g_autofree const gchar **strv = g_new0 (const gchar *, priv->obsoletes->len + 1); + for (guint i = 0; i < priv->obsoletes->len; i++) + strv[i] = (const gchar *) g_ptr_array_index (priv->obsoletes, i); + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_CATEGORIES, + g_variant_new_strv (strv, -1)); + } + if (priv->flags != 0) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_FLAGS, + g_variant_new_uint64 (priv->flags)); + } + if (priv->level > 0) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_HSI_LEVEL, + g_variant_new_uint32 (priv->level)); + } + if (priv->result != FWUPD_SECURITY_ATTR_RESULT_UNKNOWN) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_HSI_RESULT, + g_variant_new_uint32 (priv->result)); + } + if (priv->metadata != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_METADATA, + fwupd_hash_kv_to_variant (priv->metadata)); + } + return g_variant_new ("a{sv}", &builder); +} + +/** + * fwupd_security_attr_get_metadata: + * @self: A #FwupdSecurityAttr + * @key: metadata key + * + * Gets private metadata from the attribute which may be used in the name. + * + * Returns: (nullable): the metadata value, or %NULL if unfound + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_security_attr_get_metadata (FwupdSecurityAttr *self, const gchar *key) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), NULL); + g_return_val_if_fail (key != NULL, NULL); + + if (priv->metadata == NULL) + return NULL; + return g_hash_table_lookup (priv->metadata, key); +} + +/** + * fwupd_security_attr_add_metadata: + * @self: A #FwupdSecurityAttr + * @key: metadata key + * @value: (nullable): metadata value + * + * Adds metadata to the attribute which may be used in the name. + * + * Since: 1.5.0 + **/ +void +fwupd_security_attr_add_metadata (FwupdSecurityAttr *self, + const gchar *key, + const gchar *value) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); + g_return_if_fail (key != NULL); + + if (priv->metadata == NULL) { + priv->metadata = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_free); + } + g_hash_table_insert (priv->metadata, g_strdup (key), g_strdup (value)); +} + +static void +fwupd_security_attr_from_key_value (FwupdSecurityAttr *self, const gchar *key, GVariant *value) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + + if (g_strcmp0 (key, FWUPD_RESULT_KEY_APPSTREAM_ID) == 0) { + fwupd_security_attr_set_appstream_id (self, g_variant_get_string (value, NULL)); + return; + } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_NAME) == 0) { + fwupd_security_attr_set_name (self, g_variant_get_string (value, NULL)); + return; + } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_URI) == 0) { + fwupd_security_attr_set_url (self, g_variant_get_string (value, NULL)); + return; + } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_FLAGS) == 0) { + fwupd_security_attr_set_flags (self, g_variant_get_uint64 (value)); + return; + } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_HSI_LEVEL) == 0) { + fwupd_security_attr_set_level (self, g_variant_get_uint32 (value)); + return; + } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_HSI_RESULT) == 0) { + fwupd_security_attr_set_result (self, g_variant_get_uint32 (value)); + return; + } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_METADATA) == 0) { + if (priv->metadata != NULL) + g_hash_table_unref (priv->metadata); + priv->metadata = fwupd_variant_to_hash_kv (value); + return; + } +} + +static void +fwupd_pad_kv_str (GString *str, const gchar *key, const gchar *value) +{ + /* ignore */ + if (key == NULL || value == NULL) + return; + g_string_append_printf (str, " %s: ", key); + for (gsize i = strlen (key); i < 20; i++) + g_string_append (str, " "); + g_string_append_printf (str, "%s\n", value); +} + +static void +fwupd_pad_kv_tfl (GString *str, const gchar *key, FwupdSecurityAttrFlags security_attr_flags) +{ + g_autoptr(GString) tmp = g_string_new (""); + for (guint i = 0; i < 64; i++) { + if ((security_attr_flags & ((guint64) 1 << i)) == 0) + continue; + g_string_append_printf (tmp, "%s|", + fwupd_security_attr_flag_to_string ((guint64) 1 << i)); + } + if (tmp->len == 0) { + g_string_append (tmp, fwupd_security_attr_flag_to_string (0)); + } else { + g_string_truncate (tmp, tmp->len - 1); + } + fwupd_pad_kv_str (str, key, tmp->str); +} + +static void +fwupd_pad_kv_int (GString *str, const gchar *key, guint32 value) +{ + g_autofree gchar *tmp = NULL; + + /* ignore */ + if (value == 0) + return; + tmp = g_strdup_printf("%" G_GUINT32_FORMAT, value); + fwupd_pad_kv_str (str, key, tmp); +} + +static void +fwupd_security_attr_json_add_string (JsonBuilder *builder, const gchar *key, const gchar *str) +{ + if (str == NULL) + return; + json_builder_set_member_name (builder, key); + json_builder_add_string_value (builder, str); +} + +static void +fwupd_security_attr_json_add_int (JsonBuilder *builder, const gchar *key, guint64 num) +{ + if (num == 0) + return; + json_builder_set_member_name (builder, key); + json_builder_add_int_value (builder, num); +} + +/** + * fwupd_security_attr_to_json: + * @self: A #FwupdSecurityAttr + * @builder: A #JsonBuilder + * + * Adds a fwupd self to a JSON builder + * + * Since: 1.5.0 + **/ +void +fwupd_security_attr_to_json (FwupdSecurityAttr *self, JsonBuilder *builder) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); + g_return_if_fail (builder != NULL); + + fwupd_security_attr_json_add_string (builder, FWUPD_RESULT_KEY_APPSTREAM_ID, priv->appstream_id); + fwupd_security_attr_json_add_int (builder, FWUPD_RESULT_KEY_HSI_LEVEL, priv->level); + fwupd_security_attr_json_add_string (builder, FWUPD_RESULT_KEY_HSI_RESULT, + fwupd_security_attr_result_to_string (priv->result)); + fwupd_security_attr_json_add_string (builder, FWUPD_RESULT_KEY_NAME, priv->name); + fwupd_security_attr_json_add_string (builder, FWUPD_RESULT_KEY_PLUGIN, priv->plugin); + fwupd_security_attr_json_add_string (builder, FWUPD_RESULT_KEY_URI, priv->url); + if (priv->flags != FWUPD_SECURITY_ATTR_FLAG_NONE) { + json_builder_set_member_name (builder, FWUPD_RESULT_KEY_FLAGS); + json_builder_begin_array (builder); + for (guint i = 0; i < 64; i++) { + const gchar *tmp; + if ((priv->flags & ((guint64) 1 << i)) == 0) + continue; + tmp = fwupd_security_attr_flag_to_string ((guint64) 1 << i); + json_builder_add_string_value (builder, tmp); + } + json_builder_end_array (builder); + } + if (priv->metadata != NULL) { + g_autoptr(GList) keys = g_hash_table_get_keys (priv->metadata); + for (GList *l = keys; l != NULL; l = l->next) { + const gchar *key = l->data; + const gchar *value = g_hash_table_lookup (priv->metadata, key); + fwupd_security_attr_json_add_string (builder, key, value); + } + } +} + +/** + * fwupd_security_attr_to_string: + * @self: A #FwupdSecurityAttr + * + * Builds a text representation of the object. + * + * Returns: text, or %NULL for invalid + * + * Since: 1.5.0 + **/ +gchar * +fwupd_security_attr_to_string (FwupdSecurityAttr *self) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + GString *str; + + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), NULL); + + str = g_string_new (""); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_APPSTREAM_ID, priv->appstream_id); + fwupd_pad_kv_int (str, FWUPD_RESULT_KEY_HSI_LEVEL, priv->level); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_HSI_RESULT, + fwupd_security_attr_result_to_string (priv->result)); + if (priv->flags != FWUPD_SECURITY_ATTR_FLAG_NONE) + fwupd_pad_kv_tfl (str, FWUPD_RESULT_KEY_FLAGS, priv->flags); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_NAME, priv->name); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_PLUGIN, priv->plugin); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_URI, priv->url); + for (guint i = 0; i < priv->obsoletes->len; i++) { + const gchar *appstream_id = g_ptr_array_index (priv->obsoletes, i); + fwupd_pad_kv_str (str, "Obsolete", appstream_id); + } + if (priv->metadata != NULL) { + g_autoptr(GList) keys = g_hash_table_get_keys (priv->metadata); + for (GList *l = keys; l != NULL; l = l->next) { + const gchar *key = l->data; + const gchar *value = g_hash_table_lookup (priv->metadata, key); + fwupd_pad_kv_str (str, key, value); + } + } + + return g_string_free (str, FALSE); +} + +static void +fwupd_security_attr_class_init (FwupdSecurityAttrClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fwupd_security_attr_finalize; +} + +static void +fwupd_security_attr_init (FwupdSecurityAttr *self) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + priv->obsoletes = g_ptr_array_new_with_free_func (g_free); +} + +static void +fwupd_security_attr_finalize (GObject *object) +{ + FwupdSecurityAttr *self = FWUPD_SECURITY_ATTR (object); + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + + if (priv->metadata != NULL) + g_hash_table_unref (priv->metadata); + g_free (priv->appstream_id); + g_free (priv->name); + g_free (priv->plugin); + g_free (priv->url); + g_ptr_array_unref (priv->obsoletes); + + G_OBJECT_CLASS (fwupd_security_attr_parent_class)->finalize (object); +} + +static void +fwupd_security_attr_set_from_variant_iter (FwupdSecurityAttr *self, GVariantIter *iter) +{ + GVariant *value; + const gchar *key; + while (g_variant_iter_next (iter, "{&sv}", &key, &value)) { + fwupd_security_attr_from_key_value (self, key, value); + g_variant_unref (value); + } +} + +/** + * fwupd_security_attr_from_variant: + * @value: a #GVariant + * + * Creates a new self using packed data. + * + * Returns: (transfer full): a new #FwupdSecurityAttr, or %NULL if @value was invalid + * + * Since: 1.5.0 + **/ +FwupdSecurityAttr * +fwupd_security_attr_from_variant (GVariant *value) +{ + FwupdSecurityAttr *rel = NULL; + const gchar *type_string; + g_autoptr(GVariantIter) iter = NULL; + + type_string = g_variant_get_type_string (value); + if (g_strcmp0 (type_string, "(a{sv})") == 0) { + rel = fwupd_security_attr_new (NULL); + g_variant_get (value, "(a{sv})", &iter); + fwupd_security_attr_set_from_variant_iter (rel, iter); + } else if (g_strcmp0 (type_string, "a{sv}") == 0) { + rel = fwupd_security_attr_new (NULL); + g_variant_get (value, "a{sv}", &iter); + fwupd_security_attr_set_from_variant_iter (rel, iter); + } else { + g_warning ("type %s not known", type_string); + } + return rel; +} + +/** + * fwupd_security_attr_array_from_variant: + * @value: a #GVariant + * + * Creates an array of new security_attrs using packed data. + * + * Returns: (transfer container) (element-type FwupdSecurityAttr): attributes, or %NULL if @value was invalid + * + * Since: 1.5.0 + **/ +GPtrArray * +fwupd_security_attr_array_from_variant (GVariant *value) +{ + GPtrArray *array = NULL; + gsize sz; + g_autoptr(GVariant) untuple = NULL; + + array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + untuple = g_variant_get_child_value (value, 0); + sz = g_variant_n_children (untuple); + for (guint i = 0; i < sz; i++) { + FwupdSecurityAttr *rel; + g_autoptr(GVariant) data = NULL; + data = g_variant_get_child_value (untuple, i); + rel = fwupd_security_attr_from_variant (data); + if (rel == NULL) + continue; + g_ptr_array_add (array, rel); + } + return array; +} + +/** + * fwupd_security_attr_new: + * @appstream_id: (allow-none): the AppStream component ID, e.g. `com.intel.BiosGuard` + * + * Creates a new self. + * + * Returns: a new #FwupdSecurityAttr + * + * Since: 1.5.0 + **/ +FwupdSecurityAttr * +fwupd_security_attr_new (const gchar *appstream_id) +{ + FwupdSecurityAttr *self; + self = g_object_new (FWUPD_TYPE_SECURITY_ATTR, NULL); + if (appstream_id != NULL) + fwupd_security_attr_set_appstream_id (self, appstream_id); + return FWUPD_SECURITY_ATTR (self); +} diff -Nru fwupd-1.4.5/libfwupd/fwupd-security-attr.h fwupd-1.5.8/libfwupd/fwupd-security-attr.h --- fwupd-1.4.5/libfwupd/fwupd-security-attr.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupd/fwupd-security-attr.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#include "fwupd-enums.h" + +G_BEGIN_DECLS + +#define FWUPD_TYPE_SECURITY_ATTR (fwupd_security_attr_get_type ()) +G_DECLARE_DERIVABLE_TYPE (FwupdSecurityAttr, fwupd_security_attr, FWUPD, SECURITY_ATTR, GObject) + +struct _FwupdSecurityAttrClass +{ + GObjectClass parent_class; + /*< private >*/ + void (*_fwupd_reserved1) (void); + void (*_fwupd_reserved2) (void); + void (*_fwupd_reserved3) (void); + void (*_fwupd_reserved4) (void); + void (*_fwupd_reserved5) (void); + void (*_fwupd_reserved6) (void); + void (*_fwupd_reserved7) (void); +}; + + +/** + * FwupdSecurityAttrFlags: + * @FWUPD_SECURITY_ATTR_FLAG_NONE: No flags set + * @FWUPD_SECURITY_ATTR_FLAG_SUCCESS: Success + * @FWUPD_SECURITY_ATTR_FLAG_OBSOLETED: Obsoleted by another attribute + * @FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES: Suffix `U` + * @FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION: Suffix `A` + * @FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE: Suffix `!` + * + * The flags available for HSI attributes. + **/ +typedef enum { + FWUPD_SECURITY_ATTR_FLAG_NONE = 0, + FWUPD_SECURITY_ATTR_FLAG_SUCCESS = 1 << 0, + FWUPD_SECURITY_ATTR_FLAG_OBSOLETED = 1 << 1, + FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES = 1 << 8, + FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION = 1 << 9, + FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE = 1 << 10, +} FwupdSecurityAttrFlags; + +/** + * FwupdSecurityAttrLevel: + * @FWUPD_SECURITY_ATTR_LEVEL_NONE: Very few detected firmware protections + * @FWUPD_SECURITY_ATTR_LEVEL_CRITICAL: The most basic of security protections + * @FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT: Firmware security issues considered important + * @FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL: Firmware security issues that pose a theoretical concern + * @FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_PROTECTION: Out-of-band protection of the system firmware + * @FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_ATTESTATION: Out-of-band attestation of the system firmware + * + * The HSI level. + **/ +typedef enum { + FWUPD_SECURITY_ATTR_LEVEL_NONE = 0, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_LEVEL_CRITICAL = 1, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT = 2, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL = 3, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_PROTECTION = 4, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_ATTESTATION = 5, /* Since: 1.5.0 */ + /*< private >*/ + FWUPD_SECURITY_ATTR_LEVEL_LAST = 6 /* perhaps increased in the future */ +} FwupdSecurityAttrLevel; + +/** + * FwupdSecurityAttrResult: + * @FWUPD_SECURITY_ATTR_RESULT_UNKNOWN: Not known + * @FWUPD_SECURITY_ATTR_RESULT_ENABLED: Enabled + * @FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED: Not enabled + * @FWUPD_SECURITY_ATTR_RESULT_VALID: Valid + * @FWUPD_SECURITY_ATTR_RESULT_NOT_VALID: Not valid + * @FWUPD_SECURITY_ATTR_RESULT_LOCKED: Locked + * @FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED: Not locked + * @FWUPD_SECURITY_ATTR_RESULT_ENCRYPTED: Encrypted + * @FWUPD_SECURITY_ATTR_RESULT_NOT_ENCRYPTED: Not encrypted + * @FWUPD_SECURITY_ATTR_RESULT_TAINTED: Tainted + * @FWUPD_SECURITY_ATTR_RESULT_NOT_TAINTED: Not tainted + * @FWUPD_SECURITY_ATTR_RESULT_FOUND: Found + * @FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND: NOt found + * @FWUPD_SECURITY_ATTR_RESULT_SUPPORTED: Supported + * @FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED: Not supported + * + * The HSI result. + **/ +typedef enum { + FWUPD_SECURITY_ATTR_RESULT_UNKNOWN, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_RESULT_ENABLED, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_RESULT_VALID, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_RESULT_NOT_VALID, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_RESULT_LOCKED, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_RESULT_ENCRYPTED, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_RESULT_NOT_ENCRYPTED, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_RESULT_TAINTED, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_RESULT_NOT_TAINTED, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_RESULT_FOUND, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_RESULT_SUPPORTED, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED, /* Since: 1.5.0 */ + /*< private >*/ + FWUPD_SECURITY_ATTR_RESULT_LAST +} FwupdSecurityAttrResult; + +FwupdSecurityAttr *fwupd_security_attr_new (const gchar *appstream_id); +gchar *fwupd_security_attr_to_string (FwupdSecurityAttr *self); + +const gchar *fwupd_security_attr_get_appstream_id (FwupdSecurityAttr *self); +void fwupd_security_attr_set_appstream_id (FwupdSecurityAttr *self, + const gchar *appstream_id); +FwupdSecurityAttrLevel fwupd_security_attr_get_level (FwupdSecurityAttr *self); +void fwupd_security_attr_set_level (FwupdSecurityAttr *self, + FwupdSecurityAttrLevel level); +FwupdSecurityAttrResult fwupd_security_attr_get_result (FwupdSecurityAttr *self); +void fwupd_security_attr_set_result (FwupdSecurityAttr *self, + FwupdSecurityAttrResult result); +const gchar *fwupd_security_attr_get_name (FwupdSecurityAttr *self); +void fwupd_security_attr_set_name (FwupdSecurityAttr *self, + const gchar *name); +const gchar *fwupd_security_attr_get_plugin (FwupdSecurityAttr *self); +void fwupd_security_attr_set_plugin (FwupdSecurityAttr *self, + const gchar *plugin); +const gchar *fwupd_security_attr_get_url (FwupdSecurityAttr *self); +void fwupd_security_attr_set_url (FwupdSecurityAttr *self, + const gchar *url); +GPtrArray *fwupd_security_attr_get_obsoletes (FwupdSecurityAttr *self); +void fwupd_security_attr_add_obsolete (FwupdSecurityAttr *self, + const gchar *appstream_id); +gboolean fwupd_security_attr_has_obsolete (FwupdSecurityAttr *self, + const gchar *appstream_id); +const gchar *fwupd_security_attr_get_metadata (FwupdSecurityAttr *self, + const gchar *key); +void fwupd_security_attr_add_metadata (FwupdSecurityAttr *self, + const gchar *key, + const gchar *value); +FwupdSecurityAttrFlags fwupd_security_attr_get_flags (FwupdSecurityAttr *self); +void fwupd_security_attr_set_flags (FwupdSecurityAttr *self, + FwupdSecurityAttrFlags flags); +void fwupd_security_attr_add_flag (FwupdSecurityAttr *self, + FwupdSecurityAttrFlags flag); +gboolean fwupd_security_attr_has_flag (FwupdSecurityAttr *self, + FwupdSecurityAttrFlags flag); +const gchar *fwupd_security_attr_flag_to_string (FwupdSecurityAttrFlags flag); +const gchar *fwupd_security_attr_flag_to_suffix (FwupdSecurityAttrFlags flag); +const gchar *fwupd_security_attr_result_to_string (FwupdSecurityAttrResult result); + +FwupdSecurityAttr *fwupd_security_attr_from_variant (GVariant *value); +GPtrArray *fwupd_security_attr_array_from_variant (GVariant *value); + +G_END_DECLS diff -Nru fwupd-1.4.5/libfwupd/fwupd-security-attr-private.h fwupd-1.5.8/libfwupd/fwupd-security-attr-private.h --- fwupd-1.4.5/libfwupd/fwupd-security-attr-private.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupd/fwupd-security-attr-private.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include +#include + +#include "fwupd-security-attr.h" + +G_BEGIN_DECLS + +#define FWUPD_SECURITY_ATTR_ID_ACPI_DMAR "org.fwupd.hsi.AcpiDmar" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_ENCRYPTED_RAM "org.fwupd.hsi.EncryptedRam" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_FWUPD_ATTESTATION "org.fwupd.hsi.Fwupd.Attestation" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_FWUPD_PLUGINS "org.fwupd.hsi.Fwupd.Plugins" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_FWUPD_UPDATES "org.fwupd.hsi.Fwupd.Updates" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ENABLED "org.fwupd.hsi.IntelBootguard.Enabled" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_VERIFIED "org.fwupd.hsi.IntelBootguard.Verified" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ACM "org.fwupd.hsi.IntelBootguard.Acm" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_POLICY "org.fwupd.hsi.IntelBootguard.Policy" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_OTP "org.fwupd.hsi.IntelBootguard.Otp" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_CET_ENABLED "org.fwupd.hsi.IntelCet.Enabled" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_CET_ACTIVE "org.fwupd.hsi.IntelCet.Active" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_SMAP "org.fwupd.hsi.IntelSmap" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_IOMMU "org.fwupd.hsi.Iommu" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_KERNEL_LOCKDOWN "org.fwupd.hsi.Kernel.Lockdown" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_KERNEL_SWAP "org.fwupd.hsi.Kernel.Swap" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_KERNEL_TAINTED "org.fwupd.hsi.Kernel.Tainted" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_MEI_MANUFACTURING_MODE "org.fwupd.hsi.Mei.ManufacturingMode" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_MEI_OVERRIDE_STRAP "org.fwupd.hsi.Mei.OverrideStrap" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_MEI_VERSION "org.fwupd.hsi.Mei.Version" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_SPI_BIOSWE "org.fwupd.hsi.Spi.Bioswe" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_SPI_BLE "org.fwupd.hsi.Spi.Ble" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_SPI_SMM_BWP "org.fwupd.hsi.Spi.SmmBwp" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_IDLE "org.fwupd.hsi.SuspendToIdle" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_RAM "org.fwupd.hsi.SuspendToRam" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_TPM_RECONSTRUCTION_PCR0 "org.fwupd.hsi.Tpm.ReconstructionPcr0" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_TPM_VERSION_20 "org.fwupd.hsi.Tpm.Version20" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT "org.fwupd.hsi.Uefi.SecureBoot" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_DCI_ENABLED "org.fwupd.hsi.IntelDci.Enabled" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_INTEL_DCI_LOCKED "org.fwupd.hsi.IntelDci.Locked" /* Since: 1.5.0 */ +#define FWUPD_SECURITY_ATTR_ID_UEFI_PK "org.fwupd.hsi.Uefi.Pk" /* Since: 1.5.5 */ + +GVariant *fwupd_security_attr_to_variant (FwupdSecurityAttr *self); +void fwupd_security_attr_to_json (FwupdSecurityAttr *self, + JsonBuilder *builder); + +G_END_DECLS + diff -Nru fwupd-1.4.5/libfwupd/fwupd-self-test.c fwupd-1.5.8/libfwupd/fwupd-self-test.c --- fwupd-1.4.5/libfwupd/fwupd-self-test.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupd/fwupd-self-test.c 2021-03-31 20:08:32.000000000 +0000 @@ -7,11 +7,13 @@ #include "config.h" #include +#include #ifdef HAVE_FNMATCH_H #include #endif #include "fwupd-client.h" +#include "fwupd-client-sync.h" #include "fwupd-common.h" #include "fwupd-enums.h" #include "fwupd-error.h" @@ -147,6 +149,12 @@ break; g_assert_cmpint (fwupd_device_flag_from_string (tmp), ==, i); } + for (guint64 i = 1; i < FWUPD_PLUGIN_FLAG_UNKNOWN; i *= 2) { + const gchar *tmp = fwupd_plugin_flag_to_string (i); + if (tmp == NULL) + break; + g_assert_cmpint (fwupd_plugin_flag_from_string (tmp), ==, i); + } } static void @@ -322,7 +330,7 @@ dev = fwupd_device_new (); fwupd_device_add_checksum (dev, "beefdead"); fwupd_device_set_created (dev, 1); - fwupd_device_set_flags (dev, FWUPD_DEVICE_FLAG_UPDATABLE); + fwupd_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); fwupd_device_set_id (dev, "USB:foo"); fwupd_device_set_modified (dev, 60 * 60 * 24); fwupd_device_set_name (dev, "ColorHug2"); @@ -330,7 +338,11 @@ fwupd_device_add_guid (dev, "00000000-0000-0000-0000-000000000000"); fwupd_device_add_icon (dev, "input-gaming"); fwupd_device_add_icon (dev, "input-mouse"); - fwupd_device_add_flag (dev, FWUPD_DEVICE_FLAG_REQUIRE_AC); + fwupd_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE | + FWUPD_DEVICE_FLAG_REQUIRE_AC); + g_assert_true (fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_REQUIRE_AC)); + g_assert_true (fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE)); + g_assert_false (fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_HISTORICAL)); rel = fwupd_release_new (); fwupd_release_add_flag (rel, FWUPD_RELEASE_FLAG_TRUSTED_PAYLOAD); fwupd_release_add_checksum (rel, "deadbeef"); @@ -338,7 +350,8 @@ fwupd_release_set_filename (rel, "firmware.bin"); fwupd_release_set_appstream_id (rel, "org.dave.ColorHug.firmware"); fwupd_release_set_size (rel, 1024); - fwupd_release_set_uri (rel, "http://foo.com"); + fwupd_release_add_location (rel, "http://foo.com"); + fwupd_release_add_location (rel, "ftp://foo.com"); fwupd_release_set_version (rel, "1.2.3"); fwupd_device_add_release (dev, rel); str = fwupd_device_to_string (dev); @@ -372,6 +385,7 @@ " Checksum: SHA1(deadbeef)\n" " Size: 1.0 kB\n" " Uri: http://foo.com\n" + " Uri: ftp://foo.com\n" " Flags: trusted-payload\n", &error); g_assert_no_error (error); g_assert (ret); @@ -418,6 +432,10 @@ " \"deadbeef\"\n" " ],\n" " \"Size\" : 1024,\n" + " \"Locations\" : [\n" + " \"http://foo.com\",\n" + " \"ftp://foo.com\"\n" + " ],\n" " \"Uri\" : \"http://foo.com\",\n" " \"Flags\" : [\n" " \"trusted-payload\"\n" @@ -532,7 +550,6 @@ g_assert_no_error (error); g_assert (remote2 != NULL); g_assert_cmpstr (fwupd_remote_get_id (remote2), ==, "lvfs"); - g_assert (fwupd_remote_get_enabled (remote2)); g_assert (fwupd_remote_get_metadata_uri (remote2) != NULL); /* check we set an error when unfound */ diff -Nru fwupd-1.4.5/libfwupd/fwupd-thread-test.c fwupd-1.5.8/libfwupd/fwupd-thread-test.c --- fwupd-1.4.5/libfwupd/fwupd-thread-test.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupd/fwupd-thread-test.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2020 Philip Withnall + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include + +typedef struct { + GApplication *app; + FwupdClient *client; + GPtrArray *worker_threads; +} FuThreadTestSelf; + +static gboolean +fwupd_thread_test_exit_idle_cb (gpointer user_data) +{ + FuThreadTestSelf *self = user_data; + g_application_release (self->app); + return G_SOURCE_REMOVE; +} + +static gpointer +fwupd_thread_test_thread_cb (gpointer user_data) +{ + FuThreadTestSelf *self = user_data; + g_autoptr(GError) error_local = NULL; + g_autoptr(GPtrArray) devices = NULL; + g_autoptr(GMainContext) context = g_main_context_new (); + g_autoptr(GMainContextPusher) pusher = g_main_context_pusher_new (context); + + g_assert (pusher != NULL); + g_message ("Calling fwupd_client_get_devices() in thread %p with main context %p", + g_thread_self (), g_main_context_get_thread_default ()); + devices = fwupd_client_get_devices (self->client, NULL, &error_local); + if (devices == NULL) + g_warning ("%s", error_local->message); + g_idle_add (fwupd_thread_test_exit_idle_cb, self); + return NULL; +} + +static gboolean +fwupd_thread_test_idle_cb (gpointer user_data) +{ + FuThreadTestSelf *self = user_data; + + g_message ("fwupd_thread_test_idle_cb() in thread %p with main context %p", + g_thread_self (), g_main_context_get_thread_default ()); + + /* create 'n' threads with a small delay, and 'n-1' references on the app */ + for (guint i = 0; i < 30; i++) { + g_autofree gchar *thread_str = g_strdup_printf ("worker%02u", i); + GThread *thread = g_thread_new (thread_str, + fwupd_thread_test_thread_cb, + self); + g_usleep (g_random_int_range (0, 1000)); + g_ptr_array_add (self->worker_threads, thread); + if (i > 0) + g_application_hold (self->app); + } + + return G_SOURCE_REMOVE; +} + +static void +fwupd_thread_test_activate_cb (GApplication *app, gpointer user_data) +{ + FuThreadTestSelf *self = user_data; + g_application_hold (self->app); + g_idle_add (fwupd_thread_test_idle_cb, self); +} + +static gboolean +fwupd_thread_test_has_system_bus (void) +{ + g_autoptr(GDBusConnection) conn = NULL; + conn = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL); + return conn != NULL; +} + +int +main (void) +{ + gint retval; + g_autoptr(FwupdClient) client = fwupd_client_new (); + g_autoptr(GApplication) app = g_application_new ("org.test.Test", G_APPLICATION_FLAGS_NONE); + g_autoptr(GPtrArray) worker_threads = g_ptr_array_new (); + FuThreadTestSelf self = { app, client, worker_threads }; + + /* only some of the CI targets have a DBus daemon */ + if (!fwupd_thread_test_has_system_bus ()) { + g_message ("D-Bus system bus unavailable, skipping tests."); + return 0; + } + + g_message ("Created FwupdClient in thread %p with main context %p", + g_thread_self (), g_main_context_get_thread_default ()); + g_signal_connect (app, "activate", + G_CALLBACK (fwupd_thread_test_activate_cb), &self); + retval = g_application_run (app, 0, NULL); + for (guint i = 0; i < self.worker_threads->len; i++) { + GThread *thread = g_ptr_array_index (self.worker_threads, i); + g_thread_join (thread); + } + + return retval; +} diff -Nru fwupd-1.4.5/libfwupd/meson.build fwupd-1.5.8/libfwupd/meson.build --- fwupd-1.4.5/libfwupd/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupd/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,7 +1,3 @@ -cargs = [ - '-DG_LOG_DOMAIN="Fwupd"', -] - fwupd_version_h = configure_file( input : 'fwupd-version.h.in', output : 'fwupd-version.h', @@ -15,41 +11,55 @@ install_headers([ 'fwupd-client.h', + 'fwupd-client-sync.h', 'fwupd-common.h', 'fwupd-deprecated.h', 'fwupd-device.h', 'fwupd-enums.h', 'fwupd-error.h', 'fwupd-remote.h', + 'fwupd-security-attr.h', 'fwupd-release.h', + 'fwupd-plugin.h', fwupd_version_h, ], subdir : 'fwupd-1/libfwupd', ) +libfwupd_deps = [ + giounix, + gmodule, + libjcat, + libjsonglib, +] + +if get_option('curl') + libfwupd_deps += libcurl +endif + +libfwupd_src = [ + 'fwupd-client.c', + 'fwupd-client-sync.c', + 'fwupd-common.c', # fuzzing + 'fwupd-device.c', # fuzzing + 'fwupd-enums.c', # fuzzing + 'fwupd-error.c', # fuzzing + 'fwupd-security-attr.c', + 'fwupd-release.c', # fuzzing + 'fwupd-plugin.c', + 'fwupd-remote.c', +] + fwupd_mapfile = 'fwupd.map' vflag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), fwupd_mapfile) -fwupd = shared_library( +fwupd = library( 'fwupd', - sources : [ - 'fwupd-client.c', - 'fwupd-common.c', - 'fwupd-device.c', - 'fwupd-enums.c', - 'fwupd-error.c', - 'fwupd-release.c', - 'fwupd-remote.c', - ], + sources : libfwupd_src, soversion : libfwupd_lt_current, version : libfwupd_lt_version, - dependencies : [ - giounix, - soup, - libjcat, - libjsonglib, - ], + dependencies : libfwupd_deps, c_args : [ - cargs, + '-DG_LOG_DOMAIN="Fwupd"', '-DLOCALSTATEDIR="' + localstatedir + '"', ], include_directories : root_incdir, @@ -58,9 +68,15 @@ install : true ) +libfwupd_dep = declare_dependency( + link_with : fwupd, + include_directories : [root_incdir, include_directories('.')], + dependencies : libfwupd_deps +) + pkgg = import('pkgconfig') pkgg.generate( - libraries : fwupd, + fwupd, requires : [ 'gio-2.0' ], subdirs : 'fwupd-1', version : meson.project_version(), @@ -70,10 +86,18 @@ ) if get_option('introspection') + fwupd_gir_deps = [ + giounix, + ] + if get_option('curl') + fwupd_gir_deps += libcurl + endif fwupd_gir = gnome.generate_gir(fwupd, sources : [ 'fwupd-client.c', 'fwupd-client.h', + 'fwupd-client-sync.c', + 'fwupd-client-sync.h', 'fwupd-common.c', 'fwupd-common.h', 'fwupd-common-private.h', @@ -85,9 +109,15 @@ 'fwupd-enums-private.h', 'fwupd-error.c', 'fwupd-error.h', + 'fwupd-security-attr.c', + 'fwupd-security-attr.h', + 'fwupd-security-attr-private.h', 'fwupd-release.c', 'fwupd-release.h', 'fwupd-release-private.h', + 'fwupd-plugin.c', + 'fwupd-plugin.h', + 'fwupd-plugin-private.h', 'fwupd-remote.c', 'fwupd-remote.h', 'fwupd-remote-private.h', @@ -98,21 +128,17 @@ identifier_prefix : 'Fwupd', export_packages : 'fwupd', header : 'fwupd.h', - dependencies : [ - giounix, - soup, - ], + dependencies : fwupd_gir_deps, includes : [ 'Gio-2.0', 'GObject-2.0', - 'Soup-2.4', ], install : true ) gnome.generate_vapi('fwupd', sources : fwupd_gir[0], - packages : ['gio-2.0', 'libsoup-2.4'], + packages : ['gio-2.0'], install : true, ) @@ -155,13 +181,11 @@ root_incdir, ], dependencies : [ - gio, - soup, - libjsonglib, + libfwupd_deps, ], link_with : fwupd, c_args : [ - cargs, + '-DG_LOG_DOMAIN="Fwupd"', '-DLOCALSTATEDIR="' + localstatedir + '"', '-DTESTDATADIR="' + testdatadir + '"', '-DFU_SELF_TEST_REMOTES_DIR="' + testdatadir + '"', @@ -169,6 +193,42 @@ ], ) test('fwupd-self-test', e, timeout: 60) + if gio.version().version_compare ('>= 2.64.0') + e = executable( + 'fwupd-thread-test', + sources : [ + 'fwupd-thread-test.c' + ], + include_directories : [ + root_incdir, + ], + dependencies : [ + libfwupd_deps, + ], + link_with : fwupd, + c_args : [ + '-DG_LOG_DOMAIN="Fwupd"', + ], + ) + test('fwupd-thread-test', e, timeout: 60) + e = executable( + 'fwupd-context-test', + sources : [ + 'fwupd-context-test.c' + ], + include_directories : [ + root_incdir, + ], + dependencies : [ + libfwupd_deps, + ], + link_with : fwupd, + c_args : [ + '-DG_LOG_DOMAIN="Fwupd"', + ], + ) + test('fwupd-context-test', e, timeout: 60) + endif endif fwupd_incdir = include_directories('.') diff -Nru fwupd-1.4.5/libfwupd/README.md fwupd-1.5.8/libfwupd/README.md --- fwupd-1.4.5/libfwupd/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupd/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,14 @@ +Planned API/ABI changes for next release +======================================== + + * Typedef `FwupdFeatureFlags` to `guint64` so it's the same size on all platforms + * Remove the `soup-session` fallback property in `FwupdClient`. + * Remove fwupd_device_set_vendor_id() and fwupd_device_get_vendor_id() + * Remove the deprecated flags like `FWUPD_DEVICE_FLAG_MD_SET_ICON` + * Remove `fwupd_release_get_uri()` and `fwupd_release_set_uri()` + * Rename `fwupd_client_install_release2_async()` to `fwupd_client_install_release_async()` + * Remove fwupd_device_set_protocol() and fwupd_device_get_protocol() + Migration from Version 0.9.x ============================ diff -Nru fwupd-1.4.5/libfwupdplugin/fu-archive.c fwupd-1.5.8/libfwupdplugin/fu-archive.c --- fwupd-1.4.5/libfwupdplugin/fu-archive.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-archive.c 2021-03-31 20:08:32.000000000 +0000 @@ -9,10 +9,14 @@ #include "config.h" #include + +#ifdef HAVE_LIBARCHIVE #include #include +#endif #include "fu-archive.h" +#include "fwupd-error.h" /** * SECTION:fu-archive @@ -106,6 +110,7 @@ g_return_val_if_fail (FU_IS_ARCHIVE (self), FALSE); g_return_val_if_fail (callback != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); g_hash_table_iter_init (&iter, self->entries); while (g_hash_table_iter_next (&iter, &key, &value)) { @@ -115,6 +120,7 @@ return TRUE; } +#ifdef HAVE_LIBARCHIVE /* workaround the struct types of libarchive */ typedef struct archive _archive_read_ctx; @@ -126,10 +132,12 @@ } G_DEFINE_AUTOPTR_CLEANUP_FUNC(_archive_read_ctx, _archive_read_ctx_free) +#endif static gboolean fu_archive_load (FuArchive *self, GBytes *blob, FuArchiveFlags flags, GError **error) { +#ifdef HAVE_LIBARCHIVE int r; g_autoptr(_archive_read_ctx) arch = NULL; @@ -218,6 +226,13 @@ /* success */ return TRUE; +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "missing libarchive support"); + return FALSE; +#endif } /** diff -Nru fwupd-1.4.5/libfwupdplugin/fu-archive.h fwupd-1.5.8/libfwupdplugin/fu-archive.h --- fwupd-1.4.5/libfwupdplugin/fu-archive.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-archive.h 2021-03-31 20:08:32.000000000 +0000 @@ -32,6 +32,7 @@ * @filename: A filename. * @bytes: The blob referenced by @filename. * @user_data: User data. + * @error: a #GError or NULL * * Specifies the type of archive iteration function. */ @@ -39,15 +40,19 @@ const gchar *filename, GBytes *bytes, gpointer user_data, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; -FuArchive *fu_archive_new (GBytes *data, - FuArchiveFlags flags, - GError **error); -GBytes *fu_archive_lookup_by_fn (FuArchive *self, - const gchar *fn, - GError **error); +FuArchive *fu_archive_new (GBytes *data, + FuArchiveFlags flags, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +GBytes *fu_archive_lookup_by_fn (FuArchive *self, + const gchar *fn, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_archive_iterate (FuArchive *self, FuArchiveIterateFunc callback, gpointer user_data, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; diff -Nru fwupd-1.4.5/libfwupdplugin/fu-bluez-device.c fwupd-1.5.8/libfwupdplugin/fu-bluez-device.c --- fwupd-1.4.5/libfwupdplugin/fu-bluez-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-bluez-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,697 @@ +/* + * Copyright (C) 2021 Ricardo Cañuelo + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuBluezDevice" + +#include "config.h" + +#include + +#include "fu-bluez-device.h" +#include "fu-common.h" +#include "fu-device-private.h" +#include "fu-firmware-common.h" + +#define DEFAULT_PROXY_TIMEOUT 5000 + +/** + * SECTION:fu-bluez-device + * @short_description: a BlueZ Bluetooth device + * + * An object that represents a BlueZ Bluetooth device. + * + * See also: #FuBluezDevice + */ + +typedef struct { + FuBluezDevice parent_instance; + GDBusObjectManager *object_manager; + GDBusProxy *proxy; + GHashTable *uuids; /* utf8 : FuBluezDeviceUuidHelper */ +} FuBluezDevicePrivate; + +typedef struct { + FuBluezDevice *self; + gchar *uuid; + gchar *path; + gulong signal_id; + GDBusProxy *proxy; +} FuBluezDeviceUuidHelper; + +enum { + PROP_0, + PROP_OBJECT_MANAGER, + PROP_PROXY, + PROP_LAST +}; + +enum { + SIGNAL_CHANGED, + SIGNAL_LAST +}; + +static guint signals[SIGNAL_LAST] = { 0 }; + +G_DEFINE_TYPE_WITH_PRIVATE (FuBluezDevice, fu_bluez_device, FU_TYPE_DEVICE) + +#define GET_PRIVATE(o) (fu_bluez_device_get_instance_private (o)) + +static void +fu_bluez_uuid_free (FuBluezDeviceUuidHelper *uuid_helper) +{ + if (uuid_helper->path != NULL) + g_free (uuid_helper->path); + if (uuid_helper->proxy != NULL) + g_object_unref (uuid_helper->proxy); + g_free (uuid_helper->uuid); + g_object_unref (uuid_helper->self); + g_free (uuid_helper); +} + +/* + * Looks up a UUID in the FuBluezDevice uuids table. + */ +static FuBluezDeviceUuidHelper * +fu_bluez_device_get_uuid_helper (FuBluezDevice *self, + const gchar *uuid, + GError **error) +{ + FuBluezDevicePrivate *priv = GET_PRIVATE (self); + FuBluezDeviceUuidHelper *uuid_helper; + + uuid_helper = g_hash_table_lookup (priv->uuids, uuid); + if (uuid_helper == NULL) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "UUID %s not supported", uuid); + return NULL; + } + + return uuid_helper; +} + +static void +fu_bluez_device_signal_cb (GDBusProxy *proxy, + GVariant *changed_properties, + GStrv invalidated_properties, + FuBluezDeviceUuidHelper *uuid_helper) +{ + g_signal_emit (uuid_helper->self, signals[SIGNAL_CHANGED], 0, uuid_helper->uuid); +} + +/* + * Builds the GDBusProxy of the BlueZ object identified by a UUID + * string. If the object doesn't have a dedicated proxy yet, this + * creates it and saves it in the FuBluezDeviceUuidHelper object. + * + * NOTE: Currently limited to GATT characteristics. + */ +static gboolean +fu_bluez_device_ensure_uuid_helper_proxy (FuBluezDeviceUuidHelper *uuid_helper, + GError **error) +{ + if (uuid_helper->proxy != NULL) + return TRUE; + uuid_helper->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.bluez", + uuid_helper->path, + "org.bluez.GattCharacteristic1", + NULL, error); + if (uuid_helper->proxy == NULL) { + g_prefix_error (error, "Failed to create GDBusProxy for uuid_helper: "); + return FALSE; + } + g_dbus_proxy_set_default_timeout (uuid_helper->proxy, DEFAULT_PROXY_TIMEOUT); + uuid_helper->signal_id = g_signal_connect (uuid_helper->proxy, + "g-properties-changed", + G_CALLBACK (fu_bluez_device_signal_cb), + uuid_helper); + if (uuid_helper->signal_id <= 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "cannot connect to signal of UUID %s", + uuid_helper->uuid); + return FALSE; + } + return TRUE; +} + +static void +fu_bluez_device_add_uuid_path (FuBluezDevice *self, const gchar *uuid, const gchar *path) +{ + FuBluezDevicePrivate *priv = GET_PRIVATE (self); + FuBluezDeviceUuidHelper *uuid_helper; + g_return_if_fail (FU_IS_BLUEZ_DEVICE (self)); + g_return_if_fail (uuid != NULL); + g_return_if_fail (path != NULL); + + uuid_helper = g_new0 (FuBluezDeviceUuidHelper, 1); + uuid_helper->self = g_object_ref (self); + uuid_helper->uuid = g_strdup (uuid); + uuid_helper->path = g_strdup (path); + g_hash_table_insert (priv->uuids, g_strdup (uuid), uuid_helper); +} + +static void +fu_bluez_device_set_modalias (FuBluezDevice *self, const gchar *modalias) +{ + gsize modaliaslen = strlen (modalias); + guint16 vid = 0x0; + guint16 pid = 0x0; + guint16 rev = 0x0; + + g_return_if_fail (modalias != NULL); + + /* usb:v0461p4EEFd0001 */ + if (g_str_has_prefix (modalias, "usb:")) { + fu_firmware_strparse_uint16_safe (modalias, modaliaslen, 5, &vid, NULL); + fu_firmware_strparse_uint16_safe (modalias, modaliaslen, 10, &pid, NULL); + fu_firmware_strparse_uint16_safe (modalias, modaliaslen, 15, &rev, NULL); + + /* bluetooth:v000ApFFFFdFFFF */ + } else if (g_str_has_prefix (modalias, "bluetooth:")) { + fu_firmware_strparse_uint16_safe (modalias, modaliaslen, 11, &vid, NULL); + fu_firmware_strparse_uint16_safe (modalias, modaliaslen, 16, &pid, NULL); + fu_firmware_strparse_uint16_safe (modalias, modaliaslen, 21, &rev, NULL); + } + + if (vid != 0x0 && pid != 0x0 && rev != 0x0) { + g_autofree gchar *devid = NULL; + devid = g_strdup_printf ("BLUETOOTH\\VID_%04X&PID_%04X&REV_%04X", + vid, pid, rev); + fu_device_add_instance_id (FU_DEVICE (self), devid); + } + if (vid != 0x0 && pid != 0x0) { + g_autofree gchar *devid = NULL; + devid = g_strdup_printf ("BLUETOOTH\\VID_%04X&PID_%04X", vid, pid); + fu_device_add_instance_id (FU_DEVICE (self), devid); + } + if (vid != 0x0) { + g_autofree gchar *devid = NULL; + g_autofree gchar *vendor_id = NULL; + devid = g_strdup_printf ("BLUETOOTH\\VID_%04X", vid); + fu_device_add_instance_id_full (FU_DEVICE (self), devid, + FU_DEVICE_INSTANCE_FLAG_ONLY_QUIRKS); + vendor_id = g_strdup_printf ("BLUETOOTH:%04X", vid); + fu_device_add_vendor_id (FU_DEVICE (self), vendor_id); + } +} + +static void +fu_bluez_device_to_string (FuDevice *device, guint idt, GString *str) +{ + FuBluezDevice *self = FU_BLUEZ_DEVICE (device); + FuBluezDevicePrivate *priv = GET_PRIVATE (self); + + if (priv->uuids != NULL) { + GHashTableIter iter; + gpointer key, value; + g_hash_table_iter_init (&iter, priv->uuids); + while (g_hash_table_iter_next (&iter, &key, &value)) { + FuBluezDeviceUuidHelper *uuid_helper = (FuBluezDeviceUuidHelper *) value; + fu_common_string_append_kv (str, idt + 1, + (const gchar *) key, + uuid_helper->path); + } + } +} + +/* + * Returns the value of a property of an object specified by its path as + * a GVariant, or NULL if the property wasn't found. + */ +static GVariant * +fu_bluez_device_get_ble_property (const gchar *obj_path, + const gchar *iface, + const gchar *prop_name, + GError **error) +{ + g_autoptr(GDBusProxy) proxy = NULL; + g_autoptr(GVariant) val = NULL; + + proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.bluez", + obj_path, iface, NULL, error); + if (proxy == NULL) { + g_prefix_error (error, "failed to connect to %s: ", iface); + return NULL; + } + g_dbus_proxy_set_default_timeout (proxy, DEFAULT_PROXY_TIMEOUT); + val = g_dbus_proxy_get_cached_property (proxy, prop_name); + if (val == NULL) { + g_prefix_error (error, "property %s not found in %s: ", + prop_name, obj_path); + return NULL; + } + + return g_steal_pointer (&val); +} + +/* + * Returns the value of the string property of an object specified by + * its path, or NULL if the property wasn't found. + * + * The returned string must be freed using g_free(). + */ +static gchar * +fu_bluez_device_get_ble_string_property (const gchar *obj_path, + const gchar *iface, + const gchar *prop_name, + GError **error) +{ + g_autoptr(GVariant) val = NULL; + val = fu_bluez_device_get_ble_property (obj_path, iface, prop_name, error); + if (val == NULL) + return NULL; + return g_variant_dup_string (val, NULL); +} + +/* + * Populates the {uuid_helper : object_path} entries of a device for all its + * characteristics. + * + * TODO: Extend to services and descriptors too? + */ +static void +fu_bluez_device_add_device_uuids (FuBluezDevice *self) +{ + FuBluezDevicePrivate *priv = GET_PRIVATE (self); + g_autolist(GDBusObject) obj_list = NULL; + + obj_list = g_dbus_object_manager_get_objects (priv->object_manager); + for (GList *l = obj_list; l != NULL; l = l->next) { + GDBusObject *obj = G_DBUS_OBJECT (l->data); + g_autoptr(GDBusInterface) iface = NULL; + g_autoptr(GError) error_local = NULL; + g_autofree gchar *obj_uuid = NULL; + const gchar *obj_path = g_dbus_object_get_object_path (obj); + + /* not us */ + if (!g_str_has_prefix (g_dbus_object_get_object_path (obj), + g_dbus_proxy_get_object_path (priv->proxy))) + continue; + + /* + * TODO: Currently restricted to getting UUIDs for + * characteristics only, as the only use case we're + * going to need for now is reading/writing + * characteristics. + */ + iface = g_dbus_object_get_interface (obj, "org.bluez.GattCharacteristic1"); + if (iface == NULL) + continue; + obj_uuid = fu_bluez_device_get_ble_string_property (obj_path, + "org.bluez.GattCharacteristic1", + "UUID", + &error_local); + if (obj_uuid == NULL) { + g_debug ("failed to get property: %s", error_local->message); + continue; + } + fu_bluez_device_add_uuid_path (self, obj_uuid, obj_path); + } +} + +static gboolean +fu_bluez_device_setup (FuDevice *device, GError **error) +{ + FuBluezDevice *self = FU_BLUEZ_DEVICE (device); + + fu_bluez_device_add_device_uuids (self); + + return TRUE; +} + +static gboolean +fu_bluez_device_probe (FuDevice *device, GError **error) +{ + FuBluezDevice *self = FU_BLUEZ_DEVICE (device); + FuBluezDevicePrivate *priv = GET_PRIVATE (self); + g_autoptr(GVariant) val_adapter = NULL; + g_autoptr(GVariant) val_address = NULL; + g_autoptr(GVariant) val_icon = NULL; + g_autoptr(GVariant) val_modalias = NULL; + g_autoptr(GVariant) val_name = NULL; + + val_address = g_dbus_proxy_get_cached_property (priv->proxy, "Address"); + if (val_address == NULL) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "No required BLE address"); + return FALSE; + } + fu_device_set_logical_id (device, g_variant_get_string (val_address, NULL)); + val_adapter = g_dbus_proxy_get_cached_property (priv->proxy, "Adapter"); + if (val_adapter != NULL) + fu_device_set_physical_id (device, g_variant_get_string (val_adapter, NULL)); + val_name = g_dbus_proxy_get_cached_property (priv->proxy, "Name"); + if (val_name != NULL) + fu_device_set_name (device, g_variant_get_string (val_name, NULL)); + val_icon = g_dbus_proxy_get_cached_property (priv->proxy, "Icon"); + if (val_icon != NULL) + fu_device_add_icon (device, g_variant_get_string (val_name, NULL)); + val_modalias = g_dbus_proxy_get_cached_property (priv->proxy, "Modalias"); + if (val_modalias != NULL) + fu_bluez_device_set_modalias (self, g_variant_get_string (val_modalias, NULL)); + + /* success */ + return TRUE; +} + +/** + * fu_bluez_device_read: + * @self: A #FuBluezDevice + * @uuid: The UUID, e.g. `00cde35c-7062-11eb-9439-0242ac130002` + * @error: A #GError, or %NULL + * + * Reads from a UUID on the device. + * + * Returns: (transfer full): data, or %NULL for error + * + * Since: 1.5.7 + **/ +GByteArray * +fu_bluez_device_read (FuBluezDevice *self, const gchar *uuid, GError **error) +{ + FuBluezDeviceUuidHelper *uuid_helper; + guint8 byte; + g_autoptr(GByteArray) buf = g_byte_array_new (); + g_autoptr(GVariantBuilder) builder = NULL; + g_autoptr(GVariantIter) iter = NULL; + g_autoptr(GVariant) val = NULL; + + uuid_helper = fu_bluez_device_get_uuid_helper (self, uuid, error); + if (uuid_helper == NULL) + return NULL; + if (!fu_bluez_device_ensure_uuid_helper_proxy (uuid_helper, error)) + return NULL; + + /* + * Call the "ReadValue" method through the proxy synchronously. + * + * The method takes one argument: an array of dicts of + * {string:value} specifing the options (here the option is + * "offset":0. + * The result is a byte array. + */ + builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); + g_variant_builder_add (builder, "{sv}", "offset", + g_variant_new("q", 0)); + + val = g_dbus_proxy_call_sync (uuid_helper->proxy, + "ReadValue", + g_variant_new ("(a{sv})", builder), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (val == NULL) { + g_prefix_error (error, "Failed to read GattCharacteristic1: "); + return NULL; + } + g_variant_get(val, "(ay)", &iter); + while (g_variant_iter_loop (iter, "y", &byte)) + g_byte_array_append (buf, &byte, 1); + + /* success */ + return g_steal_pointer (&buf); +} + +/** + * fu_bluez_device_read_string: + * @self: A #FuBluezDevice + * @uuid: The UUID, e.g. `00cde35c-7062-11eb-9439-0242ac130002` + * @error: A #GError, or %NULL + * + * Reads a string from a UUID on the device. + * + * Returns: (transfer full): data, or %NULL for error + * + * Since: 1.5.7 + **/ +gchar * +fu_bluez_device_read_string (FuBluezDevice *self, const gchar *uuid, GError **error) +{ + GByteArray *buf = fu_bluez_device_read (self, uuid, error); + if (buf == NULL) + return NULL; + return (gchar *) g_byte_array_free (buf, FALSE); +} + +/** + * fu_bluez_device_write: + * @self: A #FuBluezDevice + * @uuid: The UUID, e.g. `00cde35c-7062-11eb-9439-0242ac130002` + * @error: A #GError, or %NULL + * + * Writes to a UUID on the device. + * + * Returns: %TRUE if all the data was written + * + * Since: 1.5.7 + **/ +gboolean +fu_bluez_device_write (FuBluezDevice *self, + const gchar *uuid, + GByteArray *buf, + GError **error) +{ + FuBluezDeviceUuidHelper *uuid_helper; + g_autoptr(GVariantBuilder) opt_builder = NULL; + g_autoptr(GVariantBuilder) val_builder = NULL; + g_autoptr(GVariant) ret = NULL; + GVariant *opt_variant = NULL; + GVariant *val_variant = NULL; + + uuid_helper = fu_bluez_device_get_uuid_helper (self, uuid, error); + if (uuid_helper == NULL) + return FALSE; + if (!fu_bluez_device_ensure_uuid_helper_proxy (uuid_helper, error)) + return FALSE; + + /* build the value variant */ + val_builder = g_variant_builder_new (G_VARIANT_TYPE ("ay")); + for (gsize i = 0; i < buf->len; i++) + g_variant_builder_add (val_builder, "y", buf->data[i]); + val_variant = g_variant_new ("ay", val_builder); + + /* build the options variant (offset = 0) */ + opt_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}")); + g_variant_builder_add (opt_builder, "{sv}", "offset", + g_variant_new_uint16 (0)); + opt_variant = g_variant_new("a{sv}", opt_builder); + + ret = g_dbus_proxy_call_sync (uuid_helper->proxy, + "WriteValue", + g_variant_new ("(@ay@a{sv})", + val_variant, + opt_variant), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (ret == NULL) { + g_prefix_error (error, "Failed to write GattCharacteristic1: "); + return FALSE; + } + + /* success */ + return TRUE; +} + +/** + * fu_bluez_device_notify_start: + * @uuid: The UUID, e.g. `00cde35c-7062-11eb-9439-0242ac130002` + * @error: A #GError, or %NULL + * + * Enables notifications for property changes in a UUID (StartNotify + * method). + * + * Returns: %TRUE if the method call completed successfully. + * + * Since: 1.5.8 + **/ +gboolean +fu_bluez_device_notify_start (FuBluezDevice *self, const gchar *uuid, GError **error) +{ + FuBluezDeviceUuidHelper *uuid_helper; + g_autoptr(GVariant) retval = NULL; + + uuid_helper = fu_bluez_device_get_uuid_helper (self, uuid, error); + if (uuid_helper == NULL) + return FALSE; + if (!fu_bluez_device_ensure_uuid_helper_proxy (uuid_helper, error)) + return FALSE; + retval = g_dbus_proxy_call_sync (uuid_helper->proxy, + "StartNotify", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (retval == NULL) { + g_prefix_error (error, "Failed to enable notifications: "); + return FALSE; + } + + return TRUE; +} + +/** + * fu_bluez_device_notify_stop: + * @uuid: The UUID, e.g. `00cde35c-7062-11eb-9439-0242ac130002` + * @error: A #GError, or %NULL + * + * Disables notifications for property changes in a UUID (StopNotify + * method). + * + * Returns: %TRUE if the method call completed successfully. + * + * Since: 1.5.8 + **/ +gboolean +fu_bluez_device_notify_stop (FuBluezDevice *self, const gchar *uuid, GError **error) +{ + FuBluezDeviceUuidHelper *uuid_helper; + g_autoptr(GVariant) retval = NULL; + + uuid_helper = fu_bluez_device_get_uuid_helper (self, uuid, error); + if (uuid_helper == NULL) + return FALSE; + if (!fu_bluez_device_ensure_uuid_helper_proxy (uuid_helper, error)) + return FALSE; + retval = g_dbus_proxy_call_sync (uuid_helper->proxy, + "StopNotify", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (retval == NULL) { + g_prefix_error (error, "Failed to enable notifications: "); + return FALSE; + } + + return TRUE; +} + +static void +fu_bluez_device_incorporate (FuDevice *self, FuDevice *donor) +{ + FuBluezDevice *uself = FU_BLUEZ_DEVICE (self); + FuBluezDevice *udonor = FU_BLUEZ_DEVICE (donor); + FuBluezDevicePrivate *priv = GET_PRIVATE (uself); + FuBluezDevicePrivate *privdonor = GET_PRIVATE (udonor); + + if (g_hash_table_size (priv->uuids) == 0) { + GHashTableIter iter; + gpointer key, value; + g_hash_table_iter_init (&iter, privdonor->uuids); + while (g_hash_table_iter_next (&iter, &key, &value)) { + FuBluezDeviceUuidHelper *uuid_helper = (FuBluezDeviceUuidHelper *) value; + fu_bluez_device_add_uuid_path (uself, + (const gchar *) key, + uuid_helper->path); + } + } + if (priv->object_manager == NULL) + priv->object_manager = g_object_ref (privdonor->object_manager); + if (priv->proxy == NULL) + priv->proxy = g_object_ref (privdonor->proxy); +} + +static void +fu_bluez_device_get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + FuBluezDevice *self = FU_BLUEZ_DEVICE (object); + FuBluezDevicePrivate *priv = GET_PRIVATE (self); + switch (prop_id) { + case PROP_OBJECT_MANAGER: + g_value_set_object (value, priv->object_manager); + break; + case PROP_PROXY: + g_value_set_object (value, priv->proxy); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +fu_bluez_device_set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + FuBluezDevice *self = FU_BLUEZ_DEVICE (object); + FuBluezDevicePrivate *priv = GET_PRIVATE (self); + switch (prop_id) { + case PROP_OBJECT_MANAGER: + priv->object_manager = g_value_dup_object (value); + break; + case PROP_PROXY: + priv->proxy = g_value_dup_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +fu_bluez_device_finalize (GObject *object) +{ + FuBluezDevice *self = FU_BLUEZ_DEVICE (object); + FuBluezDevicePrivate *priv = GET_PRIVATE (self); + + g_hash_table_unref (priv->uuids); + g_object_unref (priv->proxy); + g_object_unref (priv->object_manager); + G_OBJECT_CLASS (fu_bluez_device_parent_class)->finalize (object); +} + +static void +fu_bluez_device_init (FuBluezDevice *self) +{ + FuBluezDevicePrivate *priv = GET_PRIVATE (self); + priv->uuids = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, (GDestroyNotify) fu_bluez_uuid_free); +} + +static void +fu_bluez_device_class_init (FuBluezDeviceClass *klass) +{ + FuDeviceClass *device_class = FU_DEVICE_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GParamSpec *pspec; + + object_class->get_property = fu_bluez_device_get_property; + object_class->set_property = fu_bluez_device_set_property; + object_class->finalize = fu_bluez_device_finalize; + device_class->probe = fu_bluez_device_probe; + device_class->setup = fu_bluez_device_setup; + device_class->to_string = fu_bluez_device_to_string; + device_class->incorporate = fu_bluez_device_incorporate; + + signals[SIGNAL_CHANGED] = + g_signal_new ("changed", + G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, + 0, NULL, NULL, g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); + + pspec = g_param_spec_object ("object-manager", NULL, NULL, + G_TYPE_DBUS_OBJECT_MANAGER, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_OBJECT_MANAGER, pspec); + + pspec = g_param_spec_object ("proxy", NULL, NULL, + G_TYPE_DBUS_PROXY, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_PROXY, pspec); +} diff -Nru fwupd-1.4.5/libfwupdplugin/fu-bluez-device.h fwupd-1.5.8/libfwupdplugin/fu-bluez-device.h --- fwupd-1.4.5/libfwupdplugin/fu-bluez-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-bluez-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2021 Ricardo Cañuelo + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-device.h" + +#define FU_TYPE_BLUEZ_DEVICE (fu_bluez_device_get_type ()) +G_DECLARE_DERIVABLE_TYPE (FuBluezDevice, fu_bluez_device, FU, BLUEZ_DEVICE, FuDevice) + +struct _FuBluezDeviceClass +{ + FuDeviceClass parent_class; + gpointer __reserved[31]; +}; + +GByteArray *fu_bluez_device_read (FuBluezDevice *self, + const gchar *uuid, + GError **error); +gchar *fu_bluez_device_read_string (FuBluezDevice *self, + const gchar *uuid, + GError **error); +gboolean fu_bluez_device_write (FuBluezDevice *self, + const gchar *uuid, + GByteArray *buf, + GError **error); +gboolean fu_bluez_device_notify_start (FuBluezDevice *self, + const gchar *uuid, + GError **error); +gboolean fu_bluez_device_notify_stop (FuBluezDevice *self, + const gchar *uuid, + GError **error); diff -Nru fwupd-1.4.5/libfwupdplugin/fu-cabinet.c fwupd-1.5.8/libfwupdplugin/fu-cabinet.c --- fwupd-1.4.5/libfwupdplugin/fu-cabinet.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-cabinet.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2020 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -341,8 +341,11 @@ /* verify it is correct */ if (g_strcmp0 (xb_builder_node_get_text (csum), self->container_checksum) != 0) { - g_debug ("invalid container checksum %s, fixing up to %s", - xb_builder_node_get_text (csum), self->container_checksum); + if (xb_builder_node_get_text (csum) != NULL) { + g_warning ("invalid container checksum %s, fixing up to %s", + xb_builder_node_get_text (csum), + self->container_checksum); + } xb_builder_node_set_text (csum, self->container_checksum, -1); } return TRUE; @@ -361,10 +364,8 @@ g_autoptr(XbBuilderNode) bn_info = xb_builder_node_new ("info"); /* indicate the metainfo file was signed */ - if (release_flags & FWUPD_RELEASE_FLAG_TRUSTED_METADATA) { - g_autoptr(XbBuilderNode) bn_trust = NULL; + if (release_flags & FWUPD_RELEASE_FLAG_TRUSTED_METADATA) xb_builder_node_insert (bn_info, "metadata_trust", NULL); - } xb_builder_source_set_info (source, bn_info); /* rewrite to be under a components root */ @@ -485,7 +486,7 @@ g_autoptr(XbBuilderFixup) fixup2 = NULL; /* verbose profiling */ - if (g_getenv ("FWUPD_VERBOSE") != NULL) { + if (g_getenv ("FWUPD_XMLB_VERBOSE") != NULL) { xb_builder_set_profile_flags (self->builder, XB_SILO_PROFILE_FLAG_XPATH | XB_SILO_PROFILE_FLAG_DEBUG); @@ -504,7 +505,6 @@ /* adds each metainfo file to the silo */ for (guint i = 0; i < folders->len; i++) { GCabFolder *cabfolder = GCAB_FOLDER (g_ptr_array_index (folders, i)); - g_debug ("processing folder: %u/%u", i + 1, folders->len); if (!fu_cabinet_build_silo_folder (self, cabfolder, error)) return FALSE; } @@ -674,7 +674,9 @@ return FALSE; /* sanity check */ - components = xb_silo_query (self->silo, "components/component", 0, &error_local); + components = xb_silo_query (self->silo, + "components/component[@type='firmware']", + 0, &error_local); if (components == NULL) { g_set_error (error, FWUPD_ERROR, diff -Nru fwupd-1.4.5/libfwupdplugin/fu-cabinet.h fwupd-1.5.8/libfwupdplugin/fu-cabinet.h --- fwupd-1.4.5/libfwupdplugin/fu-cabinet.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-cabinet.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2020 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -34,5 +34,6 @@ gboolean fu_cabinet_parse (FuCabinet *self, GBytes *data, FuCabinetParseFlags flags, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; XbSilo *fu_cabinet_get_silo (FuCabinet *self); diff -Nru fwupd-1.4.5/libfwupdplugin/fu-chunk.c fwupd-1.5.8/libfwupdplugin/fu-chunk.c --- fwupd-1.4.5/libfwupdplugin/fu-chunk.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-chunk.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -10,7 +10,8 @@ #include -#include "fu-chunk.h" +#include "fu-chunk-private.h" +#include "fu-common.h" /** * SECTION:fu-chunk @@ -20,8 +21,230 @@ * */ +struct _FuChunk { + GObject parent_instance; + guint32 idx; + guint32 page; + guint32 address; + const guint8 *data; + guint32 data_sz; + gboolean is_mutable; + GBytes *bytes; +}; + +G_DEFINE_TYPE (FuChunk, fu_chunk, G_TYPE_OBJECT) + +/** + * fu_chunk_set_idx: + * @self: a #FuChunk + * @idx: index, starting at 0 + * + * Sets the index of the chunk. + * + * Since: 1.5.6 + **/ +void +fu_chunk_set_idx (FuChunk *self, guint32 idx) +{ + g_return_if_fail (FU_IS_CHUNK (self)); + self->idx = idx; +} + +/** + * fu_chunk_get_idx: + * @self: a #FuChunk + * + * Gets the index of the chunk. + * + * Return value: index + * + * Since: 1.5.6 + **/ +guint32 +fu_chunk_get_idx (FuChunk *self) +{ + g_return_val_if_fail (FU_IS_CHUNK (self), G_MAXUINT32); + return self->idx; +} + +/** + * fu_chunk_set_page: + * @self: a #FuChunk + * @page: page number, starting at 0 + * + * Sets the page of the chunk. + * + * Since: 1.5.6 + **/ +void +fu_chunk_set_page (FuChunk *self, guint32 page) +{ + g_return_if_fail (FU_IS_CHUNK (self)); + self->page = page; +} + +/** + * fu_chunk_get_page: + * @self: a #FuChunk + * + * Gets the page of the chunk. + * + * Return value: page + * + * Since: 1.5.6 + **/ +guint32 +fu_chunk_get_page (FuChunk *self) +{ + g_return_val_if_fail (FU_IS_CHUNK (self), G_MAXUINT32); + return self->page; +} + +/** + * fu_chunk_set_address: + * @self: a #FuChunk + * @address: memory address + * + * Sets the address of the chunk. + * + * Since: 1.5.6 + **/ +void +fu_chunk_set_address (FuChunk *self, guint32 address) +{ + g_return_if_fail (FU_IS_CHUNK (self)); + self->address = address; +} + +/** + * fu_chunk_get_address: + * @self: a #FuChunk + * + * Gets the address of the chunk. + * + * Return value: address + * + * Since: 1.5.6 + **/ +guint32 +fu_chunk_get_address (FuChunk *self) +{ + g_return_val_if_fail (FU_IS_CHUNK (self), G_MAXUINT32); + return self->address; +} + +/** + * fu_chunk_get_data: + * @self: a #FuChunk + * + * Gets the data of the chunk. + * + * Return value: bytes + * + * Since: 1.5.6 + **/ +const guint8 * +fu_chunk_get_data (FuChunk *self) +{ + g_return_val_if_fail (FU_IS_CHUNK (self), NULL); + return self->data; +} + +/** + * fu_chunk_get_data_out: + * @self: a #FuChunk + * + * Gets the mutable data of the chunk. + * + * WARNING: At the moment fu_chunk_get_data_out() returns the same data as + * fu_chunk_get_data() in all cases. The caller should verify the data passed to + * fu_chunk_array_new() is also writable (i.e. not `const` or `mmap`) before + * using this function. + * + * Return value: (transfer none): bytes + * + * Since: 1.5.6 + **/ +guint8 * +fu_chunk_get_data_out (FuChunk *self) +{ + g_return_val_if_fail (FU_IS_CHUNK (self), NULL); + + /* warn, but allow to proceed */ + if (!self->is_mutable) { + g_critical ("calling fu_chunk_get_data_out() from immutable chunk"); + self->is_mutable = TRUE; + } + return (guint8 *) self->data; +} + +/** + * fu_chunk_get_data_sz: + * @self: a #FuChunk + * + * Gets the data size of the chunk. + * + * Return value: size in bytes + * + * Since: 1.5.6 + **/ +guint32 +fu_chunk_get_data_sz (FuChunk *self) +{ + g_return_val_if_fail (FU_IS_CHUNK (self), G_MAXUINT32); + return self->data_sz; +} + /** - * fu_chunk_new: (skip): + * fu_chunk_set_bytes: + * @self: a #FuChunk + * @bytes: (nullable): a #GBytes, or %NULL + * + * Sets the GBytes blob + * + * Since: 1.5.6 + **/ +void +fu_chunk_set_bytes (FuChunk *self, GBytes *bytes) +{ + g_return_if_fail (FU_IS_CHUNK (self)); + + /* not changed */ + if (self->bytes == bytes) + return; + + if (self->bytes != NULL) { + g_bytes_unref (self->bytes); + self->bytes = NULL; + } + if (bytes != NULL) { + self->bytes = g_bytes_ref (bytes); + self->data = g_bytes_get_data (bytes, NULL); + self->data_sz = g_bytes_get_size (bytes); + } +} + +/** + * fu_chunk_get_bytes: + * @self: a #FuChunk + * + * Gets the data as bytes of the chunk. + * + * Return value: (transfer full): a #GBytes + * + * Since: 1.5.6 + **/ +GBytes * +fu_chunk_get_bytes (FuChunk *self) +{ + g_return_val_if_fail (FU_IS_CHUNK (self), NULL); + if (self->bytes != NULL) + return g_bytes_ref (self->bytes); + return g_bytes_new_static (self->data, self->data_sz); +} + +/** + * fu_chunk_new: * @idx: the packet number * @page: the hardware memory page * @address: the address *within* the page @@ -41,18 +264,52 @@ const guint8 *data, guint32 data_sz) { - FuChunk *item = g_new0 (FuChunk, 1); - item->idx = idx; - item->page = page; - item->address = address; - item->data = data; - item->data_sz = data_sz; - return item; + FuChunk *self = g_object_new (FU_TYPE_CHUNK, NULL); + self->idx = idx; + self->page = page; + self->address = address; + self->data = data; + self->data_sz = data_sz; + return self; +} + +/** + * fu_chunk_bytes_new: + * @bytes: (nullable): a #GBytes + * + * Creates a new packet of data. + * + * Return value: (transfer full): a #FuChunk + * + * Since: 1.5.6 + **/ +FuChunk * +fu_chunk_bytes_new (GBytes *bytes) +{ + FuChunk *self = g_object_new (FU_TYPE_CHUNK, NULL); + fu_chunk_set_bytes (self, bytes); + return self; +} + +void +fu_chunk_add_string (FuChunk *self, guint idt, GString *str) +{ + fu_common_string_append_kv (str, idt, G_OBJECT_TYPE_NAME (self), NULL); + fu_common_string_append_kx (str, idt + 1, "Index", self->idx); + fu_common_string_append_kx (str, idt + 1, "Page", self->page); + fu_common_string_append_kx (str, idt + 1, "Address", self->address); + if (self->data != NULL) { + g_autofree gchar *datastr = NULL; + datastr = fu_common_strsafe ((const gchar *) self->data, MIN (self->data_sz, 16)); + if (datastr != NULL) + fu_common_string_append_kv (str, idt + 1, "Data", datastr); + } + fu_common_string_append_kx (str, idt + 1, "DataSz", self->data_sz); } /** * fu_chunk_to_string: - * @item: a #FuChunk + * @self: a #FuChunk * * Converts the chunked packet to a string representation. * @@ -61,24 +318,11 @@ * Since: 1.1.2 **/ gchar * -fu_chunk_to_string (FuChunk *item) +fu_chunk_to_string (FuChunk *self) { - g_autoptr(GString) str = g_string_new (NULL); - if (item->data != NULL) { - for (guint32 i = 0; i < item->data_sz; i++) { - gchar tmp = (gchar) item->data[i]; - if (tmp == 0x00) - break; - g_string_append_c (str, g_ascii_isalnum (tmp) ? tmp : '?'); - } - } - return g_strdup_printf ("#%02" G_GUINT32_FORMAT ": page:%02x " - "addr:%04x len:%02" G_GUINT32_FORMAT " %s", - item->idx, - (guint) item->page, - (guint) item->address, - item->data_sz, - str->str); + GString *str = g_string_new (NULL); + fu_chunk_add_string (self, 0, str); + return g_string_free (str, FALSE); } /** @@ -96,15 +340,54 @@ { GString *str = g_string_new (NULL); for (guint i = 0; i < chunks->len; i++) { - FuChunk *item = g_ptr_array_index (chunks, i); - g_autofree gchar *tmp = fu_chunk_to_string (item); + FuChunk *chk = g_ptr_array_index (chunks, i); + g_autofree gchar *tmp = fu_chunk_to_string (chk); g_string_append_printf (str, "%s\n", tmp); } + if (str->len > 0) + g_string_truncate (str, str->len - 1); return g_string_free (str, FALSE); } /** - * fu_chunk_array_new: (skip): + * fu_chunk_array_mutable_new: + * @data: a mutable blob of memory + * @data_sz: size of @data_sz + * @addr_start: the hardware address offset, or 0 + * @page_sz: the hardware page size, or 0 + * @packet_sz: the transfer size, or 0 + * + * Chunks a mutable blob of memory into packets, ensuring each packet does not + * cross a package boundary and is less that a specific transfer size. + * + * Return value: (transfer container) (element-type FuChunk): array of packets + * + * Since: 1.5.6 + **/ +GPtrArray * +fu_chunk_array_mutable_new (guint8 *data, + guint32 data_sz, + guint32 addr_start, + guint32 page_sz, + guint32 packet_sz) +{ + GPtrArray *chunks; + + g_return_val_if_fail (data != NULL, NULL); + g_return_val_if_fail (data_sz > 0, NULL); + + chunks = fu_chunk_array_new (data, data_sz, addr_start, page_sz, packet_sz); + if (chunks == NULL) + return NULL; + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + chk->is_mutable = TRUE; + } + return chunks; +} + +/** + * fu_chunk_array_new: * @data: a linear blob of memory, or %NULL * @data_sz: size of @data_sz * @addr_start: the hardware address offset, or 0 @@ -125,14 +408,14 @@ guint32 page_sz, guint32 packet_sz) { - GPtrArray *segments = NULL; + GPtrArray *chunks = NULL; guint32 page_old = G_MAXUINT32; guint32 idx; guint32 last_flush = 0; g_return_val_if_fail (data_sz > 0, NULL); - segments = g_ptr_array_new_with_free_func (g_free); + chunks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); for (idx = 1; idx < data_sz; idx++) { guint32 page = 0; if (page_sz > 0) @@ -144,8 +427,8 @@ guint32 address_offset = addr_start + last_flush; if (page_sz > 0) address_offset %= page_sz; - g_ptr_array_add (segments, - fu_chunk_new (segments->len, + g_ptr_array_add (chunks, + fu_chunk_new (chunks->len, page_old, address_offset, data_offset, @@ -159,8 +442,8 @@ guint32 address_offset = addr_start + last_flush; if (page_sz > 0) address_offset %= page_sz; - g_ptr_array_add (segments, - fu_chunk_new (segments->len, + g_ptr_array_add (chunks, + fu_chunk_new (chunks->len, page, address_offset, data_offset, @@ -177,18 +460,18 @@ address_offset %= page_sz; page = (addr_start + (idx - 1)) / page_sz; } - g_ptr_array_add (segments, - fu_chunk_new (segments->len, + g_ptr_array_add (chunks, + fu_chunk_new (chunks->len, page, address_offset, data_offset, data_sz - last_flush)); } - return segments; + return chunks; } /** - * fu_chunk_array_new_from_bytes: (skip): + * fu_chunk_array_new_from_bytes: * @blob: a #GBytes * @addr_start: the hardware address offset, or 0 * @page_sz: the hardware page size, or 0 @@ -207,8 +490,77 @@ guint32 page_sz, guint32 packet_sz) { + GPtrArray *chunks; gsize sz; const guint8 *data = g_bytes_get_data (blob, &sz); - return fu_chunk_array_new (data, (guint32) sz, - addr_start, page_sz, packet_sz); + + chunks = fu_chunk_array_new (data, (guint32) sz, addr_start, page_sz, packet_sz); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + chk->bytes = fu_common_bytes_new_offset (blob, + chk->data - data, + chk->data_sz, + NULL); + } + return chunks; +} + +/* private */ +gboolean +fu_chunk_build (FuChunk *self, XbNode *n, GError **error) +{ + guint64 tmp; + g_autoptr(XbNode) data = NULL; + + g_return_val_if_fail (FU_IS_CHUNK (self), FALSE); + g_return_val_if_fail (XB_IS_NODE (n), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* optional properties */ + tmp = xb_node_query_text_as_uint (n, "idx", NULL); + if (tmp != G_MAXUINT64) + self->idx = tmp; + tmp = xb_node_query_text_as_uint (n, "page", NULL); + if (tmp != G_MAXUINT64) + self->page = tmp; + tmp = xb_node_query_text_as_uint (n, "addr", NULL); + if (tmp != G_MAXUINT64) + self->address = tmp; + data = xb_node_query_first (n, "data", NULL); + if (data != NULL && xb_node_get_text (data) != NULL) { + gsize bufsz = 0; + g_autofree guchar *buf = NULL; + g_autoptr(GBytes) blob = NULL; + buf = g_base64_decode (xb_node_get_text (data), &bufsz); + blob = g_bytes_new (buf, bufsz); + fu_chunk_set_bytes (self, blob); + } else if (data != NULL) { + g_autoptr(GBytes) blob = NULL; + blob = g_bytes_new (NULL, 0); + fu_chunk_set_bytes (self, blob); + } + + /* success */ + return TRUE; +} + +static void +fu_chunk_finalize (GObject *object) +{ + FuChunk *self = FU_CHUNK (object); + if (self->bytes != NULL) + g_bytes_unref (self->bytes); + G_OBJECT_CLASS (fu_chunk_parent_class)->finalize (object); +} + +static void +fu_chunk_class_init (FuChunkClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fu_chunk_finalize; +} + +static void +fu_chunk_init (FuChunk *self) +{ } diff -Nru fwupd-1.4.5/libfwupdplugin/fu-chunk.h fwupd-1.5.8/libfwupdplugin/fu-chunk.h --- fwupd-1.4.5/libfwupdplugin/fu-chunk.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-chunk.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,34 +1,51 @@ /* - * Copyright (C) 2017-2018 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -#include -#include +#include -typedef struct { - guint32 idx; - guint32 page; - guint32 address; - const guint8 *data; - guint32 data_sz; -} FuChunk; +#define FU_TYPE_CHUNK (fu_chunk_get_type ()) + +G_DECLARE_FINAL_TYPE (FuChunk, fu_chunk, FU, CHUNK, GObject) + +FuChunk *fu_chunk_bytes_new (GBytes *bytes); +void fu_chunk_set_idx (FuChunk *self, + guint32 idx); +guint32 fu_chunk_get_idx (FuChunk *self); +void fu_chunk_set_page (FuChunk *self, + guint32 page); +guint32 fu_chunk_get_page (FuChunk *self); +void fu_chunk_set_address (FuChunk *self, + guint32 address); +guint32 fu_chunk_get_address (FuChunk *self); +const guint8 *fu_chunk_get_data (FuChunk *self); +guint8 *fu_chunk_get_data_out (FuChunk *self); +guint32 fu_chunk_get_data_sz (FuChunk *self); +void fu_chunk_set_bytes (FuChunk *self, + GBytes *bytes); +GBytes *fu_chunk_get_bytes (FuChunk *self); FuChunk *fu_chunk_new (guint32 idx, guint32 page, guint32 address, const guint8 *data, guint32 data_sz); -gchar *fu_chunk_to_string (FuChunk *item); +gchar *fu_chunk_to_string (FuChunk *self); gchar *fu_chunk_array_to_string (GPtrArray *chunks); GPtrArray *fu_chunk_array_new (const guint8 *data, guint32 data_sz, guint32 addr_start, guint32 page_sz, + guint32 packet_sz); +GPtrArray *fu_chunk_array_mutable_new (guint8 *data, + guint32 data_sz, + guint32 addr_start, + guint32 page_sz, guint32 packet_sz); GPtrArray *fu_chunk_array_new_from_bytes (GBytes *blob, guint32 addr_start, diff -Nru fwupd-1.4.5/libfwupdplugin/fu-chunk-private.h fwupd-1.5.8/libfwupdplugin/fu-chunk-private.h --- fwupd-1.4.5/libfwupdplugin/fu-chunk-private.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-chunk-private.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2017 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#include "fu-chunk.h" + +void fu_chunk_add_string (FuChunk *self, + guint idt, + GString *str); +gboolean fu_chunk_build (FuChunk *self, + XbNode *n, + GError **error); diff -Nru fwupd-1.4.5/libfwupdplugin/fu-common.c fwupd-1.5.8/libfwupdplugin/fu-common.c --- fwupd-1.4.5/libfwupdplugin/fu-common.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-common.c 2021-03-31 20:08:32.000000000 +0000 @@ -19,16 +19,35 @@ #include #endif +#ifdef _WIN32 +#include +#endif + +#ifdef HAVE_CPUID_H +#include +#endif + +#ifdef HAVE_LIBARCHIVE #include #include +#endif #include #include #include #include +#include #include "fwupd-error.h" #include "fu-common.h" +#include "fu-volume-private.h" + +#define UDISKS_DBUS_SERVICE "org.freedesktop.UDisks2" +#define UDISKS_DBUS_PATH "/org/freedesktop/UDisks2/Manager" +#define UDISKS_DBUS_MANAGER_INTERFACE "org.freedesktop.UDisks2.Manager" +#define UDISKS_DBUS_INTERFACE_PARTITION "org.freedesktop.UDisks2.Partition" +#define UDISKS_DBUS_INTERFACE_FILESYSTEM "org.freedesktop.UDisks2.Filesystem" +#define UDISKS_DBUS_INTERFACE_BLOCK "org.freedesktop.UDisks2.Block" /** * SECTION:fu-common @@ -56,6 +75,9 @@ const gchar *filename; g_autoptr(GDir) dir = NULL; + g_return_val_if_fail (directory != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + /* try to open */ g_debug ("removing %s", directory); dir = g_dir_open (directory, 0, error); @@ -131,6 +153,10 @@ fu_common_get_files_recursive (const gchar *path, GError **error) { g_autoptr(GPtrArray) files = g_ptr_array_new_with_free_func (g_free); + + g_return_val_if_fail (path != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + if (!fu_common_get_file_list_internal (files, path, error)) return NULL; return g_steal_pointer (&files); @@ -151,8 +177,12 @@ { g_autofree gchar *parent = NULL; + g_return_val_if_fail (filename != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + parent = g_path_get_dirname (filename); - g_debug ("creating path %s", parent); + if (!g_file_test (parent, G_FILE_TEST_IS_DIR)) + g_debug ("creating path %s", parent); if (g_mkdir_with_parents (parent, 0755) == -1) { g_set_error (error, FWUPD_ERROR, @@ -185,6 +215,10 @@ g_autoptr(GFile) file = NULL; g_autoptr(GFile) file_parent = NULL; + g_return_val_if_fail (filename != NULL, FALSE); + g_return_val_if_fail (bytes != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + file = g_file_new_for_path (filename); file_parent = g_file_get_parent (file); if (!g_file_query_exists (file_parent, NULL)) { @@ -212,6 +246,10 @@ { gchar *data = NULL; gsize len = 0; + + g_return_val_if_fail (filename != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + if (!g_file_get_contents (filename, &data, &len, error)) return NULL; g_debug ("reading %s with %" G_GSIZE_FORMAT " bytes", filename, len); @@ -236,7 +274,8 @@ fu_common_get_contents_fd (gint fd, gsize count, GError **error) { #ifdef HAVE_GIO_UNIX - g_autoptr(GBytes) blob = NULL; + guint8 tmp[0x8000] = { 0x0 }; + g_autoptr(GByteArray) buf = g_byte_array_new (); g_autoptr(GError) error_local = NULL; g_autoptr(GInputStream) stream = NULL; @@ -254,15 +293,31 @@ /* read the entire fd to a data blob */ stream = g_unix_input_stream_new (fd, TRUE); - blob = g_input_stream_read_bytes (stream, count, NULL, &error_local); - if (blob == NULL) { - g_set_error_literal (error, + + /* read from stream in 32kB chunks */ + while (TRUE) { + gssize sz; + sz = g_input_stream_read (stream, tmp, sizeof(tmp), NULL, &error_local); + if (sz == 0) + break; + if (sz < 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + error_local->message); + return NULL; + } + g_byte_array_append (buf, tmp, sz); + if (buf->len > count) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - error_local->message); - return NULL; + "cannot read from fd: 0x%x > 0x%x", + buf->len, (guint) count); + return NULL; + } } - return g_steal_pointer (&blob); + return g_byte_array_free_to_bytes (g_steal_pointer (&buf)); #else g_set_error_literal (error, FWUPD_ERROR, @@ -272,6 +327,7 @@ #endif } +#ifdef HAVE_LIBARCHIVE static gboolean fu_common_extract_archive_entry (struct archive_entry *entry, const gchar *dir) { @@ -288,6 +344,7 @@ archive_entry_update_pathname_utf8 (entry, buf); return TRUE; } +#endif /** * fu_common_extract_archive: @@ -304,11 +361,16 @@ gboolean fu_common_extract_archive (GBytes *blob, const gchar *dir, GError **error) { +#ifdef HAVE_LIBARCHIVE gboolean ret = TRUE; int r; struct archive *arch = NULL; struct archive_entry *entry; + g_return_val_if_fail (blob != NULL, FALSE); + g_return_val_if_fail (dir != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + /* decompress anything matching either glob */ g_debug ("decompressing into %s", dir); arch = archive_read_new (); @@ -362,6 +424,13 @@ archive_read_free (arch); } return ret; +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "missing libarchive support"); + return FALSE; +#endif } static void @@ -503,7 +572,7 @@ fu_common_add_argv (argv, "--die-with-parent"); fu_common_add_argv (argv, "--ro-bind /usr /usr"); fu_common_add_argv (argv, "--ro-bind /lib /lib"); - fu_common_add_argv (argv, "--ro-bind /lib64 /lib64"); + fu_common_add_argv (argv, "--ro-bind-try /lib64 /lib64"); fu_common_add_argv (argv, "--ro-bind /bin /bin"); fu_common_add_argv (argv, "--ro-bind /sbin /sbin"); fu_common_add_argv (argv, "--dir /tmp"); @@ -689,6 +758,10 @@ g_autofree gchar *argv_str = NULL; gulong cancellable_id = 0; + g_return_val_if_fail (argv != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + /* create subprocess */ argv_str = g_strjoinv (" ", (gchar **) argv); g_debug ("running '%s'", argv_str); @@ -781,6 +854,33 @@ } /** + * fu_common_write_uint64: + * @buf: A writable buffer + * @val_native: a value in host byte-order + * @endian: A #FuEndianType, e.g. %G_LITTLE_ENDIAN + * + * Writes a value to a buffer using a specified endian. + * + * Since: 1.5.8 + **/ +void +fu_common_write_uint64 (guint8 *buf, guint64 val_native, FuEndianType endian) +{ + guint64 val_hw; + switch (endian) { + case G_BIG_ENDIAN: + val_hw = GUINT64_TO_BE(val_native); + break; + case G_LITTLE_ENDIAN: + val_hw = GUINT64_TO_LE(val_native); + break; + default: + g_assert_not_reached (); + } + memcpy (buf, &val_hw, sizeof(val_hw)); +} + +/** * fu_common_read_uint16: * @buf: A readable buffer * @endian: A #FuEndianType, e.g. %G_LITTLE_ENDIAN @@ -839,6 +939,35 @@ } /** + * fu_common_read_uint64: + * @buf: A readable buffer + * @endian: A #FuEndianType, e.g. %G_LITTLE_ENDIAN + * + * Read a value from a buffer using a specified endian. + * + * Returns: a value in host byte-order + * + * Since: 1.5.8 + **/ +guint64 +fu_common_read_uint64 (const guint8 *buf, FuEndianType endian) +{ + guint64 val_hw, val_native; + memcpy (&val_hw, buf, sizeof(val_hw)); + switch (endian) { + case G_BIG_ENDIAN: + val_native = GUINT64_FROM_BE(val_hw); + break; + case G_LITTLE_ENDIAN: + val_native = GUINT64_FROM_LE(val_hw); + break; + default: + g_assert_not_reached (); + } + return val_native; +} + +/** * fu_common_strtoull: * @str: A string, e.g. "0x1234" * @@ -1026,6 +1155,12 @@ if (tmp != NULL) return g_build_filename (tmp, FWUPD_LOCALSTATEDIR, NULL); return g_build_filename (FWUPD_LOCALSTATEDIR, NULL); + /* /proc */ + case FU_PATH_KIND_PROCFS: + tmp = g_getenv ("FWUPD_PROCFS"); + if (tmp != NULL) + return g_strdup (tmp); + return g_strdup ("/proc"); /* /sys/firmware */ case FU_PATH_KIND_SYSFSDIR_FW: tmp = g_getenv ("FWUPD_SYSFSFWDIR"); @@ -1050,6 +1185,12 @@ if (tmp != NULL) return g_strdup (tmp); return g_strdup ("/sys/kernel/security"); + /* /sys/firmware/acpi/tables */ + case FU_PATH_KIND_ACPI_TABLES: + tmp = g_getenv ("FWUPD_ACPITABLESDIR"); + if (tmp != NULL) + return g_strdup (tmp); + return g_strdup ("/sys/firmware/acpi/tables"); /* /etc */ case FU_PATH_KIND_SYSCONFDIR: tmp = g_getenv ("FWUPD_SYSCONFDIR"); @@ -1210,6 +1351,9 @@ { const gchar *p = text; gsize width = 0; + + g_return_val_if_fail (text != NULL, 0); + while (*p) { gunichar c = g_utf8_get_char (p); if (g_unichar_iswide (c)) @@ -1235,7 +1379,7 @@ void fu_common_string_append_kv (GString *str, guint idt, const gchar *key, const gchar *value) { - const guint align = 25; + const guint align = 24; gsize keysz; g_return_if_fail (idt * 2 < align); @@ -1577,7 +1721,7 @@ * @bytes: a #GBytes * @sz: the desired size in bytes * - * Pads a GBytes to a given @sz with `0xff`. + * Pads a GBytes to a minimum @sz with `0xff`. * * Return value: (transfer full): a #GBytes * @@ -1588,7 +1732,8 @@ { gsize bytes_sz; - g_return_val_if_fail (g_bytes_get_size (bytes) <= sz, NULL); + g_return_val_if_fail (bytes != NULL, NULL); + g_return_val_if_fail (sz != 0, NULL); /* pad */ bytes_sz = g_bytes_get_size (bytes); @@ -1600,11 +1745,48 @@ return g_bytes_new_take (data_new, sz); } - /* exactly right */ + /* not required */ return g_bytes_ref (bytes); } /** + * fu_common_bytes_new_offset: + * @bytes: a #GBytes + * @offset: where subsection starts at + * @length: length of subsection + * @error: A #GError or %NULL + * + * Creates a #GBytes which is a subsection of another #GBytes. + * + * Return value: (transfer full): a #GBytes, or #NULL if range is invalid + * + * Since: 1.5.4 + **/ +GBytes * +fu_common_bytes_new_offset (GBytes *bytes, + gsize offset, + gsize length, + GError **error) +{ + g_return_val_if_fail (bytes != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* sanity check */ + if (offset + length > g_bytes_get_size (bytes)) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "cannot create bytes @0x%02x for 0x%02x " + "as buffer only 0x%04x bytes in size", + (guint) offset, + (guint) length, + (guint) g_bytes_get_size (bytes)); + return NULL; + } + return g_bytes_new_from_bytes (bytes, offset, length); +} + +/** * fu_common_realpath: * @filename: a filename * @error: A #GError or %NULL @@ -1621,6 +1803,7 @@ char full_tmp[PATH_MAX]; g_return_val_if_fail (filename != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); #ifdef HAVE_REALPATH if (realpath (filename, full_tmp) == NULL) { @@ -1672,6 +1855,55 @@ #endif } +static gint +fu_common_filename_glob_sort_cb (gconstpointer a, gconstpointer b) +{ + return g_strcmp0 (*(const gchar **)a, *(const gchar **)b); +} + +/** + * fu_common_filename_glob: + * @directory: a directory path + * @pattern: a glob pattern, e.g. `*foo*` + * @error: A #GError or %NULL + * + * Returns all the filenames that match a specific glob pattern. + * Any results are sorted. No matching files will set @error. + * + * Return value: (element-type utf8) (transfer container): matching files, or %NULL + * + * Since: 1.5.0 + **/ +GPtrArray * +fu_common_filename_glob (const gchar *directory, const gchar *pattern, GError **error) +{ + const gchar *basename; + g_autoptr(GDir) dir = NULL; + g_autoptr(GPtrArray) files = g_ptr_array_new_with_free_func (g_free); + + g_return_val_if_fail (directory != NULL, NULL); + g_return_val_if_fail (pattern != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + dir = g_dir_open (directory, 0, error); + if (dir == NULL) + return NULL; + while ((basename = g_dir_read_name (dir)) != NULL) { + if (!fu_common_fnmatch (pattern, basename)) + continue; + g_ptr_array_add (files, g_build_filename (directory, basename, NULL)); + } + if (files->len == 0) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "no files matched pattern"); + return NULL; + } + g_ptr_array_sort (files, fu_common_filename_glob_sort_cb); + return g_steal_pointer (&files); +} + /** * fu_common_strnsplit: * @str: a string to split @@ -1699,6 +1931,75 @@ } /** + * fu_common_strsafe: + * @str: (nullable): a string to make safe for printing + * @maxsz: maximum size of returned string + * + * Converts a string into something that can be safely printed. + * + * Return value: (transfer full): safe string, or %NULL if there was nothing valid + * + * Since: 1.5.5 + **/ +gchar * +fu_common_strsafe (const gchar *str, gsize maxsz) +{ + gboolean valid = FALSE; + g_autoptr(GString) tmp = NULL; + + /* sanity check */ + if (str == NULL || maxsz == 0) + return NULL; + + /* replace non-printable chars with '.' */ + tmp = g_string_sized_new (maxsz); + for (gsize i = 0; i < maxsz && str[i] != '\0'; i++) { + if (!g_ascii_isprint (str[i])) { + g_string_append_c (tmp, '.'); + continue; + } + g_string_append_c (tmp, str[i]); + if (!g_ascii_isspace (str[i])) + valid = TRUE; + } + + /* if just junk, don't return 'all dots' */ + if (tmp->len == 0 || !valid) + return NULL; + return g_string_free (g_steal_pointer (&tmp), FALSE); +} + + +/** + * fu_common_strjoin_array: + * @separator: (nullable): string to insert between each of the strings, or %NULL + * @array: (element-type utf8): A #GPtrArray + * + * Joins an array of strings together to form one long string, with the optional + * separator inserted between each of them. + * + * If @array has no items, the return value will be an empty string. + * If @array contains a single item, separator will not appear in the resulting + * string. + * + * Returns: a string + * + * Since: 1.5.6 + **/ +gchar * +fu_common_strjoin_array (const gchar *separator, GPtrArray *array) +{ + g_autofree const gchar **strv = NULL; + + g_return_val_if_fail (array != NULL, NULL); + + strv = g_new0 (const gchar *, array->len + 1); + for (guint i = 0; i < array->len; i++) + strv[i] = g_ptr_array_index (array, i); + return g_strjoinv (separator, (gchar **) strv); +} + +/** * fu_memcpy_safe: * @dst: destination buffer * @dst_sz: maximum size of @dst, typically `sizeof(dst)` @@ -1729,6 +2030,10 @@ const guint8 *src, gsize src_sz, gsize src_offset, gsize n, GError **error) { + g_return_val_if_fail (dst != NULL, FALSE); + g_return_val_if_fail (src != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + if (n == 0) return TRUE; @@ -1771,6 +2076,45 @@ } /** + * fu_memdup_safe: + * @src: source buffer + * @n: number of bytes to copy from @src + * @error: A #GError or %NULL + * + * Duplicates some memory using memdup in a safe way. + * + * You don't need to use this function in "obviously correct" cases, nor should + * you use it when performance is a concern. Only us it when you're not sure if + * malicious data from a device or firmware could cause memory corruption. + * + * NOTE: This function intentionally limits allocation size to 1GB. + * + * Return value: (transfer full): block of allocated memory, or %NULL for an error. + * + * Since: 1.5.6 + **/ +guint8 * +fu_memdup_safe (const guint8 *src, gsize n, GError **error) +{ + /* sanity check */ + if (n > 0x40000000) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "cannot allocate %uGB of memory", + (guint) (n / 0x40000000)); + return NULL; + } + +#if GLIB_CHECK_VERSION(2,67,3) + /* linear block of memory */ + return g_memdup2 (src, n); +#else + return g_memdup (src, (guint) n); +#endif +} + +/** * fu_common_read_uint8_safe: * @buf: source buffer * @bufsz: maximum size of @buf, typically `sizeof(buf)` @@ -1796,6 +2140,10 @@ GError **error) { guint8 tmp; + + g_return_val_if_fail (buf != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + if (!fu_memcpy_safe (&tmp, sizeof(tmp), 0x0, /* dst */ buf, bufsz, offset, /* src */ sizeof(tmp), error)) @@ -1833,6 +2181,10 @@ GError **error) { guint8 dst[2] = { 0x0 }; + + g_return_val_if_fail (buf != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + if (!fu_memcpy_safe (dst, sizeof(dst), 0x0, /* dst */ buf, bufsz, offset, /* src */ sizeof(dst), error)) @@ -1870,6 +2222,10 @@ GError **error) { guint8 dst[4] = { 0x0 }; + + g_return_val_if_fail (buf != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + if (!fu_memcpy_safe (dst, sizeof(dst), 0x0, /* dst */ buf, bufsz, offset, /* src */ sizeof(dst), error)) @@ -1880,34 +2236,222 @@ } /** - * fu_byte_array_append_uint8: - * @array: A #GByteArray - * @data: #guint8 + * fu_common_read_uint64_safe: + * @buf: source buffer + * @bufsz: maximum size of @buf, typically `sizeof(buf)` + * @offset: offset in bytes into @buf to copy from + * @value: (out) (allow-none): the parsed value + * @endian: A #FuEndianType, e.g. %G_LITTLE_ENDIAN + * @error: A #GError or %NULL * - * Adds a 8 bit integer to a byte array + * Read a value from a buffer using a specified endian in a safe way. * - * Since: 1.3.1 + * You don't need to use this function in "obviously correct" cases, nor should + * you use it when performance is a concern. Only us it when you're not sure if + * malicious data from a device or firmware could cause memory corruption. + * + * Return value: %TRUE if @value was set, %FALSE otherwise + * + * Since: 1.5.8 **/ -void -fu_byte_array_append_uint8 (GByteArray *array, guint8 data) +gboolean +fu_common_read_uint64_safe (const guint8 *buf, + gsize bufsz, + gsize offset, + guint64 *value, + FuEndianType endian, + GError **error) { - g_byte_array_append (array, &data, sizeof(data)); + guint8 dst[8] = { 0x0 }; + + g_return_val_if_fail (buf != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + if (!fu_memcpy_safe (dst, sizeof(dst), 0x0, /* dst */ + buf, bufsz, offset, /* src */ + sizeof(dst), error)) + return FALSE; + if (value != NULL) + *value = fu_common_read_uint64 (dst, endian); + return TRUE; } /** - * fu_byte_array_append_uint16: - * @array: A #GByteArray - * @data: #guint16 - * @endian: #FuEndianType + * fu_common_write_uint8_safe: + * @buf: source buffer + * @bufsz: maximum size of @buf, typically `sizeof(buf)` + * @offset: offset in bytes into @buf to write to + * @value: the value to write + * @error: A #GError or %NULL * - * Adds a 16 bit integer to a byte array + * Write a value to a buffer in a safe way. * - * Since: 1.3.1 + * You don't need to use this function in "obviously correct" cases, nor should + * you use it when performance is a concern. Only us it when you're not sure if + * malicious data from a device or firmware could cause memory corruption. + * + * Return value: %TRUE if @value was written, %FALSE otherwise + * + * Since: 1.5.8 **/ -void -fu_byte_array_append_uint16 (GByteArray *array, guint16 data, FuEndianType endian) -{ - guint8 buf[2]; +gboolean +fu_common_write_uint8_safe (guint8 *buf, + gsize bufsz, + gsize offset, + guint8 value, + GError **error) +{ + g_return_val_if_fail (buf != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + return fu_memcpy_safe (buf, bufsz, offset, /* dst */ + &value, sizeof(value), 0x0, /* src */ + sizeof(value), error); +} + +/** + * fu_common_write_uint16_safe: + * @buf: source buffer + * @bufsz: maximum size of @buf, typically `sizeof(buf)` + * @offset: offset in bytes into @buf to write to + * @value: the value to write + * @endian: A #FuEndianType, e.g. %G_LITTLE_ENDIAN + * @error: A #GError or %NULL + * + * Write a value to a buffer using a specified endian in a safe way. + * + * You don't need to use this function in "obviously correct" cases, nor should + * you use it when performance is a concern. Only us it when you're not sure if + * malicious data from a device or firmware could cause memory corruption. + * + * Return value: %TRUE if @value was written, %FALSE otherwise + * + * Since: 1.5.8 + **/ +gboolean +fu_common_write_uint16_safe (guint8 *buf, + gsize bufsz, + gsize offset, + guint16 value, + FuEndianType endian, + GError **error) +{ + guint8 tmp[2] = { 0x0 }; + + g_return_val_if_fail (buf != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + fu_common_write_uint16 (tmp, value, endian); + return fu_memcpy_safe (buf, bufsz, offset, /* dst */ + tmp, sizeof(tmp), 0x0, /* src */ + sizeof(tmp), error); +} + +/** + * fu_common_write_uint32_safe: + * @buf: source buffer + * @bufsz: maximum size of @buf, typically `sizeof(buf)` + * @offset: offset in bytes into @buf to write to + * @value: the value to write + * @endian: A #FuEndianType, e.g. %G_LITTLE_ENDIAN + * @error: A #GError or %NULL + * + * Write a value to a buffer using a specified endian in a safe way. + * + * You don't need to use this function in "obviously correct" cases, nor should + * you use it when performance is a concern. Only us it when you're not sure if + * malicious data from a device or firmware could cause memory corruption. + * + * Return value: %TRUE if @value was written, %FALSE otherwise + * + * Since: 1.5.8 + **/ +gboolean +fu_common_write_uint32_safe (guint8 *buf, + gsize bufsz, + gsize offset, + guint32 value, + FuEndianType endian, + GError **error) +{ + guint8 tmp[4] = { 0x0 }; + + g_return_val_if_fail (buf != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + fu_common_write_uint32 (tmp, value, endian); + return fu_memcpy_safe (buf, bufsz, offset, /* dst */ + tmp, sizeof(tmp), 0x0, /* src */ + sizeof(tmp), error); +} + +/** + * fu_common_write_uint64_safe: + * @buf: source buffer + * @bufsz: maximum size of @buf, typically `sizeof(buf)` + * @offset: offset in bytes into @buf to write to + * @value: the value to write + * @endian: A #FuEndianType, e.g. %G_LITTLE_ENDIAN + * @error: A #GError or %NULL + * + * Write a value to a buffer using a specified endian in a safe way. + * + * You don't need to use this function in "obviously correct" cases, nor should + * you use it when performance is a concern. Only us it when you're not sure if + * malicious data from a device or firmware could cause memory corruption. + * + * Return value: %TRUE if @value was written, %FALSE otherwise + * + * Since: 1.5.8 + **/ +gboolean +fu_common_write_uint64_safe (guint8 *buf, + gsize bufsz, + gsize offset, + guint64 value, + FuEndianType endian, + GError **error) +{ + guint8 tmp[8] = { 0x0 }; + + g_return_val_if_fail (buf != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + fu_common_write_uint64 (tmp, value, endian); + return fu_memcpy_safe (buf, bufsz, offset, /* dst */ + tmp, sizeof(tmp), 0x0, /* src */ + sizeof(tmp), error); +} + +/** + * fu_byte_array_append_uint8: + * @array: A #GByteArray + * @data: #guint8 + * + * Adds a 8 bit integer to a byte array + * + * Since: 1.3.1 + **/ +void +fu_byte_array_append_uint8 (GByteArray *array, guint8 data) +{ + g_byte_array_append (array, &data, sizeof(data)); +} + +/** + * fu_byte_array_append_uint16: + * @array: A #GByteArray + * @data: #guint16 + * @endian: #FuEndianType + * + * Adds a 16 bit integer to a byte array + * + * Since: 1.3.1 + **/ +void +fu_byte_array_append_uint16 (GByteArray *array, guint16 data, FuEndianType endian) +{ + guint8 buf[2]; fu_common_write_uint16 (buf, data, endian); g_byte_array_append (array, buf, sizeof(buf)); } @@ -1931,6 +2475,42 @@ } /** + * fu_byte_array_append_uint64: + * @array: A #GByteArray + * @data: #guint64 + * @endian: #FuEndianType + * + * Adds a 64 bit integer to a byte array + * + * Since: 1.5.8 + **/ +void +fu_byte_array_append_uint64 (GByteArray *array, guint64 data, FuEndianType endian) +{ + guint8 buf[8]; + fu_common_write_uint64 (buf, data, endian); + g_byte_array_append (array, buf, sizeof(buf)); +} + +/** + * fu_byte_array_set_size: + * @array: a #GByteArray + * @length: the new size of the GByteArray + * + * Sets the size of the GByteArray, expanding it with NULs if necessary. + * + * Since: 1.5.0 + **/ +void +fu_byte_array_set_size (GByteArray *array, guint length) +{ + guint oldlength = array->len; + g_byte_array_set_size (array, length); + if (length > oldlength) + memset (array->data + oldlength, 0x0, length - oldlength); +} + +/** * fu_common_kernel_locked_down: * * Determines if kernel lockdown in effect @@ -1963,3 +2543,665 @@ return FALSE; #endif } + +/** + * fu_common_cpuid: + * @leaf: The CPUID level, now called the 'leaf' by Intel + * @eax: (out) (nullable): EAX register + * @ebx: (out) (nullable): EBX register + * @ecx: (out) (nullable): ECX register + * @edx: (out) (nullable): EDX register + * @error: A #GError or NULL + * + * Calls CPUID and returns the registers for the given leaf. + * + * Return value: %TRUE if the registers are set. + * + * Since: 1.5.0 + **/ +gboolean +fu_common_cpuid (guint32 leaf, + guint32 *eax, + guint32 *ebx, + guint32 *ecx, + guint32 *edx, + GError **error) +{ +#ifdef HAVE_CPUID_H + guint eax_tmp = 0; + guint ebx_tmp = 0; + guint ecx_tmp = 0; + guint edx_tmp = 0; + + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* get vendor */ + __get_cpuid_count (leaf, 0x0, &eax_tmp, &ebx_tmp, &ecx_tmp, &edx_tmp); + if (eax != NULL) + *eax = eax_tmp; + if (ebx != NULL) + *ebx = ebx_tmp; + if (ecx != NULL) + *ecx = ecx_tmp; + if (edx != NULL) + *edx = edx_tmp; + return TRUE; +#else + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "no support"); + return FALSE; +#endif +} + +/** + * fu_common_is_cpu_intel: + * + * Uses CPUID to discover the CPU vendor and check if it is Intel. + * + * Return value: %TRUE if the vendor was Intel. + * Deprecated: 1.5.5: Use fu_common_get_cpu_vendor() instead. + * + * Since: 1.5.0 + **/ +gboolean +fu_common_is_cpu_intel (void) +{ + return fu_common_get_cpu_vendor () == FU_CPU_VENDOR_INTEL; +} + +/** + * fu_common_get_cpu_vendor: + * + * Uses CPUID to discover the CPU vendor. + * + * Return value: a #FuCpuVendor, e.g. %FU_CPU_VENDOR_AMD if the vendor was AMD. + * + * Since: 1.5.5 + **/ +FuCpuVendor +fu_common_get_cpu_vendor (void) +{ +#ifdef HAVE_CPUID_H + guint ebx = 0; + guint ecx = 0; + guint edx = 0; + + if (fu_common_cpuid (0x0, NULL, &ebx, &ecx, &edx, NULL)) { + if (ebx == signature_INTEL_ebx && + edx == signature_INTEL_edx && + ecx == signature_INTEL_ecx) { + return FU_CPU_VENDOR_INTEL; + } + if (ebx == signature_AMD_ebx && + edx == signature_AMD_edx && + ecx == signature_AMD_ecx) { + return FU_CPU_VENDOR_AMD; + } + } +#endif + + /* failed */ + return FU_CPU_VENDOR_UNKNOWN; +} + +/** + * fu_common_is_live_media: + * + * Checks if the user is running from a live media using various heuristics. + * + * Returns: %TRUE if live + * + * Since: 1.4.6 + **/ +gboolean +fu_common_is_live_media (void) +{ + gsize bufsz = 0; + g_autofree gchar *buf = NULL; + g_auto(GStrv) tokens = NULL; + const gchar *args[] = { + "rd.live.image", + "boot=live", + NULL, /* last entry */ + }; + if (g_file_test ("/cdrom/.disk/info", G_FILE_TEST_EXISTS)) + return TRUE; + if (!g_file_get_contents ("/proc/cmdline", &buf, &bufsz, NULL)) + return FALSE; + if (bufsz == 0) + return FALSE; + tokens = fu_common_strnsplit (buf, bufsz - 1, " ", -1); + for (guint i = 0; args[i] != NULL; i++) { + if (g_strv_contains ((const gchar * const *) tokens, args[i])) + return TRUE; + } + return FALSE; +} + +/** + * fu_common_get_memory_size: + * + * Returns the size of physical memory. + * + * Returns: bytes + * + * Since: 1.5.6 + **/ +guint64 +fu_common_get_memory_size (void) +{ +#ifdef _WIN32 + MEMORYSTATUSEX status; + status.dwLength = sizeof(status); + GlobalMemoryStatusEx (&status); + return (guint64) status.ullTotalPhys; +#else + return sysconf (_SC_PHYS_PAGES) * sysconf (_SC_PAGE_SIZE); +#endif +} + +static GPtrArray * +fu_common_get_block_devices (GError **error) +{ + GVariantBuilder builder; + const gchar *obj; + g_autoptr(GVariant) output = NULL; + g_autoptr(GDBusProxy) proxy = NULL; + g_autoptr(GPtrArray) devices = NULL; + g_autoptr(GVariantIter) iter = NULL; + g_autoptr(GDBusConnection) connection = NULL; + + connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); + if (connection == NULL) { + g_prefix_error (error, "failed to get system bus: "); + return NULL; + } + proxy = g_dbus_proxy_new_sync (connection, + G_DBUS_PROXY_FLAGS_NONE, NULL, + UDISKS_DBUS_SERVICE, + UDISKS_DBUS_PATH, + UDISKS_DBUS_MANAGER_INTERFACE, + NULL, error); + if (proxy == NULL) { + g_prefix_error (error, "failed to find %s: ", UDISKS_DBUS_SERVICE); + return NULL; + } + g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); + output = g_dbus_proxy_call_sync (proxy, + "GetBlockDevices", + g_variant_new ("(a{sv})", &builder), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (output == NULL) { + if (error != NULL) + g_dbus_error_strip_remote_error (*error); + g_prefix_error (error, "failed to call %s.%s(): ", + UDISKS_DBUS_SERVICE, + "GetBlockDevices"); + return NULL; + } + devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + g_variant_get (output, "(ao)", &iter); + while (g_variant_iter_next (iter, "&o", &obj)) { + g_autoptr(GDBusProxy) proxy_blk = NULL; + proxy_blk = g_dbus_proxy_new_sync (connection, + G_DBUS_PROXY_FLAGS_NONE, NULL, + UDISKS_DBUS_SERVICE, + obj, + UDISKS_DBUS_INTERFACE_BLOCK, + NULL, error); + if (proxy_blk == NULL) { + g_prefix_error (error, "failed to initialize d-bus proxy for %s: ", obj); + return NULL; + } + g_ptr_array_add (devices, g_steal_pointer (&proxy_blk)); + } + + + return g_steal_pointer (&devices); +} + +static const gchar * +fu_common_convert_to_gpt_type (const gchar *type) +{ + struct { + const gchar *mbr; + const gchar *gpt; + } typeguids[] = { + { "0xef", "c12a7328-f81f-11d2-ba4b-00a0c93ec93b" }, /* esp */ + { "0x0b", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" }, /* fat32 */ + { NULL, NULL } + }; + for (guint i = 0; typeguids[i].mbr != NULL; i++) { + if (g_strcmp0 (type, typeguids[i].mbr) == 0) + return typeguids[i].gpt; + } + return type; +} + +/** + * fu_common_get_volumes_by_kind: + * @kind: A volume kind, typically a GUID + * @error: A #GError or NULL + * + * Finds all volumes of a specific partition type + * + * Returns: (transfer container) (element-type FuVolume): a #GPtrArray, or %NULL if the kind was not found + * + * Since: 1.4.6 + **/ +GPtrArray * +fu_common_get_volumes_by_kind (const gchar *kind, GError **error) +{ + g_autoptr(GPtrArray) devices = NULL; + g_autoptr(GPtrArray) volumes = NULL; + + g_return_val_if_fail (kind != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + devices = fu_common_get_block_devices (error); + if (devices == NULL) + return NULL; + volumes = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + for (guint i = 0; i < devices->len; i++) { + GDBusProxy *proxy_blk = g_ptr_array_index (devices, i); + const gchar *type_str; + g_autoptr(FuVolume) vol = NULL; + g_autoptr(GDBusProxy) proxy_part = NULL; + g_autoptr(GDBusProxy) proxy_fs = NULL; + g_autoptr(GVariant) val = NULL; + + proxy_part = g_dbus_proxy_new_sync (g_dbus_proxy_get_connection (proxy_blk), + G_DBUS_PROXY_FLAGS_NONE, NULL, + UDISKS_DBUS_SERVICE, + g_dbus_proxy_get_object_path (proxy_blk), + UDISKS_DBUS_INTERFACE_PARTITION, + NULL, error); + if (proxy_part == NULL) { + g_prefix_error (error, "failed to initialize d-bus proxy %s: ", + g_dbus_proxy_get_object_path (proxy_blk)); + return NULL; + } + val = g_dbus_proxy_get_cached_property (proxy_part, "Type"); + if (val == NULL) + continue; + + g_variant_get (val, "&s", &type_str); + proxy_fs = g_dbus_proxy_new_sync (g_dbus_proxy_get_connection (proxy_blk), + G_DBUS_PROXY_FLAGS_NONE, NULL, + UDISKS_DBUS_SERVICE, + g_dbus_proxy_get_object_path (proxy_blk), + UDISKS_DBUS_INTERFACE_FILESYSTEM, + NULL, error); + if (proxy_fs == NULL) { + g_prefix_error (error, "failed to initialize d-bus proxy %s: ", + g_dbus_proxy_get_object_path (proxy_blk)); + return NULL; + } + vol = g_object_new (FU_TYPE_VOLUME, + "proxy-block", proxy_blk, + "proxy-filesystem", proxy_fs, + NULL); + + /* convert MBR type to GPT type */ + type_str = fu_common_convert_to_gpt_type (type_str); + g_debug ("device %s, type: %s, internal: %d, fs: %s", + g_dbus_proxy_get_object_path (proxy_blk), type_str, + fu_volume_is_internal (vol), + fu_volume_get_id_type (vol)); + if (g_strcmp0 (type_str, kind) != 0) + continue; + g_ptr_array_add (volumes, g_steal_pointer (&vol)); + } + if (volumes->len == 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "no volumes of type %s", kind); + return NULL; + } + return g_steal_pointer (&volumes); +} + +/** + * fu_common_get_volume_by_device: + * @device: A device string, typcically starting with `/dev/` + * @error: A #GError or NULL + * + * Finds the first volume from the specified device. + * + * Returns: (transfer full): a #GPtrArray, or %NULL if the kind was not found + * + * Since: 1.5.1 + **/ +FuVolume * +fu_common_get_volume_by_device (const gchar *device, GError **error) +{ + g_autoptr(GPtrArray) devices = NULL; + + g_return_val_if_fail (device != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* find matching block device */ + devices = fu_common_get_block_devices (error); + if (devices == NULL) + return NULL; + for (guint i = 0; i < devices->len; i++) { + GDBusProxy *proxy_blk = g_ptr_array_index (devices, i); + g_autoptr(GVariant) val = NULL; + val = g_dbus_proxy_get_cached_property (proxy_blk, "Device"); + if (val == NULL) + continue; + if (g_strcmp0 (g_variant_get_bytestring (val), device) == 0) { + return g_object_new (FU_TYPE_VOLUME, + "proxy-block", proxy_blk, + NULL); + } + } + + /* failed */ + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "no volumes for device %s", + device); + return NULL; +} + +/** + * fu_common_get_volume_by_devnum: + * @devnum: A device number + * @error: A #GError or NULL + * + * Finds the first volume from the specified device. + * + * Returns: (transfer full): a #GPtrArray, or %NULL if the kind was not found + * + * Since: 1.5.1 + **/ +FuVolume * +fu_common_get_volume_by_devnum (guint32 devnum, GError **error) +{ + g_autoptr(GPtrArray) devices = NULL; + + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* find matching block device */ + devices = fu_common_get_block_devices (error); + if (devices == NULL) + return NULL; + for (guint i = 0; i < devices->len; i++) { + GDBusProxy *proxy_blk = g_ptr_array_index (devices, i); + g_autoptr(GVariant) val = NULL; + val = g_dbus_proxy_get_cached_property (proxy_blk, "DeviceNumber"); + if (val == NULL) + continue; + if (devnum == g_variant_get_uint64 (val)) { + return g_object_new (FU_TYPE_VOLUME, + "proxy-block", proxy_blk, + NULL); + } + } + + /* failed */ + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "no volumes for devnum %u", + devnum); + return NULL; +} + +/** + * fu_common_get_esp_default: + * @error: A #GError or NULL + * + * Gets the platform default ESP + * + * Returns: (transfer full): a #FuVolume, or %NULL if the ESP was not found + * + * Since: 1.4.6 + **/ +FuVolume * +fu_common_get_esp_default (GError **error) +{ + const gchar *path_tmp; + gboolean has_internal = FALSE; + g_autoptr(GPtrArray) volumes_fstab = g_ptr_array_new (); + g_autoptr(GPtrArray) volumes_mtab = g_ptr_array_new (); + g_autoptr(GPtrArray) volumes_vfat = g_ptr_array_new (); + g_autoptr(GPtrArray) volumes = NULL; + g_autoptr(GError) error_local = NULL; + + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* for the test suite use local directory for ESP */ + path_tmp = g_getenv ("FWUPD_UEFI_ESP_PATH"); + if (path_tmp != NULL) + return fu_volume_new_from_mount_path (path_tmp); + + volumes = fu_common_get_volumes_by_kind (FU_VOLUME_KIND_ESP, &error_local); + if (volumes == NULL) { + g_debug ("%s, falling back to %s", error_local->message, FU_VOLUME_KIND_BDP); + volumes = fu_common_get_volumes_by_kind (FU_VOLUME_KIND_BDP, error); + if (volumes == NULL) { + g_prefix_error (error, "%s: ", error_local->message); + return NULL; + } + } + + /* are there _any_ internal vfat partitions? + * remember HintSystem is just that -- a hint! */ + for (guint i = 0; i < volumes->len; i++) { + FuVolume *vol = g_ptr_array_index (volumes, i); + g_autofree gchar *type = fu_volume_get_id_type (vol); + if (g_strcmp0 (type, "vfat") == 0 && + fu_volume_is_internal (vol)) { + has_internal = TRUE; + break; + } + } + + /* filter to vfat partitions */ + for (guint i = 0; i < volumes->len; i++) { + FuVolume *vol = g_ptr_array_index (volumes, i); + g_autofree gchar *type = fu_volume_get_id_type (vol); + if (type == NULL) + continue; + if (has_internal && !fu_volume_is_internal (vol)) + continue; + if (g_strcmp0 (type, "vfat") == 0) + g_ptr_array_add (volumes_vfat, vol); + } + if (volumes_vfat->len == 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_FILENAME, + "No ESP found"); + return NULL; + } + for (guint i = 0; i < volumes_vfat->len; i++) { + FuVolume *vol = g_ptr_array_index (volumes_vfat, i); + g_ptr_array_add (fu_volume_is_mounted (vol) ? volumes_mtab : volumes_fstab, vol); + } + if (volumes_mtab->len == 1) { + FuVolume *vol = g_ptr_array_index (volumes_mtab, 0); + return g_object_ref (vol); + } + if (volumes_mtab->len == 0 && volumes_fstab->len == 1) { + FuVolume *vol = g_ptr_array_index (volumes_fstab, 0); + return g_object_ref (vol); + } + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_FILENAME, + "More than one available ESP"); + return NULL; +} + +/** + * fu_common_get_esp_for_path: + * @esp_path: A path to the ESP + * @error: A #GError or NULL + * + * Gets the platform ESP using a UNIX or UDisks path + * + * Returns: (transfer full): a #FuVolume, or %NULL if the ESP was not found + * + * Since: 1.4.6 + **/ +FuVolume * +fu_common_get_esp_for_path (const gchar *esp_path, GError **error) +{ + g_autofree gchar *basename = NULL; + g_autoptr(GPtrArray) volumes = NULL; + g_autoptr(GError) error_local = NULL; + + g_return_val_if_fail (esp_path != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + volumes = fu_common_get_volumes_by_kind (FU_VOLUME_KIND_ESP, &error_local); + if (volumes == NULL) { + /* check if it's a valid directory already */ + if (g_file_test (esp_path, G_FILE_TEST_IS_DIR)) + return fu_volume_new_from_mount_path (esp_path); + g_propagate_error (error, g_steal_pointer (&error_local)); + return NULL; + } + basename = g_path_get_basename (esp_path); + for (guint i = 0; i < volumes->len; i++) { + FuVolume *vol = g_ptr_array_index (volumes, i); + g_autofree gchar *vol_basename = g_path_get_basename (fu_volume_get_mount_point (vol)); + if (g_strcmp0 (basename, vol_basename) == 0) + return g_object_ref (vol); + } + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_FILENAME, + "No ESP with path %s", + esp_path); + return NULL; +} + +/** + * fu_common_crc8: + * @buf: memory buffer + * @bufsz: sizeof buf + * + * Returns the cyclic redundancy check value for the given memory buffer. + * + * Returns: CRC value + * + * Since: 1.5.0 + **/ +guint8 +fu_common_crc8 (const guint8 *buf, gsize bufsz) +{ + guint32 crc = 0; + for (gsize j = bufsz; j > 0; j--) { + crc ^= (*(buf++) << 8); + for (guint32 i = 8; i; i--) { + if (crc & 0x8000) + crc ^= (0x1070 << 3); + crc <<= 1; + } + } + return ~((guint8) (crc >> 8)); +} + +/** + * fu_common_crc16: + * @buf: memory buffer + * @bufsz: sizeof buf + * + * Returns the cyclic redundancy check value for the given memory buffer. + * + * Returns: CRC value + * + * Since: 1.5.0 + **/ +guint16 +fu_common_crc16 (const guint8 *buf, gsize bufsz) +{ + guint16 crc = 0xffff; + for (gsize len = bufsz; len > 0; len--) { + crc = (guint16) (crc ^ (*buf++)); + for (guint8 i = 0; i < 8; i++) { + if (crc & 0x1) { + crc = (crc >> 1) ^ 0xa001; + } else { + crc >>= 1; + } + } + } + return ~crc; +} + +/** + * fu_common_crc32_full: + * @buf: memory buffer + * @bufsz: sizeof buf + * @crc: initial CRC value, typically 0xFFFFFFFF + * @polynomial: CRC polynomial, typically 0xEDB88320 + * + * Returns the cyclic redundancy check value for the given memory buffer. + * + * Returns: CRC value + * + * Since: 1.5.0 + **/ +guint32 +fu_common_crc32_full (const guint8 *buf, gsize bufsz, guint32 crc, guint32 polynomial) +{ + for (guint32 idx = 0; idx < bufsz; idx++) { + guint8 data = *buf++; + crc = crc ^ data; + for (guint32 bit = 0; bit < 8; bit++) { + guint32 mask = -(crc & 1); + crc = (crc >> 1) ^ (polynomial & mask); + } + } + return ~crc; +} + +/** + * fu_common_crc32: + * @buf: memory buffer + * @bufsz: sizeof buf + * + * Returns the cyclic redundancy check value for the given memory buffer. + * + * Returns: CRC value + * + * Since: 1.5.0 + **/ +guint32 +fu_common_crc32 (const guint8 *buf, gsize bufsz) +{ + return fu_common_crc32_full (buf, bufsz, 0xFFFFFFFF, 0xEDB88320); +} + +/** + * fu_common_uri_get_scheme: + * @uri: valid URI, e.g. `https://foo.bar/baz` + * + * Returns the USI scheme for the given URI. + * + * Returns: scheme value, or %NULL if invalid, e.g. `https` + * + * Since: 1.5.6 + **/ +gchar * +fu_common_uri_get_scheme (const gchar *uri) +{ + gchar *tmp; + + g_return_val_if_fail (uri != NULL, NULL); + + tmp = g_strstr_len (uri, -1, ":"); + if (tmp == NULL || tmp[0] == '\0') + return NULL; + return g_utf8_strdown (uri, tmp - uri); +} diff -Nru fwupd-1.4.5/libfwupdplugin/fu-common-cab.c fwupd-1.5.8/libfwupdplugin/fu-common-cab.c --- fwupd-1.4.5/libfwupdplugin/fu-common-cab.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-common-cab.c 2021-03-31 20:08:32.000000000 +0000 @@ -27,6 +27,10 @@ fu_common_cab_build_silo (GBytes *blob, guint64 size_max, GError **error) { g_autoptr(FuCabinet) cabinet = fu_cabinet_new (); + + g_return_val_if_fail (blob != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + fu_cabinet_set_size_max (cabinet, size_max); if (!fu_cabinet_parse (cabinet, blob, FU_CABINET_PARSE_FLAG_NONE, error)) return NULL; diff -Nru fwupd-1.4.5/libfwupdplugin/fu-common-cab.h fwupd-1.5.8/libfwupdplugin/fu-common-cab.h --- fwupd-1.4.5/libfwupdplugin/fu-common-cab.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-common-cab.h 2021-03-31 20:08:32.000000000 +0000 @@ -10,4 +10,5 @@ XbSilo *fu_common_cab_build_silo (GBytes *blob, guint64 size_max, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; diff -Nru fwupd-1.4.5/libfwupdplugin/fu-common-guid.c fwupd-1.5.8/libfwupdplugin/fu-common-guid.c --- fwupd-1.4.5/libfwupdplugin/fu-common-guid.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-common-guid.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/libfwupdplugin/fu-common-guid.h fwupd-1.5.8/libfwupdplugin/fu-common-guid.h --- fwupd-1.4.5/libfwupdplugin/fu-common-guid.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-common-guid.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/libfwupdplugin/fu-common.h fwupd-1.5.8/libfwupdplugin/fu-common.h --- fwupd-1.4.5/libfwupdplugin/fu-common.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-common.h 2021-03-31 20:08:32.000000000 +0000 @@ -8,6 +8,8 @@ #include +#include "fu-volume.h" + /** * FuAppFlags: * @FU_APP_FLAGS_NONE: No flags set @@ -53,9 +55,11 @@ * @FU_PATH_KIND_SYSFSDIR_FW: The sysfs firmware location (IE /sys/firmware) * @FU_PATH_KIND_SYSFSDIR_DRIVERS: The platform sysfs directory (IE /sys/bus/platform/drivers) * @FU_PATH_KIND_SYSFSDIR_TPM: The TPM sysfs directory (IE /sys/class/tpm) + * @FU_PATH_KIND_PROCFS: The procfs location (IE /proc) * @FU_PATH_KIND_POLKIT_ACTIONS: The directory for policy kit actions (IE /usr/share/polkit-1/actions/) * @FU_PATH_KIND_OFFLINE_TRIGGER: The file for the offline trigger (IE /system-update) * @FU_PATH_KIND_SYSFSDIR_SECURITY: The sysfs security location (IE /sys/kernel/security) + * @FU_PATH_KIND_ACPI_TABLES: The location of the ACPI tables * * Path types to use when dynamically determining a path at runtime **/ @@ -71,13 +75,31 @@ FU_PATH_KIND_SYSFSDIR_FW, FU_PATH_KIND_SYSFSDIR_DRIVERS, FU_PATH_KIND_SYSFSDIR_TPM, + FU_PATH_KIND_PROCFS, FU_PATH_KIND_POLKIT_ACTIONS, FU_PATH_KIND_OFFLINE_TRIGGER, FU_PATH_KIND_SYSFSDIR_SECURITY, + FU_PATH_KIND_ACPI_TABLES, /*< private >*/ FU_PATH_KIND_LAST } FuPathKind; +/** + * FuCpuVendor: + * @FU_CPU_VENDOR_UNKNOWN: Unknown + * @FU_CPU_VENDOR_INTEL: Intel + * @FU_CPU_VENDOR_AMD: AMD + * + * The CPU vendor. + **/ +typedef enum { + FU_CPU_VENDOR_UNKNOWN, + FU_CPU_VENDOR_INTEL, + FU_CPU_VENDOR_AMD, + /*< private >*/ + FU_CPU_VENDOR_LAST +} FuCpuVendor; + typedef void (*FuOutputHandler) (const gchar *line, gpointer user_data); @@ -86,38 +108,53 @@ gpointer handler_user_data, guint timeout_ms, GCancellable *cancellable, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gchar *fu_common_get_path (FuPathKind path_kind); gchar *fu_common_realpath (const gchar *filename, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +GPtrArray *fu_common_filename_glob (const gchar *directory, + const gchar *pattern, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_common_fnmatch (const gchar *pattern, const gchar *str); gboolean fu_common_rmtree (const gchar *directory, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; GPtrArray *fu_common_get_files_recursive (const gchar *path, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_common_mkdir_parent (const gchar *filename, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_common_set_contents_bytes (const gchar *filename, GBytes *bytes, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; GBytes *fu_common_get_contents_bytes (const gchar *filename, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; GBytes *fu_common_get_contents_fd (gint fd, gsize count, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_common_extract_archive (GBytes *blob, const gchar *dir, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; GBytes *fu_common_firmware_builder (GBytes *bytes, const gchar *script_fn, const gchar *output_fn, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; GError *fu_common_error_array_get_best (GPtrArray *errors); guint64 fu_common_strtoull (const gchar *str); gchar *fu_common_find_program_in_path (const gchar *basename, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gchar *fu_common_strstrip (const gchar *str); void fu_common_dump_raw (const gchar *log_domain, const gchar *title, @@ -138,15 +175,26 @@ gboolean fu_common_bytes_is_empty (GBytes *bytes); gboolean fu_common_bytes_compare (GBytes *bytes1, GBytes *bytes2, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_common_bytes_compare_raw (const guint8 *buf1, gsize bufsz1, const guint8 *buf2, gsize bufsz2, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; GBytes *fu_common_bytes_pad (GBytes *bytes, gsize sz); +GBytes *fu_common_bytes_new_offset (GBytes *bytes, + gsize offset, + gsize length, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gsize fu_common_strwidth (const gchar *text); +guint8 *fu_memdup_safe (const guint8 *src, + gsize n, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_memcpy_safe (guint8 *dst, gsize dst_sz, gsize dst_offset, @@ -154,25 +202,65 @@ gsize src_sz, gsize src_offset, gsize n, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_common_read_uint8_safe (const guint8 *buf, gsize bufsz, gsize offset, guint8 *value, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_common_read_uint16_safe (const guint8 *buf, gsize bufsz, gsize offset, guint16 *value, FuEndianType endian, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_common_read_uint32_safe (const guint8 *buf, gsize bufsz, gsize offset, guint32 *value, FuEndianType endian, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fu_common_read_uint64_safe (const guint8 *buf, + gsize bufsz, + gsize offset, + guint64 *value, + FuEndianType endian, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fu_common_write_uint8_safe (guint8 *buf, + gsize bufsz, + gsize offset, + guint8 value, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fu_common_write_uint16_safe (guint8 *buf, + gsize bufsz, + gsize offset, + guint16 value, + FuEndianType endian, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fu_common_write_uint32_safe (guint8 *buf, + gsize bufsz, + gsize offset, + guint32 value, + FuEndianType endian, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fu_common_write_uint64_safe (guint8 *buf, + gsize bufsz, + gsize offset, + guint64 value, + FuEndianType endian, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fu_byte_array_set_size (GByteArray *array, + guint length); void fu_byte_array_append_uint8 (GByteArray *array, guint8 data); void fu_byte_array_append_uint16 (GByteArray *array, @@ -181,6 +269,9 @@ void fu_byte_array_append_uint32 (GByteArray *array, guint32 data, FuEndianType endian); +void fu_byte_array_append_uint64 (GByteArray *array, + guint64 data, + FuEndianType endian); void fu_common_write_uint16 (guint8 *buf, guint16 val_native, @@ -188,10 +279,15 @@ void fu_common_write_uint32 (guint8 *buf, guint32 val_native, FuEndianType endian); +void fu_common_write_uint64 (guint8 *buf, + guint64 val_native, + FuEndianType endian); guint16 fu_common_read_uint16 (const guint8 *buf, FuEndianType endian); guint32 fu_common_read_uint32 (const guint8 *buf, FuEndianType endian); +guint64 fu_common_read_uint64 (const guint8 *buf, + FuEndianType endian); guint fu_common_string_replace (GString *string, const gchar *search, @@ -216,4 +312,46 @@ gsize sz, const gchar *delimiter, gint max_tokens); +gchar *fu_common_strsafe (const gchar *str, + gsize maxsz); +gchar *fu_common_strjoin_array (const gchar *separator, + GPtrArray *array); gboolean fu_common_kernel_locked_down (void); +gboolean fu_common_cpuid (guint32 leaf, + guint32 *eax, + guint32 *ebx, + guint32 *ecx, + guint32 *edx, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fu_common_is_cpu_intel (void) +G_DEPRECATED_FOR(fu_common_get_cpu_vendor); +FuCpuVendor fu_common_get_cpu_vendor (void); +gboolean fu_common_is_live_media (void); +guint64 fu_common_get_memory_size (void); +GPtrArray *fu_common_get_volumes_by_kind (const gchar *kind, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +FuVolume *fu_common_get_volume_by_device (const gchar *device, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +FuVolume *fu_common_get_volume_by_devnum (guint32 devnum, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +FuVolume *fu_common_get_esp_for_path (const gchar *esp_path, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +FuVolume *fu_common_get_esp_default (GError **error) + G_GNUC_WARN_UNUSED_RESULT; + +guint8 fu_common_crc8 (const guint8 *buf, + gsize bufsz); +guint16 fu_common_crc16 (const guint8 *buf, + gsize bufsz); +guint32 fu_common_crc32 (const guint8 *buf, + gsize bufsz); +guint32 fu_common_crc32_full (const guint8 *buf, + gsize bufsz, + guint32 crc, + guint32 polynomial); +gchar *fu_common_uri_get_scheme (const gchar *uri); diff -Nru fwupd-1.4.5/libfwupdplugin/fu-common-version.c fwupd-1.5.8/libfwupdplugin/fu-common-version.c --- fwupd-1.4.5/libfwupdplugin/fu-common-version.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-common-version.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -238,35 +238,57 @@ return TRUE; } -static gboolean -fu_common_version_is_valid_semver_char (gchar c) -{ - if (g_ascii_isdigit (c)) - return TRUE; - if (c == '.') - return TRUE; - return FALSE; -} - /** * fu_common_version_ensure_semver: * @version: A version number, e.g. ` V1.2.3 ` * * Builds a semver from the possibly crazy version number. * - * Returns: A version number, e.g. "1.2.3" + * Returns: A version number, e.g. "1.2.3", or %NULL if the version was not valid * * Since: 1.2.9 */ gchar * fu_common_version_ensure_semver (const gchar *version) { - GString *version_safe = g_string_new (NULL); + gboolean dot_valid = FALSE; + guint digit_cnt = 0; + g_autoptr(GString) version_safe = g_string_new (NULL); + + /* invalid */ + if (version == NULL) + return NULL; + + /* hex prefix */ + if (g_str_has_prefix (version, "0x")) { + return fu_common_version_parse_from_format (version, + FWUPD_VERSION_FORMAT_TRIPLET); + } + + /* make sane */ for (guint i = 0; version[i] != '\0'; i++) { - if (fu_common_version_is_valid_semver_char (version[i])) + if (g_ascii_isdigit (version[i])) { g_string_append_c (version_safe, version[i]); + digit_cnt++; + dot_valid = TRUE; + continue; + } + if (version[i] == '-' || version[i] == '~') { + g_string_append_c (version_safe, '.'); + dot_valid = FALSE; + continue; + } + if (version[i] == '.' && dot_valid && version[i + 1] != '\0') { + g_string_append_c (version_safe, version[i]); + dot_valid = FALSE; + continue; + } } - return g_string_free (version_safe, FALSE); + + /* found no digits */ + if (digit_cnt == 0) + return NULL; + return g_string_free (g_steal_pointer (&version_safe), FALSE); } /** @@ -439,15 +461,16 @@ FwupdVersionFormat fmt_base = fu_common_version_convert_base (fmt); FwupdVersionFormat fmt_guess; + g_return_val_if_fail (version != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + /* don't touch */ if (fmt == FWUPD_VERSION_FORMAT_PLAIN) return TRUE; /* nothing we can check for */ - if (fmt == FWUPD_VERSION_FORMAT_UNKNOWN) { - g_debug ("not checking %s as no version format set", version); + if (fmt == FWUPD_VERSION_FORMAT_UNKNOWN) return TRUE; - } /* check the base format */ fmt_guess = fu_common_version_guess_format (version); @@ -464,42 +487,8 @@ return TRUE; } -/** - * fu_common_vercmp_full: - * @version_a: the semver release version, e.g. 1.2.3 - * @version_b: the semver release version, e.g. 1.2.3.1 - * @fmt: a #FwupdVersionFormat, e.g. %FWUPD_VERSION_FORMAT_PLAIN - * - * Compares version numbers for sorting taking into account the version format - * if required. - * - * Returns: -1 if a < b, +1 if a > b, 0 if they are equal, and %G_MAXINT on error - * - * Since: 1.3.9 - */ -gint -fu_common_vercmp_full (const gchar *version_a, - const gchar *version_b, - FwupdVersionFormat fmt) -{ - if (fmt == FWUPD_VERSION_FORMAT_PLAIN) - return g_strcmp0 (version_a, version_b); - return fu_common_vercmp (version_a, version_b); -} - -/** - * fu_common_vercmp: - * @version_a: the semver release version, e.g. 1.2.3 - * @version_b: the semver release version, e.g. 1.2.3.1 - * - * Compares version numbers for sorting. - * - * Returns: -1 if a < b, +1 if a > b, 0 if they are equal, and %G_MAXINT on error - * - * Since: 0.3.5 - */ -gint -fu_common_vercmp (const gchar *version_a, const gchar *version_b) +static gint +fu_common_vercmp_safe (const gchar *version_a, const gchar *version_b) { guint longest_split; g_auto(GStrv) split_a = NULL; @@ -509,7 +498,7 @@ if (version_a == NULL || version_b == NULL) return G_MAXINT; - /* optimisation */ + /* optimization */ if (g_strcmp0 (version_a, version_b) == 0) return 0; @@ -551,3 +540,50 @@ /* we really shouldn't get here */ return 0; } + +/** + * fu_common_vercmp: + * @version_a: the semver release version, e.g. 1.2.3 + * @version_b: the semver release version, e.g. 1.2.3.1 + * + * Compares version numbers for sorting. + * + * Returns: -1 if a < b, +1 if a > b, 0 if they are equal, and %G_MAXINT on error + * + * Since: 0.3.5 + */ +gint +fu_common_vercmp (const gchar *version_a, const gchar *version_b) +{ + return fu_common_vercmp_safe (version_a, version_b); +} + +/** + * fu_common_vercmp_full: + * @version_a: the semver release version, e.g. 1.2.3 + * @version_b: the semver release version, e.g. 1.2.3.1 + * @fmt: a #FwupdVersionFormat, e.g. %FWUPD_VERSION_FORMAT_PLAIN + * + * Compares version numbers for sorting taking into account the version format + * if required. + * + * Returns: -1 if a < b, +1 if a > b, 0 if they are equal, and %G_MAXINT on error + * + * Since: 1.3.9 + */ +gint +fu_common_vercmp_full (const gchar *version_a, + const gchar *version_b, + FwupdVersionFormat fmt) +{ + if (fmt == FWUPD_VERSION_FORMAT_PLAIN) + return g_strcmp0 (version_a, version_b); + if (fmt == FWUPD_VERSION_FORMAT_HEX) { + g_autofree gchar *hex_a = NULL; + g_autofree gchar *hex_b = NULL; + hex_a = fu_common_version_parse_from_format (version_a, fmt); + hex_b = fu_common_version_parse_from_format (version_b, fmt); + return fu_common_vercmp_safe (hex_a, hex_b); + } + return fu_common_vercmp_safe (version_a, version_b); +} diff -Nru fwupd-1.4.5/libfwupdplugin/fu-common-version.h fwupd-1.5.8/libfwupdplugin/fu-common-version.h --- fwupd-1.4.5/libfwupdplugin/fu-common-version.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-common-version.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -29,4 +29,5 @@ FwupdVersionFormat fu_common_version_guess_format (const gchar *version); gboolean fu_common_version_verify_format (const gchar *version, FwupdVersionFormat fmt, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; diff -Nru fwupd-1.4.5/libfwupdplugin/fu-device.c fwupd-1.5.8/libfwupdplugin/fu-device.c --- fwupd-1.4.5/libfwupdplugin/fu-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2020 Richard Hughes + * Copyright (C) 2015 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -20,6 +20,9 @@ #include "fwupd-common.h" #include "fwupd-device-private.h" +#define FU_DEVICE_RETRY_OPEN_COUNT 5 +#define FU_DEVICE_RETRY_OPEN_DELAY 500 /* ms */ + /** * SECTION:fu-device * @short_description: a physical or logical device @@ -36,19 +39,19 @@ gchar *equivalent_id; gchar *physical_id; gchar *logical_id; + gchar *backend_id; gchar *proxy_guid; FuDevice *alternate; - FuDevice *parent; /* noref */ FuDevice *proxy; /* noref */ FuQuirks *quirks; - GHashTable *metadata; + GHashTable *metadata; /* (nullable) */ GRWLock metadata_mutex; GPtrArray *parent_guids; GRWLock parent_guids_mutex; - GPtrArray *children; guint remove_delay; /* ms */ guint progress; - guint order; + guint battery_level; + gint order; guint priority; guint poll_id; gboolean done_probe; @@ -61,6 +64,7 @@ GPtrArray *possible_plugins; GPtrArray *retry_recs; /* of FuDeviceRetryRecovery */ guint retry_delay; + FuDeviceInternalFlags internal_flags; } FuDevicePrivate; typedef struct { @@ -72,10 +76,11 @@ enum { PROP_0, PROP_PROGRESS, + PROP_BATTERY_LEVEL, PROP_PHYSICAL_ID, PROP_LOGICAL_ID, + PROP_BACKEND_ID, PROP_QUIRKS, - PROP_PARENT, PROP_PROXY, PROP_LAST }; @@ -93,18 +98,21 @@ case PROP_PROGRESS: g_value_set_uint (value, priv->progress); break; + case PROP_BATTERY_LEVEL: + g_value_set_uint (value, priv->battery_level); + break; case PROP_PHYSICAL_ID: g_value_set_string (value, priv->physical_id); break; case PROP_LOGICAL_ID: g_value_set_string (value, priv->logical_id); break; + case PROP_BACKEND_ID: + g_value_set_string (value, priv->backend_id); + break; case PROP_QUIRKS: g_value_set_object (value, priv->quirks); break; - case PROP_PARENT: - g_value_set_object (value, priv->parent); - break; case PROP_PROXY: g_value_set_object (value, priv->proxy); break; @@ -123,18 +131,21 @@ case PROP_PROGRESS: fu_device_set_progress (self, g_value_get_uint (value)); break; + case PROP_BATTERY_LEVEL: + fu_device_set_battery_level (self, g_value_get_uint (value)); + break; case PROP_PHYSICAL_ID: fu_device_set_physical_id (self, g_value_get_string (value)); break; case PROP_LOGICAL_ID: fu_device_set_logical_id (self, g_value_get_string (value)); break; + case PROP_BACKEND_ID: + fu_device_set_backend_id (self, g_value_get_string (value)); + break; case PROP_QUIRKS: fu_device_set_quirks (self, g_value_get_object (value)); break; - case PROP_PARENT: - fu_device_set_parent (self, g_value_get_object (value)); - break; case PROP_PROXY: fu_device_set_proxy (self, g_value_get_object (value)); break; @@ -145,6 +156,123 @@ } /** + * fu_device_internal_flag_to_string: + * @flag: A #FuDeviceInternalFlags, e.g. %FU_DEVICE_INTERNAL_FLAG_MD_SET_ICON + * + * Converts a #FuDeviceInternalFlags to a string. + * + * Return value: identifier string + * + * Since: 1.5.5 + **/ +const gchar * +fu_device_internal_flag_to_string (FuDeviceInternalFlags flag) +{ + if (flag == FU_DEVICE_INTERNAL_FLAG_MD_SET_ICON) + return "md-set-icon"; + if (flag == FU_DEVICE_INTERNAL_FLAG_MD_SET_NAME) + return "md-set-name"; + if (flag == FU_DEVICE_INTERNAL_FLAG_MD_SET_NAME_CATEGORY) + return "md-set-name-category"; + if (flag == FU_DEVICE_INTERNAL_FLAG_MD_SET_VERFMT) + return "md-set-verfmt"; + if (flag == FU_DEVICE_INTERNAL_FLAG_ONLY_SUPPORTED) + return "only-supported"; + if (flag == FU_DEVICE_INTERNAL_FLAG_NO_AUTO_INSTANCE_IDS) + return "no-auto-instance-ids"; + if (flag == FU_DEVICE_INTERNAL_FLAG_ENSURE_SEMVER) + return "ensure-semver"; + if (flag == FU_DEVICE_INTERNAL_FLAG_RETRY_OPEN) + return "retry-open"; + if (flag == FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID) + return "replug-match-guid"; + return NULL; +} + +/** + * fu_device_internal_flag_from_string: + * @flag: A string, e.g. `md-set-icon` + * + * Converts a string to a #FuDeviceInternalFlags. + * + * Return value: enumerated value + * + * Since: 1.5.5 + **/ +FuDeviceInternalFlags +fu_device_internal_flag_from_string (const gchar *flag) +{ + if (g_strcmp0 (flag, "md-set-icon") == 0) + return FU_DEVICE_INTERNAL_FLAG_MD_SET_ICON; + if (g_strcmp0 (flag, "md-set-name") == 0) + return FU_DEVICE_INTERNAL_FLAG_MD_SET_NAME; + if (g_strcmp0 (flag, "md-set-name-category") == 0) + return FU_DEVICE_INTERNAL_FLAG_MD_SET_NAME_CATEGORY; + if (g_strcmp0 (flag, "md-set-verfmt") == 0) + return FU_DEVICE_INTERNAL_FLAG_MD_SET_VERFMT; + if (g_strcmp0 (flag, "only-supported") == 0) + return FU_DEVICE_INTERNAL_FLAG_ONLY_SUPPORTED; + if (g_strcmp0 (flag, "no-auto-instance-ids") == 0) + return FU_DEVICE_INTERNAL_FLAG_NO_AUTO_INSTANCE_IDS; + if (g_strcmp0 (flag, "ensure-semver") == 0) + return FU_DEVICE_INTERNAL_FLAG_ENSURE_SEMVER; + if (g_strcmp0 (flag, "retry-open") == 0) + return FU_DEVICE_INTERNAL_FLAG_RETRY_OPEN; + return FU_DEVICE_INTERNAL_FLAG_UNKNOWN; +} + +/** + * fu_device_add_internal_flag: + * @self: A #FuDevice + * @flag: A #FuDeviceInternalFlags, e.g. %FU_DEVICE_INTERNAL_FLAG_MD_SET_ICON + * + * Adds a private flag that stays internal to the engine and is not leaked to the client. + * + * Since: 1.5.5 + **/ +void +fu_device_add_internal_flag (FuDevice *self, FuDeviceInternalFlags flag) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_DEVICE (self)); + priv->internal_flags |= flag; +} + +/** + * fu_device_remove_internal_flag: + * @self: A #FuDevice + * @flag: A #FuDeviceInternalFlags, e.g. %FU_DEVICE_INTERNAL_FLAG_MD_SET_ICON + * + * Removes a private flag that stays internal to the engine and is not leaked to the client. + * + * Since: 1.5.5 + **/ +void +fu_device_remove_internal_flag (FuDevice *self, FuDeviceInternalFlags flag) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_DEVICE (self)); + priv->internal_flags &= ~flag; +} + +/** + * fu_device_has_internal_flag: + * @self: A #FuDevice + * @flag: A #FuDeviceInternalFlags, e.g. %FU_DEVICE_INTERNAL_FLAG_MD_SET_ICON + * + * Tests for a private flag that stays internal to the engine and is not leaked to the client. + * + * Since: 1.5.5 + **/ +gboolean +fu_device_has_internal_flag (FuDevice *self, FuDeviceInternalFlags flag) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DEVICE (self), FALSE); + return (priv->internal_flags & flag) > 0; +} + +/** * fu_device_get_possible_plugins: * @self: A #FuDevice * @@ -169,12 +297,24 @@ * Adds a plugin name to the list of plugins that *might* be able to handle this * device. This is tyically called from a quirk handler. * - * Since: 1.3.3 + * Duplicate plugin names are ignored. + * + * Since: 1.5.1 **/ -static void +void fu_device_add_possible_plugin (FuDevice *self, const gchar *plugin) { FuDevicePrivate *priv = GET_PRIVATE (self); + + g_return_if_fail (FU_IS_DEVICE (self)); + g_return_if_fail (plugin != NULL); + + /* add if it does not already exist */ +#if GLIB_CHECK_VERSION(2,54,3) + if (g_ptr_array_find_with_equal_func (priv->possible_plugins, plugin, + g_str_equal, NULL)) + return; +#endif g_ptr_array_add (priv->possible_plugins, g_strdup (plugin)); } @@ -230,10 +370,11 @@ } /** - * fu_device_retry: + * fu_device_retry_full: * @self: A #FuDevice * @func: (scope async): A function to execute * @count: The number of tries to try the function + * @delay: The delay between each try in ms * @user_data: (nullable): a helper to pass to @user_data * @error: A #GError * @@ -246,14 +387,15 @@ * If the reset function returns %FALSE, then the function returns straight away * without processing any pending retries. * - * Since: 1.4.0 + * Since: 1.5.5 **/ gboolean -fu_device_retry (FuDevice *self, - FuDeviceRetryFunc func, - guint count, - gpointer user_data, - GError **error) +fu_device_retry_full (FuDevice *self, + FuDeviceRetryFunc func, + guint count, + guint delay, + gpointer user_data, + GError **error) { FuDevicePrivate *priv = GET_PRIVATE (self); @@ -266,8 +408,8 @@ g_autoptr(GError) error_local = NULL; /* delay */ - if (i > 0 && priv->retry_delay > 0) - g_usleep (priv->retry_delay * 1000); + if (i > 0 && delay > 0) + g_usleep (delay * 1000); /* run function, if success return success */ if (func (self, user_data, &error_local)) @@ -321,6 +463,38 @@ } /** + * fu_device_retry: + * @self: A #FuDevice + * @func: (scope async): A function to execute + * @count: The number of tries to try the function + * @user_data: (nullable): a helper to pass to @user_data + * @error: A #GError + * + * Calls a specific function a number of times, optionally handling the error + * with a reset action. + * + * If fu_device_retry_add_recovery() has not been used then all errors are + * considered non-fatal until the last try. + * + * If the reset function returns %FALSE, then the function returns straight away + * without processing any pending retries. + * + * Since: 1.4.0 + **/ +gboolean +fu_device_retry (FuDevice *self, + FuDeviceRetryFunc func, + guint count, + gpointer user_data, + GError **error) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + return fu_device_retry_full (self, func, count, + priv->retry_delay, + user_data, error); +} + +/** * fu_device_poll: * @self: A #FuDevice * @error: A #GError, or %NULL @@ -405,7 +579,7 @@ * * Since: 1.0.8 **/ -guint +gint fu_device_get_order (FuDevice *self) { FuDevicePrivate *priv = GET_PRIVATE (self); @@ -424,7 +598,7 @@ * Since: 1.0.8 **/ void -fu_device_set_order (FuDevice *self, guint order) +fu_device_set_order (FuDevice *self, gint order) { FuDevicePrivate *priv = GET_PRIVATE (self); g_return_if_fail (FU_IS_DEVICE (self)); @@ -498,6 +672,11 @@ { FuDevicePrivate *priv = GET_PRIVATE (self); g_return_if_fail (FU_IS_DEVICE (self)); + + /* not changed */ + if (g_strcmp0 (priv->equivalent_id, equivalent_id) == 0) + return; + g_free (priv->equivalent_id); priv->equivalent_id = g_strdup (equivalent_id); } @@ -536,6 +715,11 @@ { FuDevicePrivate *priv = GET_PRIVATE (self); g_return_if_fail (FU_IS_DEVICE (self)); + + /* not changed */ + if (g_strcmp0 (priv->alternate_id, alternate_id) == 0) + return; + g_free (priv->alternate_id); priv->alternate_id = g_strdup (alternate_id); } @@ -603,9 +787,8 @@ FuDevice * fu_device_get_parent (FuDevice *self) { - FuDevicePrivate *priv = GET_PRIVATE (self); g_return_val_if_fail (FU_IS_DEVICE (self), NULL); - return priv->parent; + return FU_DEVICE (fwupd_device_get_parent (FWUPD_DEVICE (self))); } /** @@ -624,12 +807,13 @@ FuDevice * fu_device_get_root (FuDevice *self) { - FuDevicePrivate *priv = GET_PRIVATE (self); + FuDevice *parent; g_return_val_if_fail (FU_IS_DEVICE (self), NULL); - while (priv->parent != NULL) { - self = priv->parent; - priv = GET_PRIVATE (self); - } + do { + parent = fu_device_get_parent (self); + if (parent != NULL) + self = parent; + } while (parent != NULL); return g_object_ref (self); } @@ -649,17 +833,8 @@ void fu_device_set_parent (FuDevice *self, FuDevice *parent) { - FuDevicePrivate *priv = GET_PRIVATE (self); - g_return_if_fail (FU_IS_DEVICE (self)); - /* if unspecified, always child before parent */ - if (parent != NULL && - fu_device_get_order (parent) == fu_device_get_order (self)) { - g_debug ("auto-setting %s order", fu_device_get_id (parent)); - fu_device_set_order (parent, fu_device_get_order (self) + 1); - } - /* if the parent has quirks, make the child inherit it */ if (parent != NULL) { if (fu_device_get_quirks (self) == NULL && @@ -667,15 +842,7 @@ fu_device_set_quirks (self, fu_device_get_quirks (parent)); } - if (priv->parent != NULL) - g_object_remove_weak_pointer (G_OBJECT (priv->parent), (gpointer *) &priv->parent); - if (parent != NULL) - g_object_add_weak_pointer (G_OBJECT (parent), (gpointer *) &priv->parent); - priv->parent = parent; - - /* this is what goes over D-Bus */ - fwupd_device_set_parent_id (FWUPD_DEVICE (self), - parent != NULL ? fu_device_get_id (parent) : NULL); + fwupd_device_set_parent (FWUPD_DEVICE (self), FWUPD_DEVICE (parent)); } /** @@ -740,9 +907,8 @@ GPtrArray * fu_device_get_children (FuDevice *self) { - FuDevicePrivate *priv = GET_PRIVATE (self); g_return_val_if_fail (FU_IS_DEVICE (self), NULL); - return priv->children; + return fwupd_device_get_children (FWUPD_DEVICE (self)); } /** @@ -759,16 +925,26 @@ fu_device_add_child (FuDevice *self, FuDevice *child) { FuDevicePrivate *priv = GET_PRIVATE (self); + GPtrArray *children; + g_autoptr(GError) error = NULL; + g_return_if_fail (FU_IS_DEVICE (self)); g_return_if_fail (FU_IS_DEVICE (child)); /* add if the child does not already exist */ - for (guint i = 0; i < priv->children->len; i++) { - FuDevice *devtmp = g_ptr_array_index (priv->children, i); - if (devtmp == child) - return; + fwupd_device_add_child (FWUPD_DEVICE (self), FWUPD_DEVICE (child)); + + /* ensure the parent has the MAX() of the childrens removal delay */ + children = fu_device_get_children (self); + for (guint i = 0; i < children->len; i++) { + FuDevice *child_tmp = g_ptr_array_index (children, i); + guint remove_delay = fu_device_get_remove_delay (child_tmp); + if (remove_delay > priv->remove_delay) { + g_debug ("setting remove delay to %u as child is greater than %u", + remove_delay, priv->remove_delay); + priv->remove_delay = remove_delay; + } } - g_ptr_array_add (priv->children, g_object_ref (child)); /* copy from main device if unset */ if (fu_device_get_physical_id (child) == NULL && @@ -776,8 +952,13 @@ fu_device_set_physical_id (child, fu_device_get_physical_id (self)); if (fu_device_get_vendor (child) == NULL) fu_device_set_vendor (child, fu_device_get_vendor (self)); - if (fu_device_get_vendor_id (child) == NULL) - fu_device_set_vendor_id (child, fu_device_get_vendor_id (self)); + if (fu_device_get_vendor_ids(child)->len == 0) { + GPtrArray *vendor_ids = fu_device_get_vendor_ids (self); + for (guint i = 0; i < vendor_ids->len; i++) { + const gchar *vendor_id = g_ptr_array_index (vendor_ids, i); + fu_device_add_vendor_id (child, vendor_id); + } + } if (fu_device_get_icons(child)->len == 0) { GPtrArray *icons = fu_device_get_icons (self); for (guint i = 0; i < icons->len; i++) { @@ -787,19 +968,11 @@ } /* ensure the ID is converted */ - fu_device_ensure_id (child, NULL); + if (!fu_device_ensure_id (child, &error)) + g_warning ("failed to ensure child: %s", error->message); /* ensure the parent is also set on the child */ fu_device_set_parent (child, self); - - /* order devices so they are updated in the correct sequence */ - if (fu_device_has_flag (child, FWUPD_DEVICE_FLAG_INSTALL_PARENT_FIRST)) { - if (priv->order >= fu_device_get_order (child)) - fu_device_set_order (child, priv->order + 1); - } else { - if (priv->order <= fu_device_get_order (child)) - priv->order = fu_device_get_order (child) + 1; - } } /** @@ -978,16 +1151,22 @@ fu_device_set_summary (self, value); return TRUE; } + if (g_strcmp0 (key, FU_QUIRKS_BRANCH) == 0) { + fu_device_set_branch (self, value); + return TRUE; + } if (g_strcmp0 (key, FU_QUIRKS_VENDOR) == 0) { fu_device_set_vendor (self, value); return TRUE; } if (g_strcmp0 (key, FU_QUIRKS_VENDOR_ID) == 0) { - fu_device_set_vendor_id (self, value); + fu_device_add_vendor_id (self, value); return TRUE; } if (g_strcmp0 (key, FU_QUIRKS_PROTOCOL) == 0) { - fu_device_set_protocol (self, value); + g_auto(GStrv) sections = g_strsplit (value, ",", -1); + for (guint i = 0; sections[i] != NULL; i++) + fu_device_add_protocol (self, sections[i]); return TRUE; } if (g_strcmp0 (key, FU_QUIRKS_VERSION) == 0) { @@ -1062,6 +1241,7 @@ G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "device GType %s not supported", value); + return FALSE; } return TRUE; } @@ -1265,6 +1445,7 @@ const gchar *instance_id, FuDeviceInstanceFlags flags) { + FuDevicePrivate *priv = GET_PRIVATE (self); g_autofree gchar *guid = NULL; if (fwupd_guid_is_valid (instance_id)) { g_warning ("use fu_device_add_guid(\"%s\") instead!", instance_id); @@ -1280,6 +1461,10 @@ fu_device_add_guid_quirks (self, guid); if ((flags & FU_DEVICE_INSTANCE_FLAG_ONLY_QUIRKS) == 0) fwupd_device_add_instance_id (FWUPD_DEVICE (self), instance_id); + + /* already done by ->setup(), so this must be ->registered() */ + if (priv->done_setup) + fwupd_device_add_guid (FWUPD_DEVICE (self), guid); } /** @@ -1398,6 +1583,8 @@ g_return_val_if_fail (FU_IS_DEVICE (self), NULL); g_return_val_if_fail (key != NULL, NULL); g_return_val_if_fail (locker != NULL, NULL); + if (priv->metadata == NULL) + return NULL; return g_hash_table_lookup (priv->metadata, key); } @@ -1423,6 +1610,8 @@ g_return_val_if_fail (key != NULL, FALSE); g_return_val_if_fail (locker != NULL, FALSE); + if (priv->metadata == NULL) + return FALSE; tmp = g_hash_table_lookup (priv->metadata, key); if (tmp == NULL) return FALSE; @@ -1453,6 +1642,8 @@ g_return_val_if_fail (key != NULL, G_MAXUINT); g_return_val_if_fail (locker != NULL, G_MAXUINT); + if (priv->metadata == NULL) + return G_MAXUINT; tmp = g_hash_table_lookup (priv->metadata, key); if (tmp == NULL) return G_MAXUINT; @@ -1481,6 +1672,8 @@ g_return_if_fail (FU_IS_DEVICE (self)); g_return_if_fail (key != NULL); g_return_if_fail (locker != NULL); + if (priv->metadata == NULL) + return; g_hash_table_remove (priv->metadata, key); } @@ -1503,6 +1696,10 @@ g_return_if_fail (key != NULL); g_return_if_fail (value != NULL); g_return_if_fail (locker != NULL); + if (priv->metadata == NULL) { + priv->metadata = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_free); + } g_hash_table_insert (priv->metadata, g_strdup (key), g_strdup (value)); } @@ -1606,6 +1803,7 @@ fu_device_set_id (FuDevice *self, const gchar *id) { FuDevicePrivate *priv = GET_PRIVATE (self); + GPtrArray *children; g_autofree gchar *id_hash = NULL; g_return_if_fail (FU_IS_DEVICE (self)); @@ -1622,8 +1820,9 @@ priv->device_id_valid = TRUE; /* ensure the parent ID is set */ - for (guint i = 0; i < priv->children->len; i++) { - FuDevice *devtmp = g_ptr_array_index (priv->children, i); + children = fu_device_get_children (self); + for (guint i = 0; i < children->len; i++) { + FuDevice *devtmp = g_ptr_array_index (children, i); fwupd_device_set_parent_id (FWUPD_DEVICE (devtmp), id_hash); } } @@ -1670,7 +1869,7 @@ g_return_if_fail (FU_IS_DEVICE (self)); /* sanitize if required */ - if (fu_device_has_flag (self, FWUPD_DEVICE_FLAG_ENSURE_SEMVER)) { + if (fu_device_has_internal_flag (self, FU_DEVICE_INTERNAL_FLAG_ENSURE_SEMVER)) { version_safe = fu_common_version_ensure_semver (version); if (g_strcmp0 (version, version_safe) != 0) g_debug ("converted '%s' to '%s'", version, version_safe); @@ -1679,7 +1878,8 @@ } /* print a console warning for an invalid version, if semver */ - if (!fu_common_version_verify_format (version_safe, fu_device_get_version_format (self), &error)) + if (version_safe != NULL && + !fu_common_version_verify_format (version_safe, fu_device_get_version_format (self), &error)) g_warning ("%s", error->message); /* if different */ @@ -1712,7 +1912,7 @@ g_return_if_fail (FU_IS_DEVICE (self)); /* sanitize if required */ - if (fu_device_has_flag (self, FWUPD_DEVICE_FLAG_ENSURE_SEMVER)) { + if (fu_device_has_internal_flag (self, FU_DEVICE_INTERNAL_FLAG_ENSURE_SEMVER)) { version_safe = fu_common_version_ensure_semver (version); if (g_strcmp0 (version, version_safe) != 0) g_debug ("converted '%s' to '%s'", version, version_safe); @@ -1721,7 +1921,8 @@ } /* print a console warning for an invalid version, if semver */ - if (!fu_common_version_verify_format (version_safe, fu_device_get_version_format (self), &error)) + if (version_safe != NULL && + !fu_common_version_verify_format (version_safe, fu_device_get_version_format (self), &error)) g_warning ("%s", error->message); /* if different */ @@ -1754,7 +1955,7 @@ g_return_if_fail (FU_IS_DEVICE (self)); /* sanitize if required */ - if (fu_device_has_flag (self, FWUPD_DEVICE_FLAG_ENSURE_SEMVER)) { + if (fu_device_has_internal_flag (self, FU_DEVICE_INTERNAL_FLAG_ENSURE_SEMVER)) { version_safe = fu_common_version_ensure_semver (version); if (g_strcmp0 (version, version_safe) != 0) g_debug ("converted '%s' to '%s'", version, version_safe); @@ -1763,7 +1964,8 @@ } /* print a console warning for an invalid version, if semver */ - if (!fu_common_version_verify_format (version_safe, fu_device_get_version_format (self), &error)) + if (version_safe != NULL && + !fu_common_version_verify_format (version_safe, fu_device_get_version_format (self), &error)) g_warning ("%s", error->message); /* if different */ @@ -1856,6 +2058,11 @@ { FuDevicePrivate *priv = GET_PRIVATE (self); g_return_if_fail (FU_IS_DEVICE (self)); + + /* not changed */ + if (g_strcmp0 (priv->logical_id, logical_id) == 0) + return; + g_free (priv->logical_id); priv->logical_id = g_strdup (logical_id); priv->device_id_valid = FALSE; @@ -1863,6 +2070,55 @@ } /** + * fu_device_get_backend_id: + * @self: A #FuDevice + * + * Gets the ID set for the device as recognised by the backend. This is typically + * a Linux sysfs path or USB platform ID. If unset, it also falls back to the + * physical ID as this may be the same value. + * + * Returns: a string value, or %NULL if never set. + * + * Since: 1.5.8 + **/ +const gchar * +fu_device_get_backend_id (FuDevice *self) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DEVICE (self), NULL); + if (priv->backend_id != NULL) + return priv->backend_id; + return priv->physical_id; +} + +/** + * fu_device_set_backend_id: + * @self: A #FuDevice + * @backend_id: a string, e.g. `dev2` + * + * Sets the backend ID on the device. This is designed to disambiguate devices + * with the same physical ID. This is typically a Linux sysfs path or USB + * platform ID. + * + * Since: 1.5.8 + **/ +void +fu_device_set_backend_id (FuDevice *self, const gchar *backend_id) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_DEVICE (self)); + + /* not changed */ + if (g_strcmp0 (priv->backend_id, backend_id) == 0) + return; + + g_free (priv->backend_id); + priv->backend_id = g_strdup (backend_id); + priv->device_id_valid = FALSE; + g_object_notify (G_OBJECT (self), "backend-id"); +} + +/** * fu_device_get_proxy_guid: * @self: A #FuDevice * @@ -1895,6 +2151,11 @@ { FuDevicePrivate *priv = GET_PRIVATE (self); g_return_if_fail (FU_IS_DEVICE (self)); + + /* not changed */ + if (g_strcmp0 (priv->proxy_guid, proxy_guid) == 0) + return; + g_free (priv->proxy_guid); priv->proxy_guid = g_strdup (proxy_guid); } @@ -1913,7 +2174,10 @@ fu_device_get_protocol (FuDevice *self) { g_return_val_if_fail (FU_IS_DEVICE (self), NULL); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" return fwupd_device_get_protocol (FWUPD_DEVICE (self)); +#pragma GCC diagnostic pop } /** @@ -1929,7 +2193,7 @@ fu_device_set_protocol (FuDevice *self, const gchar *protocol) { g_return_if_fail (FU_IS_DEVICE (self)); - fwupd_device_set_protocol (FWUPD_DEVICE (self), protocol); + fwupd_device_add_protocol (FWUPD_DEVICE (self), protocol); } /** @@ -1954,6 +2218,11 @@ FuDevicePrivate *priv = GET_PRIVATE (self); g_return_if_fail (FU_IS_DEVICE (self)); g_return_if_fail (physical_id != NULL); + + /* not changed */ + if (g_strcmp0 (priv->physical_id, physical_id) == 0) + return; + g_free (priv->physical_id); priv->physical_id = g_strdup (physical_id); priv->device_id_valid = FALSE; @@ -2009,27 +2278,39 @@ if (flag & FWUPD_DEVICE_FLAG_INSTALL_ALL_RELEASES) flag |= FWUPD_DEVICE_FLAG_VERSION_CHECK_REQUIRED; fwupd_device_add_flag (FWUPD_DEVICE (self), flag); + + /* activatable devices shouldn't be allowed to update again until activated */ + /* don't let devices be updated until activated */ + if (flag & FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION) { + fwupd_device_remove_flag (FWUPD_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fwupd_device_add_flag (FWUPD_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN); + } } static void fu_device_set_custom_flag (FuDevice *self, const gchar *hint) { FwupdDeviceFlags flag; + FuDeviceInternalFlags internal_flag; /* is this a negated device flag */ if (g_str_has_prefix (hint, "~")) { flag = fwupd_device_flag_from_string (hint + 1); if (flag != FWUPD_DEVICE_FLAG_UNKNOWN) fu_device_remove_flag (self, flag); + internal_flag = fu_device_internal_flag_from_string (hint + 1); + if (internal_flag != FU_DEVICE_INTERNAL_FLAG_UNKNOWN) + fu_device_remove_internal_flag (self, internal_flag); return; } /* is this a known device flag */ flag = fwupd_device_flag_from_string (hint); - if (flag != FWUPD_DEVICE_FLAG_UNKNOWN) { + if (flag != FWUPD_DEVICE_FLAG_UNKNOWN) fu_device_add_flag (self, flag); - return; - } + internal_flag = fu_device_internal_flag_from_string (hint); + if (internal_flag != FU_DEVICE_INTERNAL_FLAG_UNKNOWN) + fu_device_remove_internal_flag (self, internal_flag); } /** @@ -2239,6 +2520,72 @@ fu_device_set_progress (self, (guint) percentage); } +/** + * fu_device_sleep_with_progress: + * @self: A #FuDevice + * @delay_secs: the delay in seconds + * + * Sleeps, setting the device progress from 0..100% as time continues. + * The value is gven in whole seconds as it does not make sense to show the + * progressbar advancing so quickly for durations of less than one second. + * + * Since: 1.5.0 + **/ +void +fu_device_sleep_with_progress (FuDevice *self, guint delay_secs) +{ + gulong delay_us_pc = (delay_secs * G_USEC_PER_SEC) / 100; + + g_return_if_fail (FU_IS_DEVICE (self)); + g_return_if_fail (delay_secs > 0); + + fu_device_set_progress (self, 0); + for (guint i = 0; i < 100; i++) { + g_usleep (delay_us_pc); + fu_device_set_progress (self, i + 1); + } +} + +/** + * fu_device_get_battery_level: + * @self: A #FuDevice + * + * Returns the battery level. + * + * Returns: value in percent + * + * Since: 1.5.8 + **/ +guint +fu_device_get_battery_level (FuDevice *self) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DEVICE (self), 0); + return priv->battery_level; +} + +/** + * fu_device_set_battery_level: + * @self: A #FuDevice + * @battery_level: the percentage value + * + * Sets the battery level, or 0 for invalid. Setting this allows fwupd to show + * a warning if the device change is too low to perform the update. + * + * Since: 1.5.8 + **/ +void +fu_device_set_battery_level (FuDevice *self, guint battery_level) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_DEVICE (self)); + g_return_if_fail (battery_level <= 100); + if (priv->battery_level == battery_level) + return; + priv->battery_level = battery_level; + g_object_notify (G_OBJECT (self), "battery-level"); +} + static void fu_device_add_string (FuDevice *self, guint idt, GString *str) { @@ -2246,7 +2593,6 @@ FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); FuDevicePrivate *priv = GET_PRIVATE (self); g_autofree gchar *tmp = NULL; - g_autoptr(GList) keys = NULL; g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new (&priv->metadata_mutex); g_return_if_fail (locker != NULL); @@ -2265,10 +2611,14 @@ fu_common_string_append_kv (str, idt + 1, "PhysicalId", priv->physical_id); if (priv->logical_id != NULL) fu_common_string_append_kv (str, idt + 1, "LogicalId", priv->logical_id); + if (priv->backend_id != NULL) + fu_common_string_append_kv (str, idt + 1, "BackendId", priv->backend_id); if (priv->proxy != NULL) fu_common_string_append_kv (str, idt + 1, "ProxyId", fu_device_get_id (priv->proxy)); if (priv->proxy_guid != NULL) fu_common_string_append_kv (str, idt + 1, "ProxyGuid", priv->proxy_guid); + if (priv->battery_level != 0) + fu_common_string_append_ku (str, idt + 1, "BatteryLevel", priv->battery_level); if (priv->size_min > 0) { g_autofree gchar *sz = g_strdup_printf ("%" G_GUINT64_FORMAT, priv->size_min); fu_common_string_append_kv (str, idt + 1, "FirmwareSizeMin", sz); @@ -2277,15 +2627,33 @@ g_autofree gchar *sz = g_strdup_printf ("%" G_GUINT64_FORMAT, priv->size_max); fu_common_string_append_kv (str, idt + 1, "FirmwareSizeMax", sz); } - if (priv->order > 0) + if (priv->order != G_MAXINT) fu_common_string_append_ku (str, idt + 1, "Order", priv->order); if (priv->priority > 0) fu_common_string_append_ku (str, idt + 1, "Priority", priv->priority); - keys = g_hash_table_get_keys (priv->metadata); - for (GList *l = keys; l != NULL; l = l->next) { - const gchar *key = l->data; - const gchar *value = g_hash_table_lookup (priv->metadata, key); - fu_common_string_append_kv (str, idt + 1, key, value); + if (priv->metadata != NULL) { + g_autoptr(GList) keys = g_hash_table_get_keys (priv->metadata); + for (GList *l = keys; l != NULL; l = l->next) { + const gchar *key = l->data; + const gchar *value = g_hash_table_lookup (priv->metadata, key); + fu_common_string_append_kv (str, idt + 1, key, value); + } + } + for (guint i = 0; i < priv->possible_plugins->len; i++) { + const gchar *name = g_ptr_array_index (priv->possible_plugins, i); + fu_common_string_append_kv (str, idt + 1, "PossiblePlugin", name); + } + if (priv->internal_flags != FU_DEVICE_INTERNAL_FLAG_NONE) { + g_autoptr(GString) tmp2 = g_string_new (""); + for (guint i = 0; i < 64; i++) { + if ((priv->internal_flags & ((guint64) 1 << i)) == 0) + continue; + g_string_append_printf (tmp2, "%s|", + fu_device_internal_flag_to_string ((guint64) 1 << i)); + } + if (tmp2->len > 0) + g_string_truncate (tmp2, tmp2->len - 1); + fu_common_string_append_kv (str, idt + 1, "InternalFlags", tmp2->str); } /* subclassed */ @@ -2294,11 +2662,9 @@ /* print children also */ children = fu_device_get_children (self); - if (children != NULL) { - for (guint i = 0; i < children->len; i++) { - FuDevice *child = g_ptr_array_index (children, i); - fu_device_add_string (child, idt + 1, str); - } + for (guint i = 0; i < children->len; i++) { + FuDevice *child = g_ptr_array_index (children, i); + fu_device_add_string (child, idt + 1, str); } } @@ -2463,6 +2829,7 @@ /* optionally subclassed */ if (klass->prepare_firmware != NULL) { + fu_device_set_status (self, FWUPD_STATUS_DECOMPRESSING); firmware = klass->prepare_firmware (self, fw, flags, error); if (firmware == NULL) return NULL; @@ -2506,6 +2873,11 @@ * @error: A #GError * * Reads firmware from the device by calling a plugin-specific vfunc. + * The device subclass should try to ensure the firmware does not contain any + * serial numbers or user-configuration values and can be used to calculate the + * device checksum. + * + * The return value can be converted to a blob of memory using fu_firmware_write(). * * Returns: (transfer full): A #FuFirmware, or %NULL for error * @@ -2515,14 +2887,13 @@ fu_device_read_firmware (FuDevice *self, GError **error) { FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); + g_autoptr(GBytes) fw = NULL; g_return_val_if_fail (FU_IS_DEVICE (self), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - /* no plugin-specific method or device doesn't support */ - if (!fu_device_has_flag (self, FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE) || - klass->read_firmware == NULL) { + /* device does not support reading for verification CRCs */ + if (!fu_device_has_flag (self, FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE)) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, @@ -2531,7 +2902,49 @@ } /* call vfunc */ - return klass->read_firmware (self, error); + if (klass->read_firmware != NULL) + return klass->read_firmware (self, error); + + /* use the default FuFirmware when only ->dump_firmware is provided */ + fw = fu_device_dump_firmware (self, error); + if (fw == NULL) + return NULL; + return fu_firmware_new_from_bytes (fw); +} + +/** + * fu_device_dump_firmware: + * @self: A #FuDevice + * @error: A #GError + * + * Reads the raw firmware image from the device by calling a plugin-specific + * vfunc. This raw firmware image may contain serial numbers or device-specific + * configuration but should be a byte-for-byte match compared to using an + * external SPI programmer. + * + * Returns: (transfer full): A #GBytes, or %NULL for error + * + * Since: 1.5.0 + **/ +GBytes * +fu_device_dump_firmware (FuDevice *self, GError **error) +{ + FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); + + g_return_val_if_fail (FU_IS_DEVICE (self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* use the default FuFirmware when only ->dump_firmware is provided */ + if (klass->dump_firmware == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "not supported"); + return NULL; + } + + /* proxy */ + return klass->dump_firmware (self, error); } /** @@ -2673,6 +3086,13 @@ return klass->cleanup (self, flags, error); } +static gboolean +fu_device_open_cb (FuDevice *self, gpointer user_data, GError **error) +{ + FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); + return klass->open (self, error); +} + /** * fu_device_open: * @self: A #FuDevice @@ -2714,8 +3134,16 @@ /* subclassed */ if (klass->open != NULL) { - if (!klass->open (self, error)) - return FALSE; + if (fu_device_has_internal_flag (self, FU_DEVICE_INTERNAL_FLAG_RETRY_OPEN)) { + if (!fu_device_retry_full (self, fu_device_open_cb, + FU_DEVICE_RETRY_OPEN_COUNT, + FU_DEVICE_RETRY_OPEN_DELAY, + NULL, error)) + return FALSE; + } else { + if (!klass->open (self, error)) + return FALSE; + } } /* setup */ @@ -2855,7 +3283,7 @@ * @self: A #FuDevice * * Converts all the Device Instance IDs added using fu_device_add_instance_id() - * into actual GUIDs, **unless** %FWUPD_DEVICE_FLAG_NO_AUTO_INSTANCE_IDS has + * into actual GUIDs, **unless** %FU_DEVICE_INTERNAL_FLAG_NO_AUTO_INSTANCE_IDS has * been set. * * Plugins will only need to need to call this manually when adding child @@ -2867,23 +3295,17 @@ void fu_device_convert_instance_ids (FuDevice *self) { - FuDevicePrivate *priv = GET_PRIVATE (self); - GPtrArray *instance_ids = fwupd_device_get_instance_ids (FWUPD_DEVICE (self)); + GPtrArray *instance_ids; /* OEM specific hardware */ - if (fu_device_has_flag (self, FWUPD_DEVICE_FLAG_NO_AUTO_INSTANCE_IDS)) + if (fu_device_has_internal_flag (self, FU_DEVICE_INTERNAL_FLAG_NO_AUTO_INSTANCE_IDS)) return; + instance_ids = fwupd_device_get_instance_ids (FWUPD_DEVICE (self)); for (guint i = 0; i < instance_ids->len; i++) { const gchar *instance_id = g_ptr_array_index (instance_ids, i); g_autofree gchar *guid = fwupd_guid_hash_string (instance_id); fwupd_device_add_guid (FWUPD_DEVICE (self), guid); } - - /* convert all children too */ - for (guint i = 0; i < priv->children->len; i++) { - FuDevice *devtmp = g_ptr_array_index (priv->children, i); - fu_device_convert_instance_ids (devtmp); - } } /** @@ -2904,6 +3326,7 @@ { FuDevicePrivate *priv = GET_PRIVATE (self); FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); + GPtrArray *children; g_return_val_if_fail (FU_IS_DEVICE (self), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); @@ -2918,6 +3341,14 @@ return FALSE; } + /* run setup on the children too (unless done already) */ + children = fu_device_get_children (self); + for (guint i = 0; i < children->len; i++) { + FuDevice *child_tmp = g_ptr_array_index (children, i); + if (!fu_device_setup (child_tmp, error)) + return FALSE; + } + /* convert the instance IDs to GUIDs */ fu_device_convert_instance_ids (self); @@ -2977,6 +3408,138 @@ } /** + * fu_device_report_metadata_pre: + * @self: A #FuDevice + * + * Collects metadata that would be useful for debugging a failed update report. + * + * Returns: (transfer full) (nullable): A #GHashTable, or %NULL if there is no data + * + * Since: 1.5.0 + **/ +GHashTable * +fu_device_report_metadata_pre (FuDevice *self) +{ + FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); + g_autoptr(GHashTable) metadata = NULL; + + g_return_val_if_fail (FU_IS_DEVICE (self), NULL); + + /* not implemented */ + if (klass->report_metadata_pre == NULL) + return NULL; + + /* metadata for all devices */ + metadata = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + klass->report_metadata_pre (self, metadata); + return g_steal_pointer (&metadata); +} + +/** + * fu_device_report_metadata_post: + * @self: A #FuDevice + * + * Collects metadata that would be useful for debugging a failed update report. + * + * Returns: (transfer full) (nullable): A #GHashTable, or %NULL if there is no data + * + * Since: 1.5.0 + **/ +GHashTable * +fu_device_report_metadata_post (FuDevice *self) +{ + FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); + g_autoptr(GHashTable) metadata = NULL; + + g_return_val_if_fail (FU_IS_DEVICE (self), NULL); + + /* not implemented */ + if (klass->report_metadata_post == NULL) + return NULL; + + /* metadata for all devices */ + metadata = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + klass->report_metadata_post (self, metadata); + return g_steal_pointer (&metadata); +} + +/** + * fu_device_bind_driver: + * @self: A #FuDevice + * @subsystem: A subsystem string, e.g. `pci` + * @driver: A kernel module name, e.g. `tg3` + * @error: A #GError, or %NULL + * + * Binds a driver to the device, which normally means the kernel driver takes + * control of the hardware. + * + * Returns: %TRUE if driver was bound. + * + * Since: 1.5.0 + **/ +gboolean +fu_device_bind_driver (FuDevice *self, + const gchar *subsystem, + const gchar *driver, + GError **error) +{ + FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); + + g_return_val_if_fail (FU_IS_DEVICE (self), FALSE); + g_return_val_if_fail (subsystem != NULL, FALSE); + g_return_val_if_fail (driver != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* not implemented */ + if (klass->bind_driver == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "not supported"); + return FALSE; + } + + /* subclass */ + return klass->bind_driver (self, subsystem, driver, error); +} + +/** + * fu_device_unbind_driver: + * @self: A #FuDevice + * @error: A #GError, or %NULL + * + * Unbinds the driver from the device, which normally means the kernel releases + * the hardware so it can be used from userspace. + * + * If there is no driver bound then this function will return with success + * without actually doing anything. + * + * Returns: %TRUE if driver was unbound. + * + * Since: 1.5.0 + **/ +gboolean +fu_device_unbind_driver (FuDevice *self, GError **error) +{ + FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); + + g_return_val_if_fail (FU_IS_DEVICE (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* not implemented */ + if (klass->unbind_driver == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "not supported"); + return FALSE; + } + + /* subclass */ + return klass->unbind_driver (self, error); +} + +/** * fu_device_incorporate: * @self: A #FuDevice * @donor: Another #FuDevice @@ -2993,7 +3556,6 @@ FuDevicePrivate *priv_donor = GET_PRIVATE (donor); GPtrArray *instance_ids = fu_device_get_instance_ids (donor); GPtrArray *parent_guids = fu_device_get_parent_guids (donor); - g_autoptr(GList) metadata_keys = NULL; g_return_if_fail (FU_IS_DEVICE (self)); g_return_if_fail (FU_IS_DEVICE (donor)); @@ -3007,6 +3569,8 @@ fu_device_set_physical_id (self, priv_donor->physical_id); if (priv->logical_id == NULL && priv_donor->logical_id != NULL) fu_device_set_logical_id (self, priv_donor->logical_id); + if (priv->backend_id == NULL && priv_donor->backend_id != NULL) + fu_device_set_backend_id (self, priv_donor->backend_id); if (priv->proxy == NULL && priv_donor->proxy != NULL) fu_device_set_proxy (self, priv_donor->proxy); if (priv->proxy_guid == NULL && priv_donor->proxy_guid != NULL) @@ -3018,12 +3582,14 @@ fu_device_add_parent_guid (self, g_ptr_array_index (parent_guids, i)); g_rw_lock_reader_unlock (&priv_donor->parent_guids_mutex); g_rw_lock_reader_lock (&priv_donor->metadata_mutex); - metadata_keys = g_hash_table_get_keys (priv_donor->metadata); - for (GList *l = metadata_keys; l != NULL; l = l->next) { - const gchar *key = l->data; - if (g_hash_table_lookup (priv->metadata, key) == NULL) { - const gchar *value = g_hash_table_lookup (priv_donor->metadata, key); - fu_device_set_metadata (self, key, value); + if (priv->metadata != NULL) { + g_autoptr(GList) keys = g_hash_table_get_keys (priv_donor->metadata); + for (GList *l = keys; l != NULL; l = l->next) { + const gchar *key = l->data; + if (g_hash_table_lookup (priv->metadata, key) == NULL) { + const gchar *value = g_hash_table_lookup (priv_donor->metadata, key); + fu_device_set_metadata (self, key, value); + } } } g_rw_lock_reader_unlock (&priv_donor->metadata_mutex); @@ -3111,25 +3677,29 @@ G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_LOGICAL_ID, pspec); + pspec = g_param_spec_string ("backend-id", NULL, NULL, NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_BACKEND_ID, pspec); + pspec = g_param_spec_uint ("progress", NULL, NULL, 0, 100, 0, G_PARAM_READWRITE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_PROGRESS, pspec); + pspec = g_param_spec_uint ("battery-level", NULL, NULL, + 0, 100, 0, + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_BATTERY_LEVEL, pspec); + pspec = g_param_spec_object ("quirks", NULL, NULL, FU_TYPE_QUIRKS, G_PARAM_READWRITE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_QUIRKS, pspec); - pspec = g_param_spec_object ("parent", NULL, NULL, - FU_TYPE_DEVICE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT | - G_PARAM_STATIC_NAME); - g_object_class_install_property (object_class, PROP_PARENT, pspec); - pspec = g_param_spec_object ("proxy", NULL, NULL, FU_TYPE_DEVICE, G_PARAM_READWRITE | @@ -3142,13 +3712,11 @@ fu_device_init (FuDevice *self) { FuDevicePrivate *priv = GET_PRIVATE (self); - priv->children = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + priv->order = G_MAXINT; priv->parent_guids = g_ptr_array_new_with_free_func (g_free); priv->possible_plugins = g_ptr_array_new_with_free_func (g_free); priv->retry_recs = g_ptr_array_new_with_free_func (g_free); g_rw_lock_init (&priv->parent_guids_mutex); - priv->metadata = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_free); g_rw_lock_init (&priv->metadata_mutex); } @@ -3158,20 +3726,19 @@ FuDevice *self = FU_DEVICE (object); FuDevicePrivate *priv = GET_PRIVATE (self); + g_rw_lock_clear (&priv->metadata_mutex); + g_rw_lock_clear (&priv->parent_guids_mutex); + if (priv->alternate != NULL) g_object_unref (priv->alternate); - if (priv->parent != NULL) - g_object_remove_weak_pointer (G_OBJECT (priv->parent), (gpointer *) &priv->parent); if (priv->proxy != NULL) g_object_remove_weak_pointer (G_OBJECT (priv->proxy), (gpointer *) &priv->proxy); if (priv->quirks != NULL) g_object_unref (priv->quirks); if (priv->poll_id != 0) g_source_remove (priv->poll_id); - g_rw_lock_clear (&priv->metadata_mutex); - g_rw_lock_clear (&priv->parent_guids_mutex); - g_hash_table_unref (priv->metadata); - g_ptr_array_unref (priv->children); + if (priv->metadata != NULL) + g_hash_table_unref (priv->metadata); g_ptr_array_unref (priv->parent_guids); g_ptr_array_unref (priv->possible_plugins); g_ptr_array_unref (priv->retry_recs); @@ -3179,6 +3746,7 @@ g_free (priv->equivalent_id); g_free (priv->physical_id); g_free (priv->logical_id); + g_free (priv->backend_id); g_free (priv->proxy_guid); G_OBJECT_CLASS (fu_device_parent_class)->finalize (object); diff -Nru fwupd-1.4.5/libfwupdplugin/fu-device.h fwupd-1.5.8/libfwupdplugin/fu-device.h --- fwupd-1.4.5/libfwupdplugin/fu-device.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2020 Richard Hughes + * Copyright (C) 2015 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -25,47 +25,78 @@ gboolean (*write_firmware) (FuDevice *self, FuFirmware *firmware, FwupdInstallFlags flags, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; FuFirmware *(*read_firmware) (FuDevice *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean (*detach) (FuDevice *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean (*attach) (FuDevice *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean (*open) (FuDevice *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean (*close) (FuDevice *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean (*probe) (FuDevice *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean (*rescan) (FuDevice *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; FuFirmware *(*prepare_firmware) (FuDevice *self, GBytes *fw, FwupdInstallFlags flags, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean (*set_quirk_kv) (FuDevice *self, const gchar *key, const gchar *value, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean (*setup) (FuDevice *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; void (*incorporate) (FuDevice *self, FuDevice *donor); gboolean (*poll) (FuDevice *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean (*activate) (FuDevice *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean (*reload) (FuDevice *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean (*prepare) (FuDevice *self, FwupdInstallFlags flags, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean (*cleanup) (FuDevice *self, FwupdInstallFlags flags, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; + void (*report_metadata_pre) (FuDevice *self, + GHashTable *metadata); + void (*report_metadata_post)(FuDevice *self, + GHashTable *metadata); + gboolean (*bind_driver) (FuDevice *self, + const gchar *subsystem, + const gchar *driver, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; + gboolean (*unbind_driver) (FuDevice *self, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; + GBytes *(*dump_firmware) (FuDevice *self, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; /*< private >*/ - gpointer padding[16]; + gpointer padding[11]; }; /** @@ -102,7 +133,8 @@ typedef gboolean (*FuDeviceRetryFunc) (FuDevice *device, gpointer user_data, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; FuDevice *fu_device_new (void); @@ -110,6 +142,8 @@ #define fu_device_remove_flag(d,v) fwupd_device_remove_flag(FWUPD_DEVICE(d),v) #define fu_device_has_flag(d,v) fwupd_device_has_flag(FWUPD_DEVICE(d),v) #define fu_device_has_instance_id(d,v) fwupd_device_has_instance_id(FWUPD_DEVICE(d),v) +#define fu_device_has_vendor_id(d,v) fwupd_device_has_vendor_id(FWUPD_DEVICE(d),v) +#define fu_device_has_protocol(d,v) fwupd_device_has_protocol(FWUPD_DEVICE(d),v) #define fu_device_add_checksum(d,v) fwupd_device_add_checksum(FWUPD_DEVICE(d),v) #define fu_device_add_release(d,v) fwupd_device_add_release(FWUPD_DEVICE(d),v) #define fu_device_add_icon(d,v) fwupd_device_add_icon(FWUPD_DEVICE(d),v) @@ -120,12 +154,14 @@ #define fu_device_set_plugin(d,v) fwupd_device_set_plugin(FWUPD_DEVICE(d),v) #define fu_device_set_serial(d,v) fwupd_device_set_serial(FWUPD_DEVICE(d),v) #define fu_device_set_summary(d,v) fwupd_device_set_summary(FWUPD_DEVICE(d),v) +#define fu_device_set_branch(d,v) fwupd_device_set_branch(FWUPD_DEVICE(d),v) #define fu_device_set_update_message(d,v) fwupd_device_set_update_message(FWUPD_DEVICE(d),v) #define fu_device_set_update_image(d,v) fwupd_device_set_update_image(FWUPD_DEVICE(d),v) #define fu_device_set_update_error(d,v) fwupd_device_set_update_error(FWUPD_DEVICE(d),v) #define fu_device_set_update_state(d,v) fwupd_device_set_update_state(FWUPD_DEVICE(d),v) #define fu_device_set_vendor(d,v) fwupd_device_set_vendor(FWUPD_DEVICE(d),v) -#define fu_device_set_vendor_id(d,v) fwupd_device_set_vendor_id(FWUPD_DEVICE(d),v) +#define fu_device_add_vendor_id(d,v) fwupd_device_add_vendor_id(FWUPD_DEVICE(d),v) +#define fu_device_add_protocol(d,v) fwupd_device_add_protocol(FWUPD_DEVICE(d),v) #define fu_device_set_version_raw(d,v) fwupd_device_set_version_raw(FWUPD_DEVICE(d),v) #define fu_device_set_version_lowest_raw(d,v) fwupd_device_set_version_lowest_raw(FWUPD_DEVICE(d),v) #define fu_device_set_version_bootloader_raw(d,v) fwupd_device_set_version_bootloader_raw(FWUPD_DEVICE(d),v) @@ -142,6 +178,7 @@ #define fu_device_get_name(d) fwupd_device_get_name(FWUPD_DEVICE(d)) #define fu_device_get_serial(d) fwupd_device_get_serial(FWUPD_DEVICE(d)) #define fu_device_get_summary(d) fwupd_device_get_summary(FWUPD_DEVICE(d)) +#define fu_device_get_branch(d) fwupd_device_get_branch(FWUPD_DEVICE(d)) #define fu_device_get_id(d) fwupd_device_get_id(FWUPD_DEVICE(d)) #define fu_device_get_plugin(d) fwupd_device_get_plugin(FWUPD_DEVICE(d)) #define fu_device_get_update_error(d) fwupd_device_get_update_error(FWUPD_DEVICE(d)) @@ -154,10 +191,41 @@ #define fu_device_get_version_raw(d) fwupd_device_get_version_raw(FWUPD_DEVICE(d)) #define fu_device_get_version_lowest_raw(d) fwupd_device_get_version_lowest_raw(FWUPD_DEVICE(d)) #define fu_device_get_version_bootloader_raw(d) fwupd_device_get_version_bootloader_raw(FWUPD_DEVICE(d)) -#define fu_device_get_vendor_id(d) fwupd_device_get_vendor_id(FWUPD_DEVICE(d)) +#define fu_device_get_vendor_ids(d) fwupd_device_get_vendor_ids(FWUPD_DEVICE(d)) +#define fu_device_get_protocols(d) fwupd_device_get_protocols(FWUPD_DEVICE(d)) #define fu_device_get_flashes_left(d) fwupd_device_get_flashes_left(FWUPD_DEVICE(d)) #define fu_device_get_install_duration(d) fwupd_device_get_install_duration(FWUPD_DEVICE(d)) +/** + * FuDeviceInternalFlags: + * @FU_DEVICE_INTERNAL_FLAG_NONE: No flags set + * @FU_DEVICE_INTERNAL_FLAG_NO_AUTO_INSTANCE_IDS: Do not add instance IDs from the device baseclass + * @FU_DEVICE_INTERNAL_FLAG_ENSURE_SEMVER: Ensure the version is a valid semantic version, e.g. numbers separated with dots + * @FU_DEVICE_INTERNAL_FLAG_ONLY_SUPPORTED: Only devices supported in the metadata will be opened + * @FU_DEVICE_INTERNAL_FLAG_MD_SET_NAME: Set the device name from the metadata `name` if available + * @FU_DEVICE_INTERNAL_FLAG_MD_SET_NAME_CATEGORY: Set the device name from the metadata `category` if available + * @FU_DEVICE_INTERNAL_FLAG_MD_SET_VERFMT: Set the device version format from the metadata if available + * @FU_DEVICE_INTERNAL_FLAG_MD_SET_ICON: Set the device icon from the metadata if available + * @FU_DEVICE_INTERNAL_FLAG_RETRY_OPEN: Retry the device open up to 5 times if it fails + * @FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID: Match GUIDs on device replug where the physical and logical IDs will be different + * + * The device internal flags. + **/ +typedef enum { + FU_DEVICE_INTERNAL_FLAG_NONE = 0, + FU_DEVICE_INTERNAL_FLAG_NO_AUTO_INSTANCE_IDS = (1llu << 0), /* Since: 1.5.5 */ + FU_DEVICE_INTERNAL_FLAG_ENSURE_SEMVER = (1llu << 1), /* Since: 1.5.5 */ + FU_DEVICE_INTERNAL_FLAG_ONLY_SUPPORTED = (1llu << 2), /* Since: 1.5.5 */ + FU_DEVICE_INTERNAL_FLAG_MD_SET_NAME = (1llu << 3), /* Since: 1.5.5 */ + FU_DEVICE_INTERNAL_FLAG_MD_SET_NAME_CATEGORY = (1llu << 4), /* Since: 1.5.5 */ + FU_DEVICE_INTERNAL_FLAG_MD_SET_VERFMT = (1llu << 5), /* Since: 1.5.5 */ + FU_DEVICE_INTERNAL_FLAG_MD_SET_ICON = (1llu << 6), /* Since: 1.5.5 */ + FU_DEVICE_INTERNAL_FLAG_RETRY_OPEN = (1llu << 7), /* Since: 1.5.5 */ + FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID = (1llu << 8), /* Since: 1.5.8 */ + /*< private >*/ + FU_DEVICE_INTERNAL_FLAG_UNKNOWN = G_MAXUINT64, +} FuDeviceInternalFlags; + /* accessors */ gchar *fu_device_to_string (FuDevice *self); const gchar *fu_device_get_alternate_id (FuDevice *self); @@ -221,10 +289,15 @@ const gchar *fu_device_get_logical_id (FuDevice *self); void fu_device_set_logical_id (FuDevice *self, const gchar *logical_id); +const gchar *fu_device_get_backend_id (FuDevice *self); +void fu_device_set_backend_id (FuDevice *self, + const gchar *backend_id); const gchar *fu_device_get_proxy_guid (FuDevice *self); void fu_device_set_proxy_guid (FuDevice *self, const gchar *proxy_guid); +G_DEPRECATED_FOR(fu_device_get_protocols) const gchar *fu_device_get_protocol (FuDevice *self); +G_DEPRECATED_FOR(fu_device_add_protocol) void fu_device_set_protocol (FuDevice *self, const gchar *protocol); guint fu_device_get_priority (FuDevice *self); @@ -256,55 +329,85 @@ guint fu_device_get_progress (FuDevice *self); void fu_device_set_progress (FuDevice *self, guint progress); +guint fu_device_get_battery_level (FuDevice *self); +void fu_device_set_battery_level (FuDevice *self, + guint battery_level); void fu_device_set_progress_full (FuDevice *self, gsize progress_done, gsize progress_total); +void fu_device_sleep_with_progress (FuDevice *self, + guint delay_secs); void fu_device_set_quirks (FuDevice *self, FuQuirks *quirks); FuQuirks *fu_device_get_quirks (FuDevice *self); FwupdRelease *fu_device_get_release_default (FuDevice *self); +GType fu_device_get_specialized_gtype (FuDevice *self); +void fu_device_add_internal_flag (FuDevice *self, + FuDeviceInternalFlags flag); +void fu_device_remove_internal_flag (FuDevice *self, + FuDeviceInternalFlags flag); +gboolean fu_device_has_internal_flag (FuDevice *self, + FuDeviceInternalFlags flag); gboolean fu_device_write_firmware (FuDevice *self, GBytes *fw, FwupdInstallFlags flags, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; FuFirmware *fu_device_prepare_firmware (FuDevice *self, GBytes *fw, FwupdInstallFlags flags, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; FuFirmware *fu_device_read_firmware (FuDevice *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +GBytes *fu_device_dump_firmware (FuDevice *self, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_device_attach (FuDevice *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_device_detach (FuDevice *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_device_reload (FuDevice *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_device_prepare (FuDevice *self, FwupdInstallFlags flags, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_device_cleanup (FuDevice *self, FwupdInstallFlags flags, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; void fu_device_incorporate (FuDevice *self, FuDevice *donor); void fu_device_incorporate_flag (FuDevice *self, FuDevice *donor, FwupdDeviceFlags flag); gboolean fu_device_open (FuDevice *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_device_close (FuDevice *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_device_probe (FuDevice *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_device_setup (FuDevice *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_device_rescan (FuDevice *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_device_activate (FuDevice *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; void fu_device_probe_invalidate (FuDevice *self); gboolean fu_device_poll (FuDevice *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; void fu_device_set_poll_interval (FuDevice *self, guint interval); void fu_device_retry_set_delay (FuDevice *self, @@ -317,4 +420,22 @@ FuDeviceRetryFunc func, guint count, gpointer user_data, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fu_device_retry_full (FuDevice *self, + FuDeviceRetryFunc func, + guint count, + guint delay, + gpointer user_data, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fu_device_bind_driver (FuDevice *self, + const gchar *subsystem, + const gchar *driver, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fu_device_unbind_driver (FuDevice *self, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +GHashTable *fu_device_report_metadata_pre (FuDevice *self); +GHashTable *fu_device_report_metadata_post (FuDevice *self); diff -Nru fwupd-1.4.5/libfwupdplugin/fu-device-locker.c fwupd-1.5.8/libfwupdplugin/fu-device-locker.c --- fwupd-1.4.5/libfwupdplugin/fu-device-locker.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-device-locker.c 2021-03-31 20:08:32.000000000 +0000 @@ -9,7 +9,9 @@ #include "config.h" #include +#ifdef HAVE_GUSB #include +#endif #include "fu-device-locker.h" #include "fu-usb-device.h" @@ -46,8 +48,8 @@ if (!self->close_func (self->device, &error)) g_warning ("failed to close device: %s", error->message); } - - g_object_unref (self->device); + if (self->device != NULL) + g_object_unref (self->device); G_OBJECT_CLASS (fu_device_locker_parent_class)->finalize (obj); } @@ -80,12 +82,28 @@ gboolean fu_device_locker_close (FuDeviceLocker *self, GError **error) { + g_autoptr(GError) error_local = NULL; g_return_val_if_fail (FU_IS_DEVICE_LOCKER (self), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); if (!self->device_open) return TRUE; - if (!self->close_func (self->device, error)) + if (!self->close_func (self->device, &error_local)) { +#ifdef HAVE_GUSB + if (G_USB_IS_DEVICE (self->device) && + g_error_matches (error_local, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_NO_DEVICE)) { + g_debug ("ignoring: %s", error_local->message); + return TRUE; + } else { + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; + } +#else + g_propagate_error (error, g_steal_pointer (&error_local)); return FALSE; +#endif + } self->device_open = FALSE; return TRUE; } @@ -120,6 +138,7 @@ g_return_val_if_fail (device != NULL, NULL); g_return_val_if_fail (error != NULL, NULL); +#ifdef HAVE_GUSB /* GUsbDevice */ if (G_USB_IS_DEVICE (device)) { return fu_device_locker_new_full (device, @@ -127,6 +146,7 @@ (FuDeviceLockerFunc) g_usb_device_close, error); } +#endif /* FuDevice */ if (FU_IS_DEVICE (device)) { diff -Nru fwupd-1.4.5/libfwupdplugin/fu-device-locker.h fwupd-1.5.8/libfwupdplugin/fu-device-locker.h --- fwupd-1.4.5/libfwupdplugin/fu-device-locker.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-device-locker.h 2021-03-31 20:08:32.000000000 +0000 @@ -16,10 +16,13 @@ GError **error); FuDeviceLocker *fu_device_locker_new (gpointer device, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; FuDeviceLocker *fu_device_locker_new_full (gpointer device, FuDeviceLockerFunc open_func, FuDeviceLockerFunc close_func, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_device_locker_close (FuDeviceLocker *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; diff -Nru fwupd-1.4.5/libfwupdplugin/fu-device-private.h fwupd-1.5.8/libfwupdplugin/fu-device-private.h --- fwupd-1.4.5/libfwupdplugin/fu-device-private.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-device-private.h 2021-03-31 20:08:32.000000000 +0000 @@ -11,21 +11,26 @@ #define fu_device_set_plugin(d,v) fwupd_device_set_plugin(FWUPD_DEVICE(d),v) +const gchar *fu_device_internal_flag_to_string (FuDeviceInternalFlags flag); +FuDeviceInternalFlags fu_device_internal_flag_from_string (const gchar *flag); + GPtrArray *fu_device_get_parent_guids (FuDevice *self); gboolean fu_device_has_parent_guid (FuDevice *self, const gchar *guid); void fu_device_set_parent (FuDevice *self, FuDevice *parent); -guint fu_device_get_order (FuDevice *self); +gint fu_device_get_order (FuDevice *self); void fu_device_set_order (FuDevice *self, - guint order); + gint order); void fu_device_set_alternate (FuDevice *self, FuDevice *alternate); -GType fu_device_get_specialized_gtype (FuDevice *self); gboolean fu_device_ensure_id (FuDevice *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; void fu_device_incorporate_from_component (FuDevice *device, XbNode *component); void fu_device_convert_instance_ids (FuDevice *self); gchar *fu_device_get_guids_as_str (FuDevice *self); GPtrArray *fu_device_get_possible_plugins (FuDevice *self); +void fu_device_add_possible_plugin (FuDevice *self, + const gchar *plugin); diff -Nru fwupd-1.4.5/libfwupdplugin/fu-dfu-firmware.c fwupd-1.5.8/libfwupdplugin/fu-dfu-firmware.c --- fwupd-1.4.5/libfwupdplugin/fu-dfu-firmware.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-dfu-firmware.c 2021-03-31 20:08:32.000000000 +0000 @@ -8,8 +8,10 @@ #include "config.h" +#include + #include "fu-common.h" -#include "fu-dfu-firmware.h" +#include "fu-dfu-firmware-private.h" /** * SECTION:fu-dfu-firmware @@ -25,6 +27,7 @@ guint16 pid; guint16 release; guint16 version; + guint8 footer_len; } FuDfuFirmwarePrivate; G_DEFINE_TYPE_WITH_PRIVATE (FuDfuFirmware, fu_dfu_firmware, FU_TYPE_FIRMWARE) @@ -41,6 +44,15 @@ fu_common_string_append_kx (str, idt, "Version", priv->version); } +/* private */ +guint8 +fu_dfu_firmware_get_footer_len (FuDfuFirmware *self) +{ + FuDfuFirmwarePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DFU_FIRMWARE (self), 0x0); + return priv->footer_len; +} + /** * fu_dfu_firmware_get_vid: * @self: a #FuDfuFirmware @@ -181,60 +193,6 @@ priv->version = version; } -static guint32 _crctbl[] = { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, - 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, - 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, - 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, - 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, - 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, - 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, - 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, - 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, - 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, - 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, - 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, - 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, - 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, - 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, - 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, - 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, - 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, - 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, - 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, - 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, - 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; - -static guint32 -fu_dfu_firmware_generate_crc32 (const guint8 *data, gsize length) -{ - guint32 accum = 0xffffffff; - for (guint i = 0; i < length; i++) - accum = _crctbl[(accum^data[i]) & 0xff] ^ (accum >> 8); - return accum; -} - typedef struct __attribute__((packed)) { guint16 release; guint16 pid; @@ -245,23 +203,18 @@ guint32 crc; } FuDfuFirmwareFooter; -static gboolean -fu_dfu_firmware_parse (FuFirmware *firmware, - GBytes *fw, - guint64 addr_start, - guint64 addr_end, - FwupdInstallFlags flags, - GError **error) +gboolean +fu_dfu_firmware_parse_footer (FuDfuFirmware *self, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) { - FuDfuFirmware *self = FU_DFU_FIRMWARE (firmware); FuDfuFirmwarePrivate *priv = GET_PRIVATE (self); FuDfuFirmwareFooter ftr; gsize len; guint32 crc; guint32 crc_new; guint8 *data; - g_autoptr(FuFirmwareImage) image = NULL; - g_autoptr(GBytes) contents = NULL; /* check data size */ data = (guint8 *) g_bytes_get_data (fw, &len); @@ -289,8 +242,8 @@ sizeof(FuDfuFirmwareFooter), error)) return FALSE; crc = GUINT32_FROM_LE(ftr.crc); - if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { - crc_new = fu_dfu_firmware_generate_crc32 (data, len - 4); + if ((flags & FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM) == 0) { + crc_new = ~fu_common_crc32 (data, len - 4); if (crc != crc_new) { g_set_error (error, FWUPD_ERROR, @@ -306,26 +259,51 @@ priv->pid = GUINT16_FROM_LE(ftr.pid); priv->release = GUINT16_FROM_LE(ftr.release); priv->version = GUINT16_FROM_LE(ftr.ver); + priv->footer_len = ftr.len; /* check reported length */ - if (ftr.len > len) { + if (priv->footer_len > len) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, - "reported firmware size %04x larger than file %04x", - (guint) ftr.len, (guint) len); + "reported footer size %04x larger than file %04x", + (guint) priv->footer_len, (guint) len); return FALSE; } /* success */ - contents = g_bytes_new_from_bytes (fw, 0, len - ftr.len); + return TRUE; +} + +static gboolean +fu_dfu_firmware_parse (FuFirmware *firmware, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error) +{ + FuDfuFirmware *self = FU_DFU_FIRMWARE (firmware); + FuDfuFirmwarePrivate *priv = GET_PRIVATE (self); + gsize len = g_bytes_get_size (fw); + g_autoptr(FuFirmwareImage) image = NULL; + g_autoptr(GBytes) contents = NULL; + + /* parse footer */ + if (!fu_dfu_firmware_parse_footer (self, fw, flags, error)) + return FALSE; + + /* trim footer off */ + contents = fu_common_bytes_new_offset (fw, 0, len - priv->footer_len, error); + if (contents == NULL) + return FALSE; image = fu_firmware_image_new (contents); fu_firmware_add_image (firmware, image); return TRUE; } -static GBytes * -fu_dfu_firmware_add_footer (FuDfuFirmware *self, GBytes *contents, GError **error) +GBytes * +fu_dfu_firmware_append_footer (FuDfuFirmware *self, GBytes *contents, GError **error) { FuDfuFirmwarePrivate *priv = GET_PRIVATE (self); GByteArray *buf = g_byte_array_new (); @@ -343,9 +321,7 @@ fu_byte_array_append_uint16 (buf, priv->version, G_LITTLE_ENDIAN); g_byte_array_append (buf, (const guint8 *) "UFD", 3); fu_byte_array_append_uint8 (buf, sizeof(FuDfuFirmwareFooter)); - fu_byte_array_append_uint32 (buf, - fu_dfu_firmware_generate_crc32 (buf->data, buf->len), - G_LITTLE_ENDIAN); + fu_byte_array_append_uint32 (buf, ~fu_common_crc32 (buf->data, buf->len), G_LITTLE_ENDIAN); return g_byte_array_free_to_bytes (buf); } @@ -369,7 +345,29 @@ fw = fu_firmware_get_image_default_bytes (firmware, error); if (fw == NULL) return NULL; - return fu_dfu_firmware_add_footer (self, fw, error); + return fu_dfu_firmware_append_footer (self, fw, error); +} + +static gboolean +fu_dfu_firmware_build (FuFirmware *firmware, XbNode *n, GError **error) +{ + FuDfuFirmware *self = FU_DFU_FIRMWARE (firmware); + FuDfuFirmwarePrivate *priv = GET_PRIVATE (self); + guint64 tmp; + + /* optional properties */ + tmp = xb_node_query_text_as_uint (n, "vendor", NULL); + if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT16) + priv->vid = tmp; + tmp = xb_node_query_text_as_uint (n, "product", NULL); + if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT16) + priv->pid = tmp; + tmp = xb_node_query_text_as_uint (n, "release", NULL); + if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT16) + priv->release = tmp; + + /* success */ + return TRUE; } static void @@ -379,7 +377,9 @@ priv->vid = 0xffff; priv->pid = 0xffff; priv->release = 0xffff; - priv->version = 0x0100; + priv->version = DFU_VERSION_DFU_1_0; + fu_firmware_add_flag (FU_FIRMWARE (self), FU_FIRMWARE_FLAG_HAS_CHECKSUM); + fu_firmware_add_flag (FU_FIRMWARE (self), FU_FIRMWARE_FLAG_HAS_VID_PID); } static void @@ -389,6 +389,7 @@ klass_firmware->to_string = fu_dfu_firmware_to_string; klass_firmware->parse = fu_dfu_firmware_parse; klass_firmware->write = fu_dfu_firmware_write; + klass_firmware->build = fu_dfu_firmware_build; } /** diff -Nru fwupd-1.4.5/libfwupdplugin/fu-dfu-firmware-private.h fwupd-1.5.8/libfwupdplugin/fu-dfu-firmware-private.h --- fwupd-1.4.5/libfwupdplugin/fu-dfu-firmware-private.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-dfu-firmware-private.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-dfu-firmware.h" + +/** + * DfuVersion: + * @DFU_VERSION_UNKNOWN: Format unknown + * @DFU_VERSION_DFU_1_0: DFU 1.0 + * @DFU_VERSION_DFU_1_1: DFU 1.1 + * @DFU_VERSION_DFUSE: DfuSe + * @DFU_VERSION_ATMEL_AVR: Atmel AVR + * + * The known versions of the DFU standard in BCD format. + **/ +typedef enum { + DFU_VERSION_UNKNOWN = 0, + DFU_VERSION_DFU_1_0 = 0x0100, + DFU_VERSION_DFU_1_1 = 0x0110, + DFU_VERSION_DFUSE = 0x011a, /* defined by ST */ + DFU_VERSION_ATMEL_AVR = 0xff01, /* made up */ + /*< private >*/ + DFU_VERSION_LAST +} DfuVersion; + +guint8 fu_dfu_firmware_get_footer_len (FuDfuFirmware *self); +GBytes *fu_dfu_firmware_append_footer (FuDfuFirmware *self, + GBytes *contents, + GError **error); +gboolean fu_dfu_firmware_parse_footer (FuDfuFirmware *self, + GBytes *fw, + FwupdInstallFlags flags, + GError **error); diff -Nru fwupd-1.4.5/libfwupdplugin/fu-dfuse-firmware.c fwupd-1.5.8/libfwupdplugin/fu-dfuse-firmware.c --- fwupd-1.4.5/libfwupdplugin/fu-dfuse-firmware.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-dfuse-firmware.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,360 @@ +/* + * Copyright (C) 2015 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuFirmware" + +#include "config.h" + +#include + +#include "fu-chunk-private.h" +#include "fu-common.h" +#include "fu-dfu-firmware-private.h" +#include "fu-dfuse-firmware.h" + +/** + * SECTION:fu-dfuse-firmware + * @short_description: DfuSe firmware image + * + * An object that represents a DfuSe firmware image. + * + * See also: #FuDfuFirmware + */ + +G_DEFINE_TYPE (FuDfuseFirmware, fu_dfuse_firmware, FU_TYPE_DFU_FIRMWARE) + +/* firmware: LE */ +typedef struct __attribute__((packed)) { + guint8 sig[5]; + guint8 ver; + guint32 image_size; + guint8 targets; +} DfuSeHdr; + +/* image: LE */ +typedef struct __attribute__((packed)) { + guint8 sig[6]; + guint8 alt_setting; + guint32 target_named; + gchar target_name[255]; + guint32 target_size; + guint32 chunks; +} DfuSeImageHdr; + +/* element: LE */ +typedef struct __attribute__((packed)) { + guint32 address; + guint32 size; +} DfuSeElementHdr; + +G_STATIC_ASSERT(sizeof(DfuSeHdr) == 11); +G_STATIC_ASSERT(sizeof(DfuSeImageHdr) == 274); +G_STATIC_ASSERT(sizeof(DfuSeElementHdr) == 8); + +static FuChunk * +fu_firmware_image_chunk_parse (FuDfuseFirmware *self, + GBytes *bytes, + gsize *offset, + GError **error) +{ + DfuSeElementHdr hdr = { 0x0 }; + gsize bufsz = 0; + gsize ftrlen = fu_dfu_firmware_get_footer_len (FU_DFU_FIRMWARE (self)); + const guint8 *buf = g_bytes_get_data (bytes, &bufsz); + g_autoptr(FuChunk) chk = NULL; + g_autoptr(GBytes) blob = NULL; + + /* check size */ + if (!fu_memcpy_safe ((guint8 *) &hdr, sizeof(hdr), 0x0, /* dst */ + buf, bufsz - ftrlen, *offset, /* src */ + sizeof(hdr), error)) + return NULL; + + /* create new chunk */ + *offset += sizeof(hdr); + blob = fu_common_bytes_new_offset (bytes, *offset, + GUINT32_FROM_LE (hdr.size), + error); + if (blob == NULL) + return NULL; + chk = fu_chunk_bytes_new (blob); + fu_chunk_set_address (chk, GUINT32_FROM_LE (hdr.address)); + *offset += fu_chunk_get_data_sz (chk); + + /* success */ + return g_steal_pointer (&chk); +} + +static FuFirmwareImage * +fu_dfuse_firmware_image_parse (FuDfuseFirmware *self, + GBytes *bytes, + gsize *offset, + GError **error) +{ + DfuSeImageHdr hdr = { 0x0 }; + gsize bufsz = 0; + const guint8 *buf = g_bytes_get_data (bytes, &bufsz); + g_autoptr(FuFirmwareImage) image = fu_firmware_image_new (NULL); + + /* verify image signature */ + if (!fu_memcpy_safe ((guint8 *) &hdr, sizeof(hdr), 0x0, /* dst */ + buf, bufsz, *offset, /* src */ + sizeof(hdr), error)) + return NULL; + if (memcmp (hdr.sig, "Target", sizeof(hdr.sig)) != 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "invalid DfuSe target signature"); + return NULL; + } + + /* set properties */ + fu_firmware_image_set_idx (image, hdr.alt_setting); + if (GUINT32_FROM_LE (hdr.target_named) == 0x01) { + g_autofree gchar *img_id = NULL; + img_id = g_strndup (hdr.target_name, sizeof(hdr.target_name)); + fu_firmware_image_set_id (image, img_id); + } + + /* no chunks */ + if (hdr.chunks == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "DfuSe image has no chunks"); + return NULL; + } + + /* parse chunks */ + *offset += sizeof(hdr); + for (guint j = 0; j < GUINT32_FROM_LE (hdr.chunks); j++) { + g_autoptr(FuChunk) chk = NULL; + chk = fu_firmware_image_chunk_parse (self, + bytes, + offset, + error); + if (chk == NULL) + return NULL; + fu_firmware_image_add_chunk (image, chk); + } + + /* success */ + return g_steal_pointer (&image); +} + +static gboolean +fu_dfuse_firmware_parse (FuFirmware *firmware, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error) +{ + FuDfuFirmware *dfu_firmware = FU_DFU_FIRMWARE (firmware); + DfuSeHdr hdr = { 0x0 }; + gsize bufsz = 0; + gsize offset = 0; + const guint8 *buf; + + /* DFU footer first */ + if (!fu_dfu_firmware_parse_footer (dfu_firmware, fw, flags, error)) + return FALSE; + + /* check the prefix */ + buf = (const guint8 *) g_bytes_get_data (fw, &bufsz); + if (!fu_memcpy_safe ((guint8 *) &hdr, sizeof(hdr), 0x0, /* dst */ + buf, bufsz, offset, /* src */ + sizeof(hdr), error)) + return FALSE; + if (memcmp (hdr.sig, "DfuSe", sizeof(hdr.sig)) != 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "invalid DfuSe prefix"); + return FALSE; + } + + /* check the version */ + if (hdr.ver != 0x01) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "invalid DfuSe version, got %02x", + hdr.ver); + return FALSE; + } + + /* check image size */ + if (GUINT32_FROM_LE (hdr.image_size) != + bufsz - fu_dfu_firmware_get_footer_len (dfu_firmware)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "invalid DfuSe image size, " + "got %" G_GUINT32_FORMAT ", " + "expected %" G_GSIZE_FORMAT, + GUINT32_FROM_LE (hdr.image_size), + bufsz - fu_dfu_firmware_get_footer_len (dfu_firmware)); + return FALSE; + } + + /* parse the image targets */ + offset += sizeof(hdr); + for (guint i = 0; i < hdr.targets; i++) { + g_autoptr(FuFirmwareImage) image = NULL; + image = fu_dfuse_firmware_image_parse (FU_DFUSE_FIRMWARE (firmware), + fw, &offset, + error); + if (image == NULL) + return FALSE; + fu_firmware_add_image (firmware, image); + } + return TRUE; +} + +static GBytes * +fu_firmware_image_chunk_write (FuChunk *chk) +{ + DfuSeElementHdr hdr = { 0x0 }; + const guint8 *data = fu_chunk_get_data (chk); + gsize length = fu_chunk_get_data_sz (chk); + g_autoptr(GByteArray) buf = NULL; + + buf = g_byte_array_sized_new (sizeof(DfuSeElementHdr) + length); + hdr.address = GUINT32_TO_LE (fu_chunk_get_address (chk)); + hdr.size = GUINT32_TO_LE (length); + g_byte_array_append (buf, (const guint8 *) &hdr, sizeof(hdr)); + g_byte_array_append (buf, data, length); + return g_byte_array_free_to_bytes (g_steal_pointer (&buf)); +} + +static GBytes * +fu_dfuse_firmware_image_write (FuFirmwareImage *image, GError **error) +{ + DfuSeImageHdr hdr = { 0x0 }; + gsize totalsz = 0; + g_autoptr(GByteArray) buf = NULL; + g_autoptr(GPtrArray) blobs = NULL; + g_autoptr(GPtrArray) chunks = NULL; + + /* get total size */ + blobs = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref); + chunks = fu_firmware_image_get_chunks (image, error); + if (chunks == NULL) + return NULL; + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + GBytes *bytes = fu_firmware_image_chunk_write (chk); + g_ptr_array_add (blobs, bytes); + totalsz += g_bytes_get_size (bytes); + } + + /* mutable output buffer */ + buf = g_byte_array_sized_new (sizeof(DfuSeImageHdr) + totalsz); + + /* add prefix */ + memcpy (hdr.sig, "Target", 6); + hdr.alt_setting = fu_firmware_image_get_idx (image); + if (fu_firmware_image_get_id (image) != NULL) { + hdr.target_named = GUINT32_TO_LE (0x01); + g_strlcpy ((gchar *) &hdr.target_name, + fu_firmware_image_get_id (image), + sizeof(hdr.target_name)); + } + hdr.target_size = GUINT32_TO_LE (totalsz); + hdr.chunks = GUINT32_TO_LE (chunks->len); + g_byte_array_append (buf, (const guint8 *) &hdr, sizeof(hdr)); + + /* copy data */ + for (guint i = 0; i < blobs->len; i++) { + GBytes *blob = g_ptr_array_index (blobs, i); + g_byte_array_append (buf, + g_bytes_get_data (blob, NULL), + g_bytes_get_size (blob)); + } + return g_byte_array_free_to_bytes (g_steal_pointer (&buf)); +} + +static GBytes * +fu_dfuse_firmware_write (FuFirmware *firmware, GError **error) +{ + DfuSeHdr hdr = { 0x0 }; + gsize totalsz = 0; + g_autoptr(GByteArray) buf = NULL; + g_autoptr(GBytes) blob_noftr = NULL; + g_autoptr(GPtrArray) blobs = NULL; + g_autoptr(GPtrArray) images = NULL; + + /* create mutable output buffer */ + blobs = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref); + images = fu_firmware_get_images (FU_FIRMWARE (firmware)); + for (guint i = 0; i < images->len; i++) { + FuFirmwareImage *img = g_ptr_array_index (images, i); + g_autoptr(GBytes) blob = NULL; + blob = fu_dfuse_firmware_image_write (img, error); + if (blob == NULL) + return NULL; + totalsz += g_bytes_get_size (blob); + g_ptr_array_add (blobs, g_steal_pointer (&blob)); + } + buf = g_byte_array_sized_new (sizeof(DfuSeHdr) + totalsz); + + /* DfuSe header */ + memcpy (hdr.sig, "DfuSe", 5); + hdr.ver = 0x01; + hdr.image_size = GUINT32_TO_LE (sizeof(hdr) + totalsz); + if (images->len > G_MAXUINT8) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "too many (%u) images to write DfuSe file", + images->len); + return NULL; + } + hdr.targets = (guint8) images->len; + g_byte_array_append (buf, (const guint8 *) &hdr, sizeof(hdr)); + + /* copy images */ + for (guint i = 0; i < blobs->len; i++) { + GBytes *blob = g_ptr_array_index (blobs, i); + g_byte_array_append (buf, + g_bytes_get_data (blob, NULL), + g_bytes_get_size (blob)); + } + + /* return blob */ + blob_noftr = g_byte_array_free_to_bytes (g_steal_pointer (&buf)); + return fu_dfu_firmware_append_footer (FU_DFU_FIRMWARE (firmware), + blob_noftr, error); +} + +static void +fu_dfuse_firmware_init (FuDfuseFirmware *self) +{ + fu_dfu_firmware_set_version (FU_DFU_FIRMWARE (self), DFU_VERSION_DFUSE); +} + +static void +fu_dfuse_firmware_class_init (FuDfuseFirmwareClass *klass) +{ + FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); + klass_firmware->parse = fu_dfuse_firmware_parse; + klass_firmware->write = fu_dfuse_firmware_write; +} + +/** + * fu_dfuse_firmware_new: + * + * Creates a new #FuFirmware of sub type Dfuse + * + * Since: 1.5.6 + **/ +FuFirmware * +fu_dfuse_firmware_new (void) +{ + return FU_FIRMWARE (g_object_new (FU_TYPE_DFUSE_FIRMWARE, NULL)); +} diff -Nru fwupd-1.4.5/libfwupdplugin/fu-dfuse-firmware.h fwupd-1.5.8/libfwupdplugin/fu-dfuse-firmware.h --- fwupd-1.4.5/libfwupdplugin/fu-dfuse-firmware.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-dfuse-firmware.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2015 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-dfu-firmware.h" + +#define FU_TYPE_DFUSE_FIRMWARE (fu_dfuse_firmware_get_type ()) +G_DECLARE_DERIVABLE_TYPE (FuDfuseFirmware, fu_dfuse_firmware, FU, DFUSE_FIRMWARE, FuDfuFirmware) + +struct _FuDfuseFirmwareClass +{ + FuDfuFirmwareClass parent_class; +}; + +FuFirmware *fu_dfuse_firmware_new (void); diff -Nru fwupd-1.4.5/libfwupdplugin/fu-efi-signature.c fwupd-1.5.8/libfwupdplugin/fu-efi-signature.c --- fwupd-1.4.5/libfwupdplugin/fu-efi-signature.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-efi-signature.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-efi-signature-private.h" + +/** + * SECTION:fu-efi-signature + * @short_description: Parser for EFI_SIGNATURE + * + * An object that represents a UEFI Signature. + * + * See also: #FuFirmware + */ + +struct _FuEfiSignature { + FuFirmwareImage parent_instance; + FuEfiSignatureKind kind; + gchar *owner; +}; + +G_DEFINE_TYPE (FuEfiSignature, fu_efi_signature, FU_TYPE_FIRMWARE_IMAGE) + +/** + * fu_efi_signature_kind_to_string: + * @kind: A #FuEfiSignatureKind, e.g. %FU_EFI_SIGNATURE_KIND_X509 + * + * Converts the signature kind to a text representation. + * + * Returns: text, e.g. `x509_cert` + * + * Since: 1.5.5 + **/ +const gchar * +fu_efi_signature_kind_to_string (FuEfiSignatureKind kind) +{ + if (kind == FU_EFI_SIGNATURE_KIND_SHA256) + return "sha256"; + if (kind == FU_EFI_SIGNATURE_KIND_X509) + return "x509_cert"; + return "unknown"; +} + +/** + * fu_efi_signature_new: (skip): + * @kind: A #FuEfiSignatureKind + * @owner: A GUID, e.g. %FU_EFI_SIGNATURE_GUID_MICROSOFT + * + * Creates a new EFI_SIGNATURE. + * + * Returns: (transfer full): signature + * + * Since: 1.5.5 + **/ +FuEfiSignature * +fu_efi_signature_new (FuEfiSignatureKind kind, const gchar *owner) +{ + g_autoptr(FuEfiSignature) self = g_object_new (FU_TYPE_EFI_SIGNATURE, NULL); + self->kind = kind; + self->owner = g_strdup (owner); + return g_steal_pointer (&self); +} + +/** + * fu_efi_signature_get_kind: + * @self: A #FuEfiSignature + * + * Returns the signature kind. + * + * Returns: #FuEfiSignatureKind, e.g. %FU_EFI_SIGNATURE_KIND_SHA256 + * + * Since: 1.5.5 + **/ +FuEfiSignatureKind +fu_efi_signature_get_kind (FuEfiSignature *self) +{ + g_return_val_if_fail (FU_IS_EFI_SIGNATURE (self), FU_EFI_SIGNATURE_KIND_UNKNOWN); + return self->kind; +} + +/** + * fu_efi_signature_get_owner: + * @self: A #FuEfiSignature + * + * Returns the GUID of the signature owner. + * + * Returns: GUID owner, perhaps %FU_EFI_SIGNATURE_GUID_MICROSOFT + * + * Since: 1.5.5 + **/ +const gchar * +fu_efi_signature_get_owner (FuEfiSignature *self) +{ + g_return_val_if_fail (FU_IS_EFI_SIGNATURE (self), NULL); + return self->owner; +} + +static gchar * +fu_efi_signature_get_checksum (FuFirmwareImage *firmware_image, + GChecksumType csum_kind, + GError **error) +{ + FuEfiSignature *self = FU_EFI_SIGNATURE (firmware_image); + g_autoptr(GBytes) data = fu_firmware_image_get_bytes (firmware_image); + + /* special case: this is *literally* a hash */ + if (self->kind == FU_EFI_SIGNATURE_KIND_SHA256 && + csum_kind == G_CHECKSUM_SHA256) { + GString *str; + const guint8 *buf; + gsize bufsz = 0; + buf = g_bytes_get_data (data, &bufsz); + str = g_string_new (NULL); + for (gsize i = 0; i < bufsz; i++) + g_string_append_printf (str, "%02x", buf[i]); + return g_string_free (str, FALSE); + } + + /* fallback */ + return g_compute_checksum_for_bytes (csum_kind, data); +} + +static void +fu_efi_signature_finalize (GObject *obj) +{ + FuEfiSignature *self = FU_EFI_SIGNATURE (obj); + g_free (self->owner); + G_OBJECT_CLASS (fu_efi_signature_parent_class)->finalize (obj); +} + +static void +fu_efi_signature_class_init (FuEfiSignatureClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuFirmwareImageClass *firmware_image_class = FU_FIRMWARE_IMAGE_CLASS (klass); + object_class->finalize = fu_efi_signature_finalize; + firmware_image_class->get_checksum = fu_efi_signature_get_checksum; +} + +static void +fu_efi_signature_init (FuEfiSignature *self) +{ +} diff -Nru fwupd-1.4.5/libfwupdplugin/fu-efi-signature.h fwupd-1.5.8/libfwupdplugin/fu-efi-signature.h --- fwupd-1.4.5/libfwupdplugin/fu-efi-signature.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-efi-signature.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#include "fu-firmware-image.h" + +#define FU_TYPE_EFI_SIGNATURE (fu_efi_signature_get_type ()) +G_DECLARE_FINAL_TYPE (FuEfiSignature, fu_efi_signature, FU, EFI_SIGNATURE, FuFirmwareImage) + +typedef enum { + FU_EFI_SIGNATURE_KIND_UNKNOWN, + FU_EFI_SIGNATURE_KIND_SHA256, + FU_EFI_SIGNATURE_KIND_X509, + /*< private >*/ + FU_EFI_SIGNATURE_KIND_LAST +} FuEfiSignatureKind; + +#define FU_EFI_SIGNATURE_GUID_ZERO "00000000-0000-0000-0000-000000000000" +#define FU_EFI_SIGNATURE_GUID_MICROSOFT "77fa9abd-0359-4d32-bd60-28f4e78f784b" +#define FU_EFI_SIGNATURE_GUID_OVMF "a0baa8a3-041d-48a8-bc87-c36d121b5e3d" +#define FU_EFI_SIGNATURE_GUID_OVMF_LEGACY "d5c1df0b-1bac-4edf-ba48-08834009ca5a" + +const gchar *fu_efi_signature_kind_to_string (FuEfiSignatureKind kind); + +FuEfiSignatureKind fu_efi_signature_get_kind (FuEfiSignature *self); +const gchar *fu_efi_signature_get_owner (FuEfiSignature *self); diff -Nru fwupd-1.4.5/libfwupdplugin/fu-efi-signature-list.c fwupd-1.5.8/libfwupdplugin/fu-efi-signature-list.c --- fwupd-1.4.5/libfwupdplugin/fu-efi-signature-list.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-efi-signature-list.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include + +#include "fu-common.h" +#include "fu-efi-signature-private.h" +#include "fu-efi-signature-list.h" + +/** + * SECTION:fu-efi-signature-list + * @short_description: Parser for EFI_SIGNATURE_LIST + * + * An object that represents a UEFI SignatureList. + * + * See also: #FuFirmware + */ + +struct _FuEfiSignatureList { + FuFirmware parent_instance; +}; + +G_DEFINE_TYPE (FuEfiSignatureList, fu_efi_signature_list, FU_TYPE_FIRMWARE) + +static gboolean +fu_efi_signature_list_parse_item (FuEfiSignatureList *self, + FuEfiSignatureKind sig_kind, + const guint8 *buf, + gsize bufsz, + gsize offset, + guint32 sig_size, + GError **error) +{ + fwupd_guid_t guid; + gsize sig_datasz; + g_autofree gchar *sig_owner = NULL; + g_autofree guint8 *sig_data = NULL; + g_autoptr(FuEfiSignature) sig = NULL; + g_autoptr(GBytes) data = NULL; + + /* allocate data buf */ + if (sig_size <= sizeof(fwupd_guid_t)) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "SignatureSize invalid: 0x%x", + (guint) sig_size); + return FALSE; + } + sig_datasz = sig_size - sizeof(fwupd_guid_t); + sig_data = g_malloc0 (sig_datasz); + + /* read both blocks of data */ + if (!fu_memcpy_safe ((guint8 *) &guid, sizeof(guid), 0x0, /* dst */ + buf, bufsz, offset, /* src */ + sizeof(guid), error)) { + g_prefix_error (error, "failed to read signature GUID: "); + return FALSE; + } + if (!fu_memcpy_safe (sig_data, sig_datasz, 0x0, /* dst */ + buf, bufsz, offset + sizeof(fwupd_guid_t), /* src */ + sig_datasz, error)) { + g_prefix_error (error, "failed to read signature data: "); + return FALSE; + } + + /* create item */ + sig_owner = fwupd_guid_to_string (&guid, FWUPD_GUID_FLAG_MIXED_ENDIAN); + data = g_bytes_new (sig_data, sig_datasz); + sig = fu_efi_signature_new (sig_kind, sig_owner); + fu_firmware_image_set_bytes (FU_FIRMWARE_IMAGE (sig), data); + fu_firmware_add_image (FU_FIRMWARE (self), FU_FIRMWARE_IMAGE (sig)); + return TRUE; +} + +static gboolean +fu_efi_signature_list_parse_list (FuEfiSignatureList *self, + const guint8 *buf, + gsize bufsz, + gsize *offset, + GError **error) +{ + FuEfiSignatureKind sig_kind = FU_EFI_SIGNATURE_KIND_UNKNOWN; + fwupd_guid_t guid; + gsize offset_tmp; + guint32 sig_header_size = 0; + guint32 sig_list_size = 0; + guint32 sig_size = 0; + g_autofree gchar *sig_type = NULL; + + /* read EFI_SIGNATURE_LIST */ + if (!fu_memcpy_safe ((guint8 *) &guid, sizeof(guid), 0x0, /* dst */ + buf, bufsz, *offset, /* src */ + sizeof(guid), error)) { + g_prefix_error (error, "failed to read GUID header: "); + return FALSE; + } + sig_type = fwupd_guid_to_string (&guid, FWUPD_GUID_FLAG_MIXED_ENDIAN); + if (g_strcmp0 (sig_type, "c1c41626-504c-4092-aca9-41f936934328") == 0) { + sig_kind = FU_EFI_SIGNATURE_KIND_SHA256; + } else if (g_strcmp0 (sig_type, "a5c059a1-94e4-4aa7-87b5-ab155c2bf072") == 0) { + sig_kind = FU_EFI_SIGNATURE_KIND_X509; + } + if (!fu_common_read_uint32_safe (buf, bufsz, *offset + 0x10, + &sig_list_size, G_LITTLE_ENDIAN, error)) + return FALSE; + if (sig_list_size < 0x1c || sig_list_size > 1024 * 1024) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "SignatureListSize invalid: 0x%x", sig_list_size); + return FALSE; + } + if (!fu_common_read_uint32_safe (buf, bufsz, *offset + 0x14, + &sig_header_size, G_LITTLE_ENDIAN, error)) + return FALSE; + if (sig_header_size > 1024 * 1024) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "SignatureHeaderSize invalid: 0x%x", sig_size); + return FALSE; + } + if (!fu_common_read_uint32_safe (buf, bufsz, *offset + 0x18, + &sig_size, G_LITTLE_ENDIAN, error)) + return FALSE; + if (sig_size < sizeof(fwupd_guid_t) || sig_size > 1024 * 1024) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "SignatureSize invalid: 0x%x", sig_size); + return FALSE; + } + + /* header is typically unused */ + offset_tmp = *offset + 0x1c + sig_header_size; + for (guint i = 0; i < (sig_list_size - 0x1c) / sig_size; i++) { + if (!fu_efi_signature_list_parse_item (self, sig_kind, buf, bufsz, + offset_tmp, sig_size, + error)) + return FALSE; + offset_tmp += sig_size; + } + *offset += sig_list_size; + return TRUE; +} + +static gchar * +fu_efi_signature_list_get_version (FuEfiSignatureList *self) +{ + guint csum_cnt = 0; + const gchar *ignored_guids[] = { + FU_EFI_SIGNATURE_GUID_OVMF, + FU_EFI_SIGNATURE_GUID_OVMF_LEGACY, + NULL }; + g_autoptr(GPtrArray) sigs = NULL; + sigs = fu_firmware_get_images (FU_FIRMWARE (self)); + for (guint i = 0; i < sigs->len; i++) { + FuEfiSignature *sig = g_ptr_array_index (sigs, i); + if (fu_efi_signature_get_kind (sig) != FU_EFI_SIGNATURE_KIND_SHA256) + continue; + if (g_strv_contains (ignored_guids, fu_efi_signature_get_owner (sig))) + continue; + csum_cnt++; + } + return g_strdup_printf ("%u", csum_cnt); +} + +static gboolean +fu_efi_signature_list_parse (FuFirmware *firmware, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error) +{ + FuEfiSignatureList *self = FU_EFI_SIGNATURE_LIST (firmware); + gsize bufsz = 0; + gsize offset_fs = 0; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + g_autofree gchar *version_str = NULL; + + /* this allows us to skip the efi permissions uint32_t or even the + * Microsoft PKCS-7 signature */ + if ((flags & FWUPD_INSTALL_FLAG_NO_SEARCH) == 0) { + if (bufsz < 5) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "signature invalid: 0x%x", + (guint) bufsz); + return FALSE; + } + for (gsize i = 0; i < bufsz - 5; i++) { + if (memcmp (buf + i, "\x26\x16\xc4\xc1\x4c", 5) == 0) { + g_debug ("found EFI_SIGNATURE_LIST @0x%x", (guint) i); + offset_fs = i; + break; + } + } + } + + /* parse each EFI_SIGNATURE_LIST */ + for (gsize offset = offset_fs; offset < bufsz;) { + if (!fu_efi_signature_list_parse_list (self, buf, bufsz, &offset, error)) + return FALSE; + } + + /* set version */ + version_str = fu_efi_signature_list_get_version (self); + if (version_str != NULL) + fu_firmware_set_version (firmware, version_str); + + /* success */ + return TRUE; +} + +static GBytes * +fu_efi_signature_list_write (FuFirmware *firmware, GError **error) +{ + GByteArray *buf = g_byte_array_new (); + + /* SignatureType */ + for (guint i = 0; i < 16; i++) + fu_byte_array_append_uint8 (buf, 0x0); + + /* SignatureListSize */ + fu_byte_array_append_uint32 (buf, 16 + 4 + 4 + 4 + 16 + 32, G_LITTLE_ENDIAN); + + /* SignatureHeaderSize */ + fu_byte_array_append_uint32 (buf, 0, G_LITTLE_ENDIAN); + + /* SignatureSize */ + fu_byte_array_append_uint32 (buf, 16 + 32, G_LITTLE_ENDIAN); + + /* SignatureOwner */ + for (guint i = 0; i < 16; i++) + fu_byte_array_append_uint8 (buf, '1'); + + /* SignatureData */ + for (guint i = 0; i < 16; i++) + fu_byte_array_append_uint8 (buf, '2'); + + return g_byte_array_free_to_bytes (buf); +} + +/** + * fu_efi_signature_list_new: + * + * Creates a new #FuFirmware that can parse an EFI_SIGNATURE_LIST + * + * Since: 1.5.5 + **/ +FuFirmware * +fu_efi_signature_list_new (void) +{ + return g_object_new (FU_TYPE_EFI_SIGNATURE_LIST, NULL); +} + +static void +fu_efi_signature_list_class_init (FuEfiSignatureListClass *klass) +{ + FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); + klass_firmware->parse = fu_efi_signature_list_parse; + klass_firmware->write = fu_efi_signature_list_write; +} + +static void +fu_efi_signature_list_init (FuEfiSignatureList *self) +{ +} diff -Nru fwupd-1.4.5/libfwupdplugin/fu-efi-signature-list.h fwupd-1.5.8/libfwupdplugin/fu-efi-signature-list.h --- fwupd-1.4.5/libfwupdplugin/fu-efi-signature-list.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-efi-signature-list.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-firmware.h" + +#define FU_TYPE_EFI_SIGNATURE_LIST (fu_efi_signature_list_get_type ()) +G_DECLARE_FINAL_TYPE (FuEfiSignatureList, fu_efi_signature_list, FU, EFI_SIGNATURE_LIST, FuFirmware) + +FuFirmware *fu_efi_signature_list_new (void); diff -Nru fwupd-1.4.5/libfwupdplugin/fu-efi-signature-private.h fwupd-1.5.8/libfwupdplugin/fu-efi-signature-private.h --- fwupd-1.4.5/libfwupdplugin/fu-efi-signature-private.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-efi-signature-private.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,12 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-efi-signature.h" + +FuEfiSignature *fu_efi_signature_new (FuEfiSignatureKind kind, + const gchar *owner); diff -Nru fwupd-1.4.5/libfwupdplugin/fu-efivar.c fwupd-1.5.8/libfwupdplugin/fu-efivar.c --- fwupd-1.4.5/libfwupdplugin/fu-efivar.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-efivar.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,6 +1,6 @@ /* * Copyright (C) 2018 Richard Hughes - * Copyright (C) 2015-2017 Peter Jones + * Copyright (C) 2015 Peter Jones * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -51,6 +51,7 @@ { #ifndef _WIN32 g_autofree gchar *efivardir = fu_efivar_get_path (); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); if (!g_file_test (efivardir, G_FILE_TEST_IS_DIR)) { g_set_error (error, FWUPD_ERROR, @@ -61,6 +62,7 @@ } return TRUE; #else + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, @@ -69,13 +71,13 @@ #endif } +#ifndef _WIN32 static gboolean fu_efivar_set_immutable_fd (int fd, gboolean value, gboolean *value_old, GError **error) { -#ifndef _WIN32 guint flags; gboolean is_immutable; int rc; @@ -124,14 +126,8 @@ return FALSE; } return TRUE; -#else - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "efivarfs not currently supported on Windows"); - return FALSE; -#endif } +#endif static gboolean fu_efivar_set_immutable (const gchar *fn, @@ -179,8 +175,15 @@ gboolean fu_efivar_delete (const gchar *guid, const gchar *name, GError **error) { - g_autofree gchar *fn = fu_efivar_get_filename (guid, name); - g_autoptr(GFile) file = g_file_new_for_path (fn); + g_autofree gchar *fn = NULL; + g_autoptr(GFile) file = NULL; + + g_return_val_if_fail (guid != NULL, FALSE); + g_return_val_if_fail (name != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + fn = fu_efivar_get_filename (guid, name); + file = g_file_new_for_path (fn); if (!g_file_query_exists (file, NULL)) return TRUE; if (!fu_efivar_set_immutable (fn, FALSE, NULL, error)) { @@ -208,7 +211,13 @@ const gchar *fn; g_autofree gchar *nameguid_glob = NULL; g_autofree gchar *efivardir = fu_efivar_get_path (); - g_autoptr(GDir) dir = g_dir_open (efivardir, 0, error); + g_autoptr(GDir) dir = NULL; + + g_return_val_if_fail (guid != NULL, FALSE); + g_return_val_if_fail (name_glob != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + dir = g_dir_open (efivardir, 0, error); if (dir == NULL) return FALSE; nameguid_glob = g_strdup_printf ("%s-%s", name_glob, guid); @@ -227,10 +236,27 @@ return TRUE; } +static gboolean +fu_efivar_exists_guid (const gchar *guid) +{ + const gchar *fn; + g_autofree gchar *efivardir = fu_efivar_get_path (); + g_autoptr(GDir) dir = NULL; + + dir = g_dir_open (efivardir, 0, NULL); + if (dir == NULL) + return FALSE; + while ((fn = g_dir_read_name (dir)) != NULL) { + if (g_str_has_suffix (fn, guid)) + return TRUE; + } + return TRUE; +} + /** * fu_efivar_exists: * @guid: Globally unique identifier - * @name: Variable name + * @name: (nullable): Variable name * * Test if a variable exists * @@ -241,7 +267,15 @@ gboolean fu_efivar_exists (const gchar *guid, const gchar *name) { - g_autofree gchar *fn = fu_efivar_get_filename (guid, name); + g_autofree gchar *fn = NULL; + + g_return_val_if_fail (guid != NULL, FALSE); + + /* any name */ + if (name == NULL) + return fu_efivar_exists_guid (guid); + + fn = fu_efivar_get_filename (guid, name); return g_file_test (fn, G_FILE_TEST_EXISTS); } @@ -269,12 +303,18 @@ gssize data_sz_tmp; guint32 attr_tmp; guint64 sz; - g_autofree gchar *fn = fu_efivar_get_filename (guid, name); - g_autoptr(GFile) file = g_file_new_for_path (fn); + g_autofree gchar *fn = NULL; + g_autoptr(GFile) file = NULL; g_autoptr(GFileInfo) info = NULL; g_autoptr(GInputStream) istr = NULL; + g_return_val_if_fail (guid != NULL, FALSE); + g_return_val_if_fail (name != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + /* open file as stream */ + fn = fu_efivar_get_filename (guid, name); + file = g_file_new_for_path (fn); istr = G_INPUT_STREAM (g_file_read (file, NULL, error)); if (istr == NULL) return FALSE; @@ -329,6 +369,165 @@ } /** + * fu_efivar_get_data_bytes: + * @guid: Globally unique identifier + * @name: Variable name + * @attr: (nullable): Attributes + * @error: A #GError + * + * Gets the data from a UEFI variable in NVRAM + * + * Returns: (transfer full): a #GBytes, or %NULL + * + * Since: 1.5.0 + **/ +GBytes * +fu_efivar_get_data_bytes (const gchar *guid, + const gchar *name, + guint32 *attr, + GError **error) +{ + guint8 *data = NULL; + gsize datasz = 0; + + g_return_val_if_fail (guid != NULL, NULL); + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + if (!fu_efivar_get_data (guid, name, &data, &datasz, attr, error)) + return NULL; + return g_bytes_new_take (data, datasz); +} + +/** + * fu_efivar_get_names: + * @guid: Globally unique identifier + * @error: A #GError + * + * Gets the list of names where the GUID matches. An error is set if there are + * no names matching the GUID. + * + * Returns: (transfer container) (element-type utf8): array of names + * + * Since: 1.4.7 + **/ +GPtrArray * +fu_efivar_get_names (const gchar *guid, GError **error) +{ + const gchar *name_guid; + g_autofree gchar *path = fu_efivar_get_path (); + g_autoptr(GDir) dir = NULL; + g_autoptr(GPtrArray) names = g_ptr_array_new_with_free_func (g_free); + + g_return_val_if_fail (guid != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* find names with matching GUID */ + dir = g_dir_open (path, 0, error); + if (dir == NULL) + return NULL; + while ((name_guid = g_dir_read_name (dir)) != NULL) { + gsize name_guidsz = strlen (name_guid); + if (name_guidsz < 38) + continue; + if (g_strcmp0 (name_guid + name_guidsz - 36, guid) == 0) { + g_ptr_array_add (names, + g_strndup (name_guid, name_guidsz - 37)); + } + } + + /* nothing found */ + if (names->len == 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "no names for GUID %s", guid); + return NULL; + } + + /* success */ + return g_steal_pointer (&names); +} + +/** + * fu_efivar_get_monitor: + * @guid: Globally unique identifier + * @name: Variable name + * @error: A #GError + * + * Returns a file monitor for a specific key. + * + * Returns: (transfer full): a #GFileMonitor, or %NULL for an error + * + * Since: 1.5.5 + **/ +GFileMonitor * +fu_efivar_get_monitor (const gchar *guid, const gchar *name, GError **error) +{ + g_autofree gchar *fn = NULL; + g_autoptr(GFile) file = NULL; + g_autoptr(GFileMonitor) monitor = NULL; + + g_return_val_if_fail (guid != NULL, NULL); + g_return_val_if_fail (name != NULL, NULL); + + fn = fu_efivar_get_filename (guid, name); + file = g_file_new_for_path (fn); + monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, error); + if (monitor == NULL) + return NULL; + g_file_monitor_set_rate_limit (monitor, 5000); + return g_steal_pointer (&monitor); +} + +/** + * fu_efivar_space_used: + * @error: A #GError + * + * Gets the total size used by all EFI variables. This may be less than the size reported by the + * kernel as some (hopefully small) variables are hidden from userspace. + * + * Returns: total allocated size of all visible variables, or %G_MAXUINT64 on error + * + * Since: 1.5.1 + **/ +guint64 +fu_efivar_space_used (GError **error) +{ + const gchar *fn; + guint64 total = 0; + g_autoptr(GDir) dir = NULL; + g_autofree gchar *path = fu_efivar_get_path (); + + g_return_val_if_fail (error == NULL || *error == NULL, G_MAXUINT64); + + /* stat each file */ + dir = g_dir_open (path, 0, error); + if (dir == NULL) + return G_MAXUINT64; + while ((fn = g_dir_read_name (dir)) != NULL) { + guint64 sz; + g_autofree gchar *pathfn = g_build_filename (path, fn, NULL); + g_autoptr(GFile) file = g_file_new_for_path (pathfn); + g_autoptr(GFileInfo) info = NULL; + + info = g_file_query_info (file, + G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE "," + G_FILE_ATTRIBUTE_STANDARD_SIZE, + G_FILE_QUERY_INFO_NONE, + NULL, error); + if (info == NULL) + return G_MAXUINT64; + sz = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE); + if (sz == 0) + sz = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_STANDARD_SIZE); + total += sz; + } + + /* success */ + return total; +} +/** * fu_efivar_set_data: * @guid: Globally unique identifier * @name: Variable name @@ -349,12 +548,18 @@ { #ifndef _WIN32 int fd; + int open_wflags; gboolean was_immutable; g_autofree gchar *fn = fu_efivar_get_filename (guid, name); g_autofree guint8 *buf = g_malloc0 (sizeof(guint32) + sz); g_autoptr(GFile) file = g_file_new_for_path (fn); g_autoptr(GOutputStream) ostr = NULL; + g_return_val_if_fail (guid != NULL, FALSE); + g_return_val_if_fail (name != NULL, FALSE); + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + /* create empty file so we can clear the immutable bit before writing */ if (!g_file_query_exists (file, NULL)) { g_autoptr(GFileOutputStream) ostr_tmp = NULL; @@ -374,8 +579,11 @@ return FALSE; } - /* open file for writing */ - fd = open (fn, O_WRONLY); + /* open file for writing, optionally append */ + open_wflags = O_WRONLY; + if (attr & FU_EFIVAR_ATTR_APPEND_WRITE) + open_wflags |= O_APPEND; + fd = open (fn, open_wflags); if (fd < 0) { g_set_error (error, G_IO_ERROR, @@ -410,24 +618,83 @@ } /** - * fu_efivar_secure_boot_enabled: + * fu_efivar_set_data_bytes: + * @guid: Globally unique identifier + * @name: Variable name + * @bytes: a #GBytes + * @attr: Attributes + * @error: A #GError + * + * Sets the data to a UEFI variable in NVRAM + * + * Returns: %TRUE on success + * + * Since: 1.5.0 + **/ +gboolean +fu_efivar_set_data_bytes (const gchar *guid, const gchar *name, GBytes *bytes, + guint32 attr, GError **error) +{ + gsize bufsz = 0; + const guint8 *buf; + + g_return_val_if_fail (guid != NULL, FALSE); + g_return_val_if_fail (name != NULL, FALSE); + g_return_val_if_fail (bytes != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + buf = g_bytes_get_data (bytes, &bufsz); + return fu_efivar_set_data (guid, name, buf, bufsz, attr, error); +} + +/** + * fu_efivar_secure_boot_enabled_full: + * @error: A #GError * * Determines if secure boot was enabled * * Returns: %TRUE on success * - * Since: 1.4.0 + * Since: 1.5.0 **/ gboolean -fu_efivar_secure_boot_enabled (void) +fu_efivar_secure_boot_enabled_full (GError **error) { gsize data_size = 0; g_autofree guint8 *data = NULL; + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + if (!fu_efivar_get_data (FU_EFIVAR_GUID_EFI_GLOBAL, "SecureBoot", - &data, &data_size, NULL, NULL)) + &data, &data_size, NULL, NULL)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "SecureBoot is not available"); return FALSE; + } if (data_size >= 1 && data[0] & 1) return TRUE; + + /* available, but not enabled */ + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "SecureBoot is not enabled"); return FALSE; } + +/** + * fu_efivar_secure_boot_enabled: + * + * Determines if secure boot was enabled + * + * Returns: %TRUE on success + * + * Since: 1.4.0 + **/ +gboolean +fu_efivar_secure_boot_enabled (void) +{ + return fu_efivar_secure_boot_enabled_full (NULL); +} diff -Nru fwupd-1.4.5/libfwupdplugin/fu-efivar.h fwupd-1.5.8/libfwupdplugin/fu-efivar.h --- fwupd-1.4.5/libfwupdplugin/fu-efivar.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-efivar.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,45 +1,70 @@ /* * Copyright (C) 2018 Richard Hughes - * Copyright (C) 2015-2017 Peter Jones + * Copyright (C) 2015 Peter Jones * * SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -#include +#include #define FU_EFIVAR_GUID_EFI_GLOBAL "8be4df61-93ca-11d2-aa0d-00e098032b8c" -#define FU_EFIVAR_GUID_FWUPDATE "0abba7dc-e516-4167-bbf5-4d9d1c739416" +#define FU_EFIVAR_GUID_FWUPDATE "0abba7dc-e516-4167-bbf5-4d9d1c739416" +#define FU_EFIVAR_GUID_UX_CAPSULE "3b8c8162-188c-46a4-aec9-be43f1d65697" +#define FU_EFIVAR_GUID_SECURITY_DATABASE "d719b2cb-3d3a-4596-a3bc-dad00e67656f" #define FU_EFIVAR_GUID_UX_CAPSULE "3b8c8162-188c-46a4-aec9-be43f1d65697" #define FU_EFIVAR_ATTR_NON_VOLATILE (1 << 0) #define FU_EFIVAR_ATTR_BOOTSERVICE_ACCESS (1 << 1) -#define FU_EFIVAR_ATTR_RUNTIME_ACCESS (1 << 2) +#define FU_EFIVAR_ATTR_RUNTIME_ACCESS (1 << 2) #define FU_EFIVAR_ATTR_HARDWARE_ERROR_RECORD (1 << 3) #define FU_EFIVAR_ATTR_AUTHENTICATED_WRITE_ACCESS (1 << 4) -#define FU_EFIVAR_ATTR_TIME_BASED_AUTHENTICATED_WRITE_ACCESS (5 << 0) +#define FU_EFIVAR_ATTR_TIME_BASED_AUTHENTICATED_WRITE_ACCESS (1 << 5) #define FU_EFIVAR_ATTR_APPEND_WRITE (1 << 6) gboolean fu_efivar_supported (GError **error); +guint64 fu_efivar_space_used (GError **error); gboolean fu_efivar_exists (const gchar *guid, const gchar *name); +GFileMonitor *fu_efivar_get_monitor (const gchar *guid, + const gchar *name, + GError **error); gboolean fu_efivar_get_data (const gchar *guid, const gchar *name, guint8 **data, gsize *data_sz, guint32 *attr, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +GBytes *fu_efivar_get_data_bytes (const gchar *guid, + const gchar *name, + guint32 *attr, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_efivar_set_data (const gchar *guid, const gchar *name, const guint8 *data, gsize sz, guint32 attr, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fu_efivar_set_data_bytes (const gchar *guid, + const gchar *name, + GBytes *bytes, + guint32 attr, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_efivar_delete (const gchar *guid, const gchar *name, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_efivar_delete_with_glob (const gchar *guid, const gchar *name_glob, - GError **error); -gboolean fu_efivar_secure_boot_enabled (void); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +GPtrArray *fu_efivar_get_names (const gchar *guid, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fu_efivar_secure_boot_enabled (void); +gboolean fu_efivar_secure_boot_enabled_full(GError **error); diff -Nru fwupd-1.4.5/libfwupdplugin/fu-firmware.c fwupd-1.5.8/libfwupdplugin/fu-firmware.c --- fwupd-1.4.5/libfwupdplugin/fu-firmware.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-firmware.c 2021-03-31 20:08:32.000000000 +0000 @@ -21,14 +21,103 @@ */ typedef struct { + FuFirmwareFlags flags; GPtrArray *images; /* FuFirmwareImage */ gchar *version; + guint64 version_raw; } FuFirmwarePrivate; G_DEFINE_TYPE_WITH_PRIVATE (FuFirmware, fu_firmware, G_TYPE_OBJECT) #define GET_PRIVATE(o) (fu_firmware_get_instance_private (o)) /** + * fu_firmware_flag_to_string: + * @flag: A #FuFirmwareFlags, e.g. %FU_FIRMWARE_FLAG_DEDUPE_ID + * + * Converts a #FuFirmwareFlags to a string. + * + * Return value: identifier string + * + * Since: 1.5.0 + **/ +const gchar * +fu_firmware_flag_to_string (FuFirmwareFlags flag) +{ + if (flag == FU_FIRMWARE_FLAG_NONE) + return "none"; + if (flag == FU_FIRMWARE_FLAG_DEDUPE_ID) + return "dedupe-id"; + if (flag == FU_FIRMWARE_FLAG_DEDUPE_IDX) + return "dedupe-idx"; + if (flag == FU_FIRMWARE_FLAG_HAS_CHECKSUM) + return "has-checksum"; + if (flag == FU_FIRMWARE_FLAG_HAS_VID_PID) + return "has-vid-pid"; + return NULL; +} + +/** + * fu_firmware_flag_from_string: + * @flag: A string, e.g. `dedupe-id` + * + * Converts a string to a #FuFirmwareFlags. + * + * Return value: enumerated value + * + * Since: 1.5.0 + **/ +FuFirmwareFlags +fu_firmware_flag_from_string (const gchar *flag) +{ + if (g_strcmp0 (flag, "dedupe-id") == 0) + return FU_FIRMWARE_FLAG_DEDUPE_ID; + if (g_strcmp0 (flag, "dedupe-idx") == 0) + return FU_FIRMWARE_FLAG_DEDUPE_IDX; + if (g_strcmp0 (flag, "has-checksum") == 0) + return FU_FIRMWARE_FLAG_HAS_CHECKSUM; + if (g_strcmp0 (flag, "has-vid-pid") == 0) + return FU_FIRMWARE_FLAG_HAS_VID_PID; + return FU_FIRMWARE_FLAG_NONE; +} + +/** + * fu_firmware_add_flag: + * @firmware: A #FuFirmware + * @flag: the #FuFirmwareFlags + * + * Adds a specific firmware flag to the firmware. + * + * Since: 1.5.0 + **/ +void +fu_firmware_add_flag (FuFirmware *firmware, FuFirmwareFlags flag) +{ + FuFirmwarePrivate *priv = GET_PRIVATE (firmware); + g_return_if_fail (FU_IS_FIRMWARE (firmware)); + priv->flags |= flag; +} + + +/** + * fu_firmware_has_flag: + * @firmware: A #FuFirmware + * @flag: the #FuFirmwareFlags + * + * Finds if the firmware has a specific firmware flag. + * + * Returns: %TRUE if the flag is set + * + * Since: 1.5.0 + **/ +gboolean +fu_firmware_has_flag (FuFirmware *firmware, FuFirmwareFlags flag) +{ + FuFirmwarePrivate *priv = GET_PRIVATE (firmware); + g_return_val_if_fail (FU_IS_FIRMWARE (firmware), FALSE); + return (priv->flags & flag) > 0; +} + +/** * fu_firmware_get_version: * @self: A #FuFirmware * @@ -60,11 +149,55 @@ { FuFirmwarePrivate *priv = GET_PRIVATE (self); g_return_if_fail (FU_IS_FIRMWARE (self)); + + /* not changed */ + if (g_strcmp0 (priv->version, version) == 0) + return; + g_free (priv->version); priv->version = g_strdup (version); } /** + * fu_firmware_get_version_raw: + * @self: A #FuFirmware + * + * Gets an raw version that represents the firmware. This is most frequently + * used when building firmware with `0x123456` in a + * `firmware.builder.xml` file to avoid string splitting and sanity checks. + * + * Returns: an integer, or %G_MAXUINT64 for invalid + * + * Since: 1.5.7 + **/ +guint64 +fu_firmware_get_version_raw (FuFirmware *self) +{ + FuFirmwarePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_FIRMWARE (self), G_MAXUINT64); + return priv->version_raw; +} + +/** + * fu_firmware_set_version_raw: + * @self: A #FuFirmware + * @version_raw: A raw version, or %G_MAXUINT64 for invalid + * + * Sets an raw version that represents the firmware. + * + * This is optional, and is typically only used for debugging. + * + * Since: 1.5.7 + **/ +void +fu_firmware_set_version_raw (FuFirmware *self, guint64 version_raw) +{ + FuFirmwarePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_FIRMWARE (self)); + priv->version_raw = version_raw; +} + +/** * fu_firmware_tokenize: * @self: A #FuFirmware * @fw: A #GBytes @@ -126,6 +259,15 @@ g_return_val_if_fail (fw != NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + /* sanity check */ + if (g_bytes_get_size (fw) == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid firmware as zero sized"); + return FALSE; + } + /* subclassed */ if (klass->tokenize != NULL) { if (!klass->tokenize (self, fw, flags, error)) @@ -160,6 +302,112 @@ } /** + * fu_firmware_build: + * @self: A #FuFirmware + * @n: A #XbNode + * @error: A #GError, or %NULL + * + * Builds a firmware from an XML manifest. The manifest would typically have the + * following form: + * + * |[ + * + * + * 1.2.3 + * + * 7.8.9 + * stage1 + * 0x01 + * stage1.bin + * + * + * stage2 + * + * + * + * ape + * 0x7 + * aGVsbG8gd29ybGQ= + * + * + * ]| + * + * This would be used in a build-system to merge images from generated files: + * `fwupdtool firmware-build fw.builder.xml test.fw` + * + * Static binary content can be specified in the `/` sections and + * is encoded as base64 text if not empty. + * + * Additionally, extra nodes can be included under `` and `` + * which can be parsed by the subclassed objects. You should verify the + * subclassed object `FuFirmwareImage->build` vfunc for the specific additional + * options supported. + * + * Plugins should manually g_type_ensure() subclassed image objects if not + * constructed as part of the plugin fu_plugin_init() or fu_plugin_setup() + * functions. + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fu_firmware_build (FuFirmware *self, XbNode *n, GError **error) +{ + FuFirmwareClass *klass = FU_FIRMWARE_GET_CLASS (self); + const gchar *tmp; + guint64 version_raw; + g_autoptr(GPtrArray) xb_images = NULL; + + g_return_val_if_fail (FU_IS_FIRMWARE (self), FALSE); + g_return_val_if_fail (XB_IS_NODE (n), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* set attributes */ + tmp = xb_node_query_text (n, "version", NULL); + if (tmp != NULL) + fu_firmware_set_version (self, tmp); + version_raw = xb_node_query_text_as_uint (n, "version_raw", NULL); + if (version_raw != G_MAXUINT64) + fu_firmware_set_version_raw (self, version_raw); + + /* parse images */ + xb_images = xb_node_query (n, "image", 0, NULL); + if (xb_images != NULL) { + for (guint i = 0; i < xb_images->len; i++) { + XbNode *xb_image = g_ptr_array_index (xb_images, i); + g_autoptr(FuFirmwareImage) img = NULL; + tmp = xb_node_get_attr (xb_image, "gtype"); + if (tmp != NULL) { + GType gtype = g_type_from_name (tmp); + if (gtype == G_TYPE_INVALID) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "GType %s not registered", tmp); + return FALSE; + } + img = g_object_new (gtype, NULL); + } else { + img = fu_firmware_image_new (NULL); + } + if (!fu_firmware_image_build (img, xb_image, error)) + return FALSE; + fu_firmware_add_image (self, img); + } + } + + /* subclassed */ + if (klass->build != NULL) { + if (!klass->build (self, n, error)) + return FALSE; + } + + /* success */ + return TRUE; +} + +/** * fu_firmware_parse_file: * @self: A #FuFirmware * @file: A #GFile @@ -178,6 +426,11 @@ gchar *buf = NULL; gsize bufsz = 0; g_autoptr(GBytes) fw = NULL; + + g_return_val_if_fail (FU_IS_FIRMWARE (self), FALSE); + g_return_val_if_fail (G_IS_FILE (file), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + if (!g_file_load_contents (file, NULL, &buf, &bufsz, NULL, error)) return FALSE; fw = g_bytes_new_take (buf, bufsz); @@ -227,6 +480,11 @@ fu_firmware_write_file (FuFirmware *self, GFile *file, GError **error) { g_autoptr(GBytes) blob = NULL; + + g_return_val_if_fail (FU_IS_FIRMWARE (self), FALSE); + g_return_val_if_fail (G_IS_FILE (file), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + blob = fu_firmware_write (self, error); if (blob == NULL) return FALSE; @@ -245,7 +503,8 @@ * * Adds an image to the firmware. * - * If an image with the same ID is already present it is replaced. + * If %FU_FIRMWARE_FLAG_DEDUPE_ID is set, an image with the same ID is already + * present it is replaced. * * Since: 1.3.1 **/ @@ -255,10 +514,119 @@ FuFirmwarePrivate *priv = GET_PRIVATE (self); g_return_if_fail (FU_IS_FIRMWARE (self)); g_return_if_fail (FU_IS_FIRMWARE_IMAGE (img)); + + /* dedupe */ + for (guint i = 0; i < priv->images->len; i++) { + FuFirmwareImage *img_tmp = g_ptr_array_index (priv->images, i); + if (priv->flags & FU_FIRMWARE_FLAG_DEDUPE_ID) { + if (g_strcmp0 (fu_firmware_image_get_id (img_tmp), + fu_firmware_image_get_id (img)) == 0) { + g_ptr_array_remove_index (priv->images, i); + break; + } + } + if (priv->flags & FU_FIRMWARE_FLAG_DEDUPE_IDX) { + if (fu_firmware_image_get_idx (img_tmp) == + fu_firmware_image_get_idx (img)) { + g_ptr_array_remove_index (priv->images, i); + break; + } + } + } + g_ptr_array_add (priv->images, g_object_ref (img)); } /** + * fu_firmware_remove_image: + * @self: a #FuPlugin + * @img: A #FuFirmwareImage + * @error: A #GError, or %NULL + * + * Remove an image from the firmware. + * + * Returns: %TRUE if the image was removed + * + * Since: 1.5.0 + **/ +gboolean +fu_firmware_remove_image (FuFirmware *self, FuFirmwareImage *img, GError **error) +{ + FuFirmwarePrivate *priv = GET_PRIVATE (self); + + g_return_val_if_fail (FU_IS_FIRMWARE (self), FALSE); + g_return_val_if_fail (FU_IS_FIRMWARE_IMAGE (img), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + if (g_ptr_array_remove (priv->images, img)) + return TRUE; + + /* did not exist */ + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "image %s not found in firmware", + fu_firmware_image_get_id (img)); + return FALSE; +} + +/** + * fu_firmware_remove_image_by_idx: + * @self: a #FuPlugin + * @idx: index + * @error: A #GError, or %NULL + * + * Removes the first image from the firmware matching the index. + * + * Returns: %TRUE if an image was removed + * + * Since: 1.5.0 + **/ +gboolean +fu_firmware_remove_image_by_idx (FuFirmware *self, guint64 idx, GError **error) +{ + FuFirmwarePrivate *priv = GET_PRIVATE (self); + g_autoptr(FuFirmwareImage) img = NULL; + + g_return_val_if_fail (FU_IS_FIRMWARE (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + img = fu_firmware_get_image_by_idx (self, idx, error); + if (img == NULL) + return FALSE; + g_ptr_array_remove (priv->images, img); + return TRUE; +} + +/** + * fu_firmware_remove_image_by_id: + * @self: a #FuPlugin + * @id: (nullable): image ID, e.g. "config" + * @error: A #GError, or %NULL + * + * Removes the first image from the firmware matching the ID. + * + * Returns: %TRUE if an image was removed + * + * Since: 1.5.0 + **/ +gboolean +fu_firmware_remove_image_by_id (FuFirmware *self, const gchar *id, GError **error) +{ + FuFirmwarePrivate *priv = GET_PRIVATE (self); + g_autoptr(FuFirmwareImage) img = NULL; + + g_return_val_if_fail (FU_IS_FIRMWARE (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + img = fu_firmware_get_image_by_id (self, id, error); + if (img == NULL) + return FALSE; + g_ptr_array_remove (priv->images, img); + return TRUE; +} + +/** * fu_firmware_get_images: * @self: a #FuFirmware * @@ -370,6 +738,51 @@ } /** + * fu_firmware_get_image_by_checksum: + * @self: a #FuPlugin + * @checksum: checksum string of any format + * @error: A #GError, or %NULL + * + * Gets the firmware image using the image checksum. The checksum type is guessed + * based on the length of the input string. + * + * Returns: (transfer full): a #FuFirmwareImage, or %NULL if the image is not found + * + * Since: 1.5.5 + **/ +FuFirmwareImage * +fu_firmware_get_image_by_checksum (FuFirmware *self, + const gchar *checksum, + GError **error) +{ + FuFirmwarePrivate *priv = GET_PRIVATE (self); + GChecksumType csum_kind; + + g_return_val_if_fail (FU_IS_FIRMWARE (self), NULL); + g_return_val_if_fail (checksum != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + csum_kind = fwupd_checksum_guess_kind (checksum); + for (guint i = 0; i < priv->images->len; i++) { + FuFirmwareImage *img = g_ptr_array_index (priv->images, i); + g_autofree gchar *checksum_tmp = NULL; + + /* if this expensive then the subclassed FuFirmwareImage can + * cache the result as required */ + checksum_tmp = fu_firmware_image_get_checksum (img, csum_kind, error); + if (checksum_tmp == NULL) + return NULL; + if (g_strcmp0 (checksum_tmp, checksum) == 0) + return g_object_ref (img); + } + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "no image with checksum %s found in firmware", checksum); + return NULL; +} + +/** * fu_firmware_get_image_by_idx_bytes: * @self: a #FuPlugin * @idx: image index @@ -464,8 +877,22 @@ /* subclassed type */ fu_common_string_append_kv (str, 0, G_OBJECT_TYPE_NAME (self), NULL); + if (priv->flags != FU_FIRMWARE_FLAG_NONE) { + g_autoptr(GString) tmp = g_string_new (""); + for (guint i = 0; i < 64; i++) { + if ((priv->flags & ((guint64) 1 << i)) == 0) + continue; + g_string_append_printf (tmp, "%s|", + fu_firmware_flag_to_string ((guint64) 1 << i)); + } + if (tmp->len > 0) + g_string_truncate (tmp, tmp->len - 1); + fu_common_string_append_kv (str, 0, "Flags", tmp->str); + } if (priv->version != NULL) fu_common_string_append_kv (str, 0, "Version", priv->version); + if (priv->version_raw != 0x0) + fu_common_string_append_kx (str, 0, "VersionRaw", priv->version_raw); /* vfunc */ if (klass->to_string != NULL) @@ -538,3 +965,68 @@ fu_firmware_add_image (self, img); return self; } + +/** + * fu_firmware_new_from_gtypes: + * @fw: a #GBytes + * @flags: a #FwupdInstallFlags, e.g. %FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM + * @error: (nullable): a #GError or %NULL + * @...: An array of #GTypes, ending with %G_TYPE_INVALID + * + * Tries to parse the firmware with each #GType in order. + * + * Return value: (transfer full) (nullable): A #FuFirmware, or %NULL + * + * Since: 1.5.6 + **/ +FuFirmware * +fu_firmware_new_from_gtypes (GBytes *fw, FwupdInstallFlags flags, GError **error, ...) +{ + va_list args; + g_autoptr(GArray) gtypes = g_array_new (FALSE, FALSE, sizeof(GType)); + g_autoptr(GError) error_all = NULL; + + g_return_val_if_fail (fw != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* create array of GTypes */ + va_start (args, error); + for (guint i = 0; ; i++) { + GType gtype = va_arg (args, GType); + if (gtype == G_TYPE_INVALID) + break; + g_array_append_val (gtypes, gtype); + } + va_end (args); + + /* invalid */ + if (gtypes->len == 0) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + "no GTypes specified"); + return NULL; + } + + /* try each GType in turn */ + for (guint i = 0; i < gtypes->len; i++) { + GType gtype = g_array_index (gtypes, GType, i); + g_autoptr(FuFirmware) firmware = g_object_new (gtype, NULL); + g_autoptr(GError) error_local = NULL; + if (!fu_firmware_parse (firmware, fw, flags, &error_local)) { + if (error_all == NULL) { + g_propagate_error (&error_all, + g_steal_pointer (&error_local)); + } else { + g_prefix_error (&error_all, "%s: ", + error_local->message); + } + continue; + } + return g_steal_pointer (&firmware); + } + + /* failed */ + g_propagate_error (error, g_steal_pointer (&error_all)); + return NULL; +} diff -Nru fwupd-1.4.5/libfwupdplugin/fu-firmware-common.c fwupd-1.5.8/libfwupdplugin/fu-firmware-common.c --- fwupd-1.4.5/libfwupdplugin/fu-firmware-common.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-firmware-common.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2019 Richard Hughes + * Copyright (C) 2015 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -10,6 +10,7 @@ #include +#include "fu-common.h" #include "fu-firmware-common.h" /** @@ -121,3 +122,163 @@ buffer[8] = '\0'; return (guint32) g_ascii_strtoull (buffer, NULL, 16); } + +/** + * fu_firmware_strparse_uint4_safe: + * @data: destination buffer + * @datasz: size of @data, typcally the same as `strlen(data)` + * @offset: offset in chars into @data to read + * @value: (out) (nullable): parsed value + * @error: A #GError or %NULL + * + * Parses a base 16 number from a string of 1 character in length. + * The returned @value will range from from 0 to 0xf. + * + * Return value: %TRUE if parsed, %FALSE otherwise + * + * Since: 1.5.6 + **/ +gboolean +fu_firmware_strparse_uint4_safe (const gchar *data, + gsize datasz, + gsize offset, + guint8 *value, + GError **error) +{ + gchar buffer[2] = { '\0' }; + if (!fu_memcpy_safe ((guint8 *) buffer, sizeof(buffer), 0x0, /* dst */ + (const guint8 *) data, datasz, offset, /* src */ + sizeof(buffer) - 1, error)) + return FALSE; + if (value != NULL) + *value = (guint8) g_ascii_strtoull (buffer, NULL, 16); + return TRUE; +} + +/** + * fu_firmware_strparse_uint8_safe: + * @data: destination buffer + * @datasz: size of @data, typcally the same as `strlen(data)` + * @offset: offset in chars into @data to read + * @value: (out) (nullable): parsed value + * @error: A #GError or %NULL + * + * Parses a base 16 number from a string of 2 characters in length. + * The returned @value will range from from 0 to 0xff. + * + * Return value: %TRUE if parsed, %FALSE otherwise + * + * Since: 1.5.6 + **/ +gboolean +fu_firmware_strparse_uint8_safe (const gchar *data, + gsize datasz, + gsize offset, + guint8 *value, + GError **error) +{ + gchar buffer[3] = { '\0' }; + if (!fu_memcpy_safe ((guint8 *) buffer, sizeof(buffer), 0x0, /* dst */ + (const guint8 *) data, datasz, offset, /* src */ + sizeof(buffer) - 1, error)) + return FALSE; + if (value != NULL) + *value = (guint8) g_ascii_strtoull (buffer, NULL, 16); + return TRUE; +} + +/** + * fu_firmware_strparse_uint16_safe: + * @data: destination buffer + * @datasz: size of @data, typcally the same as `strlen(data)` + * @offset: offset in chars into @data to read + * @value: (out) (nullable): parsed value + * @error: A #GError or %NULL + * + * Parses a base 16 number from a string of 4 characters in length. + * The returned @value will range from from 0 to 0xffff. + * + * Return value: %TRUE if parsed, %FALSE otherwise + * + * Since: 1.5.6 + **/ +gboolean +fu_firmware_strparse_uint16_safe (const gchar *data, + gsize datasz, + gsize offset, + guint16 *value, + GError **error) +{ + gchar buffer[5] = { '\0' }; + if (!fu_memcpy_safe ((guint8 *) buffer, sizeof(buffer), 0x0, /* dst */ + (const guint8 *) data, datasz, offset, /* src */ + sizeof(buffer) - 1, error)) + return FALSE; + if (value != NULL) + *value = (guint16) g_ascii_strtoull (buffer, NULL, 16); + return TRUE; +} + +/** + * fu_firmware_strparse_uint24_safe: + * @data: destination buffer + * @datasz: size of @data, typcally the same as `strlen(data)` + * @offset: offset in chars into @data to read + * @value: (out) (nullable): parsed value + * @error: A #GError or %NULL + * + * Parses a base 16 number from a string of 6 characters in length. + * The returned @value will range from from 0 to 0xffffff. + * + * Return value: %TRUE if parsed, %FALSE otherwise + * + * Since: 1.5.6 + **/ +gboolean +fu_firmware_strparse_uint24_safe (const gchar *data, + gsize datasz, + gsize offset, + guint32 *value, + GError **error) +{ + gchar buffer[7] = { '\0' }; + if (!fu_memcpy_safe ((guint8 *) buffer, sizeof(buffer), 0x0, /* dst */ + (const guint8 *) data, datasz, offset, /* src */ + sizeof(buffer) - 1, error)) + return FALSE; + if (value != NULL) + *value = (guint16) g_ascii_strtoull (buffer, NULL, 16); + return TRUE; +} + +/** + * fu_firmware_strparse_uint32_safe: + * @data: destination buffer + * @datasz: size of @data, typcally the same as `strlen(data)` + * @offset: offset in chars into @data to read + * @value: (out) (nullable): parsed value + * @error: A #GError or %NULL + * + * Parses a base 16 number from a string of 8 characters in length. + * The returned @value will range from from 0 to 0xffffffff. + * + * Return value: %TRUE if parsed, %FALSE otherwise + * + * Since: 1.5.6 + **/ +gboolean +fu_firmware_strparse_uint32_safe (const gchar *data, + gsize datasz, + gsize offset, + guint32 *value, + GError **error) +{ + gchar buffer[9] = { '\0' }; + if (!fu_memcpy_safe ((guint8 *) buffer, sizeof(buffer), 0x0, /* dst */ + (const guint8 *) data, datasz, offset, /* src */ + sizeof(buffer) - 1, error)) + return FALSE; + if (value != NULL) + *value = (guint32) g_ascii_strtoull (buffer, NULL, 16); + return TRUE; +} diff -Nru fwupd-1.4.5/libfwupdplugin/fu-firmware-common.h fwupd-1.5.8/libfwupdplugin/fu-firmware-common.h --- fwupd-1.4.5/libfwupdplugin/fu-firmware-common.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-firmware-common.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2017 Richard Hughes + * Copyright (C) 2015 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -8,8 +8,39 @@ #include +G_DEPRECATED_FOR(fu_firmware_strparse_uint4_safe) guint8 fu_firmware_strparse_uint4 (const gchar *data); +G_DEPRECATED_FOR(fu_firmware_strparse_uint8_safe) guint8 fu_firmware_strparse_uint8 (const gchar *data); +G_DEPRECATED_FOR(fu_firmware_strparse_uint16_safe) guint16 fu_firmware_strparse_uint16 (const gchar *data); +G_DEPRECATED_FOR(fu_firmware_strparse_uint24_safe) guint32 fu_firmware_strparse_uint24 (const gchar *data); +G_DEPRECATED_FOR(fu_firmware_strparse_uint32_safe) guint32 fu_firmware_strparse_uint32 (const gchar *data); + +gboolean fu_firmware_strparse_uint4_safe (const gchar *data, + gsize datasz, + gsize offset, + guint8 *value, + GError **error); +gboolean fu_firmware_strparse_uint8_safe (const gchar *data, + gsize datasz, + gsize offset, + guint8 *value, + GError **error); +gboolean fu_firmware_strparse_uint16_safe (const gchar *data, + gsize datasz, + gsize offset, + guint16 *value, + GError **error); +gboolean fu_firmware_strparse_uint24_safe (const gchar *data, + gsize datasz, + gsize offset, + guint32 *value, + GError **error); +gboolean fu_firmware_strparse_uint32_safe (const gchar *data, + gsize datasz, + gsize offset, + guint32 *value, + GError **error); diff -Nru fwupd-1.4.5/libfwupdplugin/fu-firmware.h fwupd-1.5.8/libfwupdplugin/fu-firmware.h --- fwupd-1.4.5/libfwupdplugin/fu-firmware.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-firmware.h 2021-03-31 20:08:32.000000000 +0000 @@ -22,53 +22,110 @@ guint64 addr_start, guint64 addr_end, FwupdInstallFlags flags, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; GBytes *(*write) (FuFirmware *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; void (*to_string) (FuFirmware *self, guint indent, GString *str); gboolean (*tokenize) (FuFirmware *self, GBytes *fw, FwupdInstallFlags flags, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; + gboolean (*build) (FuFirmware *self, + XbNode *n, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; /*< private >*/ - gpointer padding[28]; + gpointer padding[27]; }; +/** + * FuFirmwareFlags: + * @FU_FIRMWARE_FLAG_NONE: No flags set + * @FU_FIRMWARE_FLAG_DEDUPE_ID: Dedupe imges by ID + * @FU_FIRMWARE_FLAG_DEDUPE_IDX: Dedupe imges by IDX + * @FU_FIRMWARE_FLAG_HAS_CHECKSUM: Has a CRC or checksum to test internal consistency + * @FU_FIRMWARE_FLAG_HAS_VID_PID: Has a vendor or product ID in the firmware + * + * The firmware flags. + **/ +#define FU_FIRMWARE_FLAG_NONE (0u) /* Since: 1.5.0 */ +#define FU_FIRMWARE_FLAG_DEDUPE_ID (1u << 0) /* Since: 1.5.0 */ +#define FU_FIRMWARE_FLAG_DEDUPE_IDX (1u << 1) /* Since: 1.5.0 */ +#define FU_FIRMWARE_FLAG_HAS_CHECKSUM (1u << 2) /* Since: 1.5.6 */ +#define FU_FIRMWARE_FLAG_HAS_VID_PID (1u << 3) /* Since: 1.5.6 */ +typedef guint64 FuFirmwareFlags; + +const gchar *fu_firmware_flag_to_string (FuFirmwareFlags flag); +FuFirmwareFlags fu_firmware_flag_from_string (const gchar *flag); + FuFirmware *fu_firmware_new (void); FuFirmware *fu_firmware_new_from_bytes (GBytes *fw); +FuFirmware *fu_firmware_new_from_gtypes (GBytes *fw, + FwupdInstallFlags flags, + GError **error, + ...); gchar *fu_firmware_to_string (FuFirmware *self); const gchar *fu_firmware_get_version (FuFirmware *self); void fu_firmware_set_version (FuFirmware *self, const gchar *version); +guint64 fu_firmware_get_version_raw (FuFirmware *self); +void fu_firmware_set_version_raw (FuFirmware *self, + guint64 version_raw); +void fu_firmware_add_flag (FuFirmware *firmware, + FuFirmwareFlags flag); +gboolean fu_firmware_has_flag (FuFirmware *firmware, + FuFirmwareFlags flag); gboolean fu_firmware_tokenize (FuFirmware *self, GBytes *fw, FwupdInstallFlags flags, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fu_firmware_build (FuFirmware *self, + XbNode *n, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_firmware_parse (FuFirmware *self, GBytes *fw, FwupdInstallFlags flags, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_firmware_parse_file (FuFirmware *self, GFile *file, FwupdInstallFlags flags, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_firmware_parse_full (FuFirmware *self, GBytes *fw, guint64 addr_start, guint64 addr_end, FwupdInstallFlags flags, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; GBytes *fu_firmware_write (FuFirmware *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_firmware_write_file (FuFirmware *self, GFile *file, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; void fu_firmware_add_image (FuFirmware *self, FuFirmwareImage *img); +gboolean fu_firmware_remove_image (FuFirmware *self, + FuFirmwareImage *img, + GError **error); +gboolean fu_firmware_remove_image_by_idx (FuFirmware *self, + guint64 idx, + GError **error); +gboolean fu_firmware_remove_image_by_id (FuFirmware *self, + const gchar *id, + GError **error); GPtrArray *fu_firmware_get_images (FuFirmware *self); FuFirmwareImage *fu_firmware_get_image_by_id (FuFirmware *self, const gchar *id, @@ -82,6 +139,9 @@ GBytes *fu_firmware_get_image_by_idx_bytes (FuFirmware *self, guint64 idx, GError **error); +FuFirmwareImage *fu_firmware_get_image_by_checksum (FuFirmware *self, + const gchar *checksum, + GError **error); FuFirmwareImage *fu_firmware_get_image_default (FuFirmware *self, GError **error); GBytes *fu_firmware_get_image_default_bytes (FuFirmware *self, diff -Nru fwupd-1.4.5/libfwupdplugin/fu-firmware-image.c fwupd-1.5.8/libfwupdplugin/fu-firmware-image.c --- fwupd-1.4.5/libfwupdplugin/fu-firmware-image.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-firmware-image.c 2021-03-31 20:08:32.000000000 +0000 @@ -9,21 +9,25 @@ #include "config.h" #include "fu-common.h" +#include "fu-chunk-private.h" #include "fu-firmware-image-private.h" /** - * SECTION:fu-firmware_image - * @short_description: a firmware_image file + * SECTION:fu-firmware-image + * @short_description: a firmware image section * - * An object that represents a firmware_image file. + * An object that represents an image within the firmware file. */ typedef struct { gchar *id; GBytes *bytes; guint64 addr; + guint64 offset; guint64 idx; gchar *version; + gchar *filename; + GPtrArray *chunks; /* nullable, element-type FuChunk */ } FuFirmwareImagePrivate; G_DEFINE_TYPE_WITH_PRIVATE (FuFirmwareImage, fu_firmware_image, G_TYPE_OBJECT) @@ -61,11 +65,57 @@ { FuFirmwareImagePrivate *priv = GET_PRIVATE (self); g_return_if_fail (FU_IS_FIRMWARE_IMAGE (self)); + + /* not changed */ + if (g_strcmp0 (priv->version, version) == 0) + return; + g_free (priv->version); priv->version = g_strdup (version); } /** + * fu_firmware_image_get_filename: + * @self: A #FuFirmwareImage + * + * Gets an optional filename that represents the image source or destination. + * + * Returns: a string, or %NULL + * + * Since: 1.5.0 + **/ +const gchar * +fu_firmware_image_get_filename (FuFirmwareImage *self) +{ + FuFirmwareImagePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_FIRMWARE_IMAGE (self), NULL); + return priv->filename; +} + +/** + * fu_firmware_image_set_filename: + * @self: A #FuFirmwareImage + * @filename: (nullable): A string filename, or %NULL + * + * Sets an optional filename that represents the image source or destination. + * + * Since: 1.5.0 + **/ +void +fu_firmware_image_set_filename (FuFirmwareImage *self, const gchar *filename) +{ + FuFirmwareImagePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_FIRMWARE_IMAGE (self)); + + /* not changed */ + if (g_strcmp0 (priv->filename, filename) == 0) + return; + + g_free (priv->filename); + priv->filename = g_strdup (filename); +} + +/** * fu_firmware_image_set_id: * @self: a #FuPlugin * @id: (nullable): image ID, e.g. "config" @@ -77,6 +127,11 @@ { FuFirmwareImagePrivate *priv = GET_PRIVATE (self); g_return_if_fail (FU_IS_FIRMWARE_IMAGE (self)); + + /* not changed */ + if (g_strcmp0 (priv->id, id) == 0) + return; + g_free (priv->id); priv->id = g_strdup (id); } @@ -135,6 +190,41 @@ } /** + * fu_firmware_image_set_offset: + * @self: a #FuPlugin + * @offset: integer + * + * Sets the base offset of the image. + * + * Since: 1.5.0 + **/ +void +fu_firmware_image_set_offset (FuFirmwareImage *self, guint64 offset) +{ + FuFirmwareImagePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_FIRMWARE_IMAGE (self)); + priv->offset = offset; +} + +/** + * fu_firmware_image_get_offset: + * @self: a #FuPlugin + * + * Gets the base offset of the image. + * + * Returns: integer + * + * Since: 1.5.0 + **/ +guint64 +fu_firmware_image_get_offset (FuFirmwareImage *self) +{ + FuFirmwareImagePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_FIRMWARE_IMAGE (self), G_MAXUINT64); + return priv->offset; +} + +/** * fu_firmware_image_set_idx: * @self: a #FuPlugin * @idx: integer @@ -189,6 +279,250 @@ } /** + * fu_firmware_image_get_bytes: + * @self: a #FuPlugin + * + * Gets the data set using fu_firmware_image_set_bytes(). + * + * This should only really be used by objects subclassing #FuFirmwareImage as + * images are normally exported to a file using fu_firmware_image_write(). + * + * Returns: (transfer full): a #GBytes of the data, or %NULL if the bytes is not set + * + * Since: 1.5.0 + **/ +GBytes * +fu_firmware_image_get_bytes (FuFirmwareImage *self) +{ + FuFirmwareImagePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_FIRMWARE_IMAGE (self), NULL); + if (priv->bytes == NULL) + return NULL; + return g_bytes_ref (priv->bytes); +} +/** + * fu_firmware_image_get_chunks: + * @self: a #FuFirmwareImage + * @error: A #GError, or %NULL + * + * Gets the optional image chunks. + * + * Return value: (transfer container) (element-type FuChunk) (nullable): chunk data, or %NULL + * + * Since: 1.5.6 + **/ +GPtrArray * +fu_firmware_image_get_chunks (FuFirmwareImage *self, GError **error) +{ + FuFirmwareImagePrivate *priv = GET_PRIVATE (self); + + g_return_val_if_fail (FU_IS_FIRMWARE_IMAGE (self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* set */ + if (priv->chunks != NULL) + return g_ptr_array_ref (priv->chunks); + + /* lets build something plausible */ + if (priv->bytes != NULL) { + g_autoptr(GPtrArray) chunks = NULL; + g_autoptr(FuChunk) chk = NULL; + chunks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + chk = fu_chunk_bytes_new (priv->bytes); + fu_chunk_set_idx (chk, priv->idx); + fu_chunk_set_address (chk, priv->addr); + g_ptr_array_add (chunks, g_steal_pointer (&chk)); + return g_steal_pointer (&chunks); + } + + /* nothing to do */ + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "no bytes or chunks found in firmware"); + return NULL; +} + +/** + * fu_firmware_image_add_chunk: + * @self: a #FuFirmwareImage + * @chk: a #FuChunk + * + * Adds a chunk to the image. + * + * Since: 1.5.6 + **/ +void +fu_firmware_image_add_chunk (FuFirmwareImage *self, FuChunk *chk) +{ + FuFirmwareImagePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_FIRMWARE_IMAGE (self)); + g_return_if_fail (FU_IS_CHUNK (chk)); + if (priv->chunks == NULL) + priv->chunks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + g_ptr_array_add (priv->chunks, g_object_ref (chk)); +} + +/** + * fu_firmware_image_get_checksum: + * @self: a #FuPlugin + * @csum_kind: a #GChecksumType, e.g. %G_CHECKSUM_SHA256 + * @error: A #GError, or %NULL + * + * Returns a checksum of the data. + * + * Returns: (transfer full): a checksum string, or %NULL if the checksum is not available + * + * Since: 1.5.5 + **/ +gchar * +fu_firmware_image_get_checksum (FuFirmwareImage *self, + GChecksumType csum_kind, + GError **error) +{ + FuFirmwareImagePrivate *priv = GET_PRIVATE (self); + FuFirmwareImageClass *klass = FU_FIRMWARE_IMAGE_GET_CLASS (self); + + g_return_val_if_fail (FU_IS_FIRMWARE_IMAGE (self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* subclassed */ + if (klass->get_checksum != NULL) + return klass->get_checksum (self, csum_kind, error); + + /* internal data */ + if (priv->bytes == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "no bytes found in firmware bytes %s", + priv->id); + return NULL; + } + return g_compute_checksum_for_bytes (csum_kind, priv->bytes); +} + +/** + * fu_firmware_image_parse: + * @self: A #FuFirmwareImage + * @fw: A #GBytes + * @flags: some #FwupdInstallFlags, e.g. %FWUPD_INSTALL_FLAG_FORCE + * @error: A #GError, or %NULL + * + * Parses a firmware image, typically checking image CRCs and/or headers. + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fu_firmware_image_parse (FuFirmwareImage *self, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + FuFirmwareImageClass *klass = FU_FIRMWARE_IMAGE_GET_CLASS (self); + + g_return_val_if_fail (FU_IS_FIRMWARE_IMAGE (self), FALSE); + g_return_val_if_fail (fw != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* subclassed */ + if (klass->parse != NULL) + return klass->parse (self, fw, flags, error); + + /* just add entire blob */ + fu_firmware_image_set_bytes (self, fw); + return TRUE; +} + +/** + * fu_firmware_image_build: + * @self: A #FuFirmwareImage + * @n: A #XbNode + * @error: A #GError, or %NULL + * + * Builds a firmware image from an XML manifest. + * + * Returns: %TRUE for success + * + * Since: 1.5.0 + **/ +gboolean +fu_firmware_image_build (FuFirmwareImage *self, XbNode *n, GError **error) +{ + FuFirmwareImageClass *klass = FU_FIRMWARE_IMAGE_GET_CLASS (self); + guint64 tmpval; + const gchar *tmp; + g_autoptr(GPtrArray) chunks = NULL; + g_autoptr(XbNode) data = NULL; + + g_return_val_if_fail (FU_IS_FIRMWARE_IMAGE (self), FALSE); + g_return_val_if_fail (XB_IS_NODE (n), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + tmp = xb_node_query_text (n, "version", NULL); + if (tmp != NULL) + fu_firmware_image_set_version (self, tmp); + tmp = xb_node_query_text (n, "id", NULL); + if (tmp != NULL) + fu_firmware_image_set_id (self, tmp); + tmpval = xb_node_query_text_as_uint (n, "idx", NULL); + if (tmpval != G_MAXUINT64) + fu_firmware_image_set_idx (self, tmpval); + tmpval = xb_node_query_text_as_uint (n, "addr", NULL); + if (tmpval != G_MAXUINT64) + fu_firmware_image_set_addr (self, tmpval); + tmpval = xb_node_query_text_as_uint (n, "offset", NULL); + if (tmpval != G_MAXUINT64) + fu_firmware_image_set_offset (self, tmpval); + tmp = xb_node_query_text (n, "filename", NULL); + if (tmp != NULL) { + g_autoptr(GBytes) blob = NULL; + blob = fu_common_get_contents_bytes (tmp, error); + if (blob == NULL) + return FALSE; + fu_firmware_image_set_bytes (self, blob); + fu_firmware_image_set_filename (self, tmp); + } + data = xb_node_query_first (n, "data", NULL); + if (data != NULL && xb_node_get_text (data) != NULL) { + gsize bufsz = 0; + g_autofree guchar *buf = NULL; + g_autoptr(GBytes) blob = NULL; + buf = g_base64_decode (xb_node_get_text (data), &bufsz); + blob = g_bytes_new (buf, bufsz); + fu_firmware_image_set_bytes (self, blob); + } else if (data != NULL) { + g_autoptr(GBytes) blob = NULL; + blob = g_bytes_new (NULL, 0); + fu_firmware_image_set_bytes (self, blob); + } + + /* optional chunks */ + chunks = xb_node_query (n, "chunks/chunk", 0, NULL); + if (chunks != NULL) { + for (guint i = 0; i < chunks->len; i++) { + XbNode *c = g_ptr_array_index (chunks, i); + g_autoptr(FuChunk) chk = fu_chunk_bytes_new (NULL); + fu_chunk_set_idx (chk, i); + if (!fu_chunk_build (chk, c, error)) + return FALSE; + fu_firmware_image_add_chunk (self, chk); + } + } + + /* subclassed */ + if (klass->build != NULL) { + if (!klass->build (self, n, error)) + return FALSE; + } + + /* success */ + return TRUE; +} + +/** * fu_firmware_image_write: * @self: a #FuPlugin * @error: A #GError, or %NULL @@ -215,15 +549,22 @@ if (klass->write != NULL) return klass->write (self, error); - /* fall back to what was set manually */ - if (priv->bytes == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "no bytes found in firmware bytes %s", priv->id); - return NULL; + /* set */ + if (priv->bytes != NULL) + return g_bytes_ref (priv->bytes); + + /* fall back to chunks */ + if (priv->chunks != NULL && priv->chunks->len == 1) { + FuChunk *chk = g_ptr_array_index (priv->chunks, 0); + return fu_chunk_get_bytes (chk); } - return g_bytes_ref (priv->bytes); + + /* failed */ + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "no bytes found in firmware bytes %s", priv->id); + return NULL; } /** @@ -253,6 +594,9 @@ gsize chunk_left; guint64 offset; + g_return_val_if_fail (FU_IS_FIRMWARE_IMAGE (self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + /* check address requested is larger than base address */ if (address < priv->addr) { g_set_error (error, @@ -277,11 +621,18 @@ /* if we have less data than requested */ chunk_left = g_bytes_get_size (priv->bytes) - offset; - if (chunk_sz_max > chunk_left) - return g_bytes_new_from_bytes (priv->bytes, offset, chunk_left); + if (chunk_sz_max > chunk_left) { + return fu_common_bytes_new_offset (priv->bytes, + offset, + chunk_left, + error); + } /* check chunk */ - return g_bytes_new_from_bytes (priv->bytes, offset, chunk_sz_max); + return fu_common_bytes_new_offset (priv->bytes, + offset, + chunk_sz_max, + error); } void @@ -297,13 +648,25 @@ fu_common_string_append_kx (str, idt, "Index", priv->idx); if (priv->addr != 0x0) fu_common_string_append_kx (str, idt, "Address", priv->addr); + if (priv->offset != 0x0) + fu_common_string_append_kx (str, idt, "Offset", priv->offset); if (priv->version != NULL) fu_common_string_append_kv (str, idt, "Version", priv->version); + if (priv->filename != NULL) + fu_common_string_append_kv (str, idt, "Filename", priv->filename); if (priv->bytes != NULL) { fu_common_string_append_kx (str, idt, "Data", g_bytes_get_size (priv->bytes)); } + /* add chunks */ + if (priv->chunks != NULL) { + for (guint i = 0; i < priv->chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (priv->chunks, i); + fu_chunk_add_string (chk, idt + 1, str); + } + } + /* vfunc */ if (klass->to_string != NULL) klass->to_string (self, idt, str); @@ -339,8 +702,11 @@ FuFirmwareImagePrivate *priv = GET_PRIVATE (self); g_free (priv->id); g_free (priv->version); + g_free (priv->filename); if (priv->bytes != NULL) g_bytes_unref (priv->bytes); + if (priv->chunks != NULL) + g_ptr_array_unref (priv->chunks); G_OBJECT_CLASS (fu_firmware_image_parent_class)->finalize (object); } diff -Nru fwupd-1.4.5/libfwupdplugin/fu-firmware-image.h fwupd-1.5.8/libfwupdplugin/fu-firmware-image.h --- fwupd-1.4.5/libfwupdplugin/fu-firmware-image.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-firmware-image.h 2021-03-31 20:08:32.000000000 +0000 @@ -8,6 +8,9 @@ #include #include +#include + +#include "fu-chunk.h" #define FU_TYPE_FIRMWARE_IMAGE (fu_firmware_image_get_type ()) G_DECLARE_DERIVABLE_TYPE (FuFirmwareImage, fu_firmware_image, FU, FIRMWARE_IMAGE, GObject) @@ -18,14 +21,24 @@ gboolean (*parse) (FuFirmwareImage *self, GBytes *fw, FwupdInstallFlags flags, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; void (*to_string) (FuFirmwareImage *self, guint idt, GString *str); GBytes *(*write) (FuFirmwareImage *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; + gboolean (*build) (FuFirmwareImage *self, + XbNode *n, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; + gchar *(*get_checksum)(FuFirmwareImage *self, + GChecksumType csum_kind, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; /*< private >*/ - gpointer padding[28]; + gpointer padding[26]; }; #define FU_FIRMWARE_IMAGE_ID_PAYLOAD "payload" @@ -38,20 +51,45 @@ const gchar *fu_firmware_image_get_version (FuFirmwareImage *self); void fu_firmware_image_set_version (FuFirmwareImage *self, const gchar *version); +const gchar *fu_firmware_image_get_filename (FuFirmwareImage *self); +void fu_firmware_image_set_filename (FuFirmwareImage *self, + const gchar *filename); const gchar *fu_firmware_image_get_id (FuFirmwareImage *self); void fu_firmware_image_set_id (FuFirmwareImage *self, const gchar *id); guint64 fu_firmware_image_get_addr (FuFirmwareImage *self); void fu_firmware_image_set_addr (FuFirmwareImage *self, guint64 addr); +guint64 fu_firmware_image_get_offset (FuFirmwareImage *self); +void fu_firmware_image_set_offset (FuFirmwareImage *self, + guint64 offset); guint64 fu_firmware_image_get_idx (FuFirmwareImage *self); void fu_firmware_image_set_idx (FuFirmwareImage *self, guint64 idx); +GBytes *fu_firmware_image_get_bytes (FuFirmwareImage *self); void fu_firmware_image_set_bytes (FuFirmwareImage *self, GBytes *bytes); -GBytes *fu_firmware_image_write (FuFirmwareImage *self, +void fu_firmware_image_add_chunk (FuFirmwareImage *self, + FuChunk *chk); +GPtrArray *fu_firmware_image_get_chunks (FuFirmwareImage *self, + GError **error); +gchar *fu_firmware_image_get_checksum (FuFirmwareImage *self, + GChecksumType csum_kind, GError **error); +gboolean fu_firmware_image_parse (FuFirmwareImage *self, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fu_firmware_image_build (FuFirmwareImage *self, + XbNode *n, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +GBytes *fu_firmware_image_write (FuFirmwareImage *self, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; GBytes *fu_firmware_image_write_chunk (FuFirmwareImage *self, guint64 address, guint64 chunk_sz_max, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; diff -Nru fwupd-1.4.5/libfwupdplugin/fu-fmap-firmware.c fwupd-1.5.8/libfwupdplugin/fu-fmap-firmware.c --- fwupd-1.4.5/libfwupdplugin/fu-fmap-firmware.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-fmap-firmware.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2020 Benson Leung + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" +#include "fu-fmap-firmware.h" + +#define FMAP_SIGNATURE "__FMAP__" +#define FMAP_AREANAME "FMAP" + +typedef struct { + guint64 base; + gsize offset; +} FuFmapFirmwarePrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (FuFmapFirmware, fu_fmap_firmware, FU_TYPE_FIRMWARE) +#define GET_PRIVATE(o) (fu_fmap_firmware_get_instance_private (o)) + +static gboolean +fu_fmap_firmware_find_offset (FuFmapFirmware *self, + const guint8 *buf, gsize bufsz, + GError **error) +{ +#ifdef HAVE_MEMMEM + FuFmapFirmwarePrivate *priv = GET_PRIVATE (self); + const guint8 *tmp; + + g_return_val_if_fail (buf != NULL, FALSE); + + /* trust glibc to do a binary or linear search as appropriate */ + tmp = memmem (buf, bufsz, FMAP_SIGNATURE, 8); + if (tmp == NULL) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "fmap header not found"); + return FALSE; + } + priv->offset = tmp - buf; + return TRUE; +#else + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "memmem() not available"); + return FALSE; +#endif +} + +static void +fu_fmap_firmware_to_string (FuFirmware *firmware, guint idt, GString *str) +{ + FuFmapFirmware *self = FU_FMAP_FIRMWARE (firmware); + FuFmapFirmwarePrivate *priv = GET_PRIVATE (self); + if (priv->offset > 0) + fu_common_string_append_kx (str, idt, "Offset", priv->offset); + fu_common_string_append_kx (str, idt, "Base", priv->base); +} + +static gboolean +fu_fmap_firmware_parse (FuFirmware *firmware, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error) +{ + FuFmapFirmware *self = FU_FMAP_FIRMWARE (firmware); + FuFmapFirmwarePrivate *priv = GET_PRIVATE (self); + FuFmapFirmwareClass *klass_firmware = FU_FMAP_FIRMWARE_GET_CLASS (firmware); + gsize bufsz; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + gsize offset = 0; + FuFmap fmap; + + /* corrupt */ + if (g_bytes_get_size (fw) < sizeof (FuFmap)) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "firmware too small for fmap"); + return FALSE; + } + + /* only search for the fmap signature if not fuzzing */ + if ((flags & FWUPD_INSTALL_FLAG_NO_SEARCH) == 0) { + if (!fu_fmap_firmware_find_offset (self, buf, bufsz, error)) + return FALSE; + } + + /* load header */ + if (!fu_memcpy_safe ((guint8 *) &fmap, sizeof(fmap), 0x0, /* dst */ + buf, bufsz, priv->offset, /* src */ + sizeof(fmap), error)) + return FALSE; + priv->base = GUINT64_FROM_LE (fmap.base); + + if (GUINT32_FROM_LE (fmap.size) != bufsz) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "file size incorrect, expected 0x%04x got 0x%04x", + (guint) fmap.size, + (guint) bufsz); + return FALSE; + } + if (GUINT16_FROM_LE (fmap.nareas) < 1) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "number of areas too small, got %" G_GUINT16_FORMAT, + GUINT16_FROM_LE (fmap.nareas)); + return FALSE; + } + offset = priv->offset + sizeof(fmap); + + for (gsize i = 0; i < GUINT16_FROM_LE (fmap.nareas); i++) { + FuFmapArea area; + g_autoptr(FuFirmwareImage) img = NULL; + g_autoptr(GBytes) bytes = NULL; + g_autofree gchar *area_name = NULL; + + /* load area */ + if (!fu_memcpy_safe ((guint8 *) &area, sizeof(area), 0x0, /* dst */ + buf, bufsz, offset, /* src */ + sizeof(area), error)) + return FALSE; + + /* skip */ + if (area.size == 0) + continue; + + img = fu_firmware_image_new (NULL); + bytes = fu_common_bytes_new_offset (fw, + (gsize) GUINT32_FROM_LE (area.offset), + (gsize) GUINT32_FROM_LE (area.size), + error); + if (bytes == NULL) + return FALSE; + area_name = g_strndup ((const gchar *) area.name, FU_FMAP_FIRMWARE_STRLEN); + fu_firmware_image_set_id (img, area_name); + fu_firmware_image_set_idx (img, i + 1); + fu_firmware_image_set_addr (img, GUINT32_FROM_LE (area.offset)); + fu_firmware_image_set_bytes (img, bytes); + fu_firmware_add_image (firmware, img); + + if (g_strcmp0 (area_name, FMAP_AREANAME) == 0) { + g_autofree gchar *version = NULL; + version = g_strdup_printf ("%d.%d", + fmap.ver_major, + fmap.ver_minor); + fu_firmware_image_set_version (img, version); + } + offset += sizeof(area); + } + + /* subclassed */ + if (klass_firmware->parse != NULL) { + if (!klass_firmware->parse (firmware, fw, addr_start, addr_end, flags, error)) + return FALSE; + } + + /* success */ + return TRUE; +} + +static GBytes * +fu_fmap_firmware_write (FuFirmware *firmware, GError **error) +{ + FuFmapFirmware *self = FU_FMAP_FIRMWARE (firmware); + FuFmapFirmwarePrivate *priv = GET_PRIVATE (self); + gsize total_sz; + gsize offset; + g_autoptr(GPtrArray) images = fu_firmware_get_images (firmware); + g_autoptr(GByteArray) buf = g_byte_array_new (); + FuFmap hdr = { + .signature = { FMAP_SIGNATURE }, + .ver_major = 0x1, + .ver_minor = 0x1, + .base = GUINT64_TO_LE (priv->base), + .size = 0x0, + .name = "", + .nareas = GUINT16_TO_LE (images->len), + }; + + /* pad to offset */ + if (priv->offset > 0) + fu_byte_array_set_size (buf, priv->offset); + + /* add header */ + total_sz = offset = sizeof(hdr) + (sizeof(FuFmapArea) * images->len); + for (guint i = 0; i < images->len; i++) { + FuFirmwareImage *img = g_ptr_array_index (images, i); + g_autoptr(GBytes) fw = fu_firmware_image_get_bytes (img); + total_sz += g_bytes_get_size (fw); + } + hdr.size = GUINT32_TO_LE (priv->offset + total_sz); + g_byte_array_append (buf, (const guint8 *) &hdr, sizeof(hdr)); + + /* add each area */ + for (guint i = 0; i < images->len; i++) { + FuFirmwareImage *img = g_ptr_array_index (images, i); + const gchar *id = fu_firmware_image_get_id (img); + g_autoptr(GBytes) fw = fu_firmware_image_get_bytes (img); + FuFmapArea area = { + .offset = GUINT32_TO_LE (priv->offset + offset), + .size = GUINT32_TO_LE (g_bytes_get_size (fw)), + .name = { "" }, + .flags = 0x0, + }; + if (id != NULL) + strncpy ((gchar *) area.name, id, sizeof(area.name) - 1); + g_byte_array_append (buf, (const guint8 *) &area, sizeof(area)); + offset += g_bytes_get_size (fw); + } + + /* add the images */ + for (guint i = 0; i < images->len; i++) { + FuFirmwareImage *img = g_ptr_array_index (images, i); + g_autoptr(GBytes) fw = fu_firmware_image_get_bytes (img); + g_byte_array_append (buf, + g_bytes_get_data (fw, NULL), + g_bytes_get_size (fw)); + } + + /* success */ + return g_byte_array_free_to_bytes (g_steal_pointer (&buf)); +} + +static gboolean +fu_fmap_firmware_build (FuFirmware *firmware, XbNode *n, GError **error) +{ + FuFmapFirmware *self = FU_FMAP_FIRMWARE (firmware); + FuFmapFirmwarePrivate *priv = GET_PRIVATE (self); + guint64 tmp; + + /* simple properties */ + tmp = xb_node_query_text_as_uint (n, "base", NULL); + if (tmp != G_MAXUINT64) + priv->base = tmp; + tmp = xb_node_query_text_as_uint (n, "offset", NULL); + if (tmp != G_MAXUINT64) + priv->offset = tmp; + + /* success */ + return TRUE; +} + +static void +fu_fmap_firmware_init (FuFmapFirmware *self) +{ +} + +static void +fu_fmap_firmware_class_init (FuFmapFirmwareClass *klass) +{ + FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); + klass_firmware->to_string = fu_fmap_firmware_to_string; + klass_firmware->parse = fu_fmap_firmware_parse; + klass_firmware->write = fu_fmap_firmware_write; + klass_firmware->build = fu_fmap_firmware_build; +} + +/** + * fu_fmap_firmware_new + * + * Creates a new #FuFirmware of sub type fmap + * + * Since: 1.5.0 + **/ +FuFirmware * +fu_fmap_firmware_new (void) +{ + return FU_FIRMWARE (g_object_new (FU_TYPE_FMAP_FIRMWARE, NULL)); +} diff -Nru fwupd-1.4.5/libfwupdplugin/fu-fmap-firmware.h fwupd-1.5.8/libfwupdplugin/fu-fmap-firmware.h --- fwupd-1.4.5/libfwupdplugin/fu-fmap-firmware.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-fmap-firmware.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2020 Benson Leung + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-firmware.h" + +#define FU_FMAP_FIRMWARE_STRLEN 32 /* maximum length for strings, */ + /* including null-terminator */ + +#define FU_TYPE_FMAP_FIRMWARE (fu_fmap_firmware_get_type ()) +G_DECLARE_DERIVABLE_TYPE (FuFmapFirmware, fu_fmap_firmware, FU, FMAP_FIRMWARE, FuFirmware) + +struct _FuFmapFirmwareClass +{ + FuFirmwareClass parent_class; + gboolean (*parse) (FuFirmware *self, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error); + /*< private >*/ + gpointer padding[14]; +}; + +/* mapping of volatile and static regions in firmware binary */ +typedef struct __attribute__((packed)) { + guint32 offset; /* offset relative to base */ + guint32 size; /* size in bytes */ + guint8 name[FU_FMAP_FIRMWARE_STRLEN]; /* descriptive name */ + guint16 flags; /* flags for this area */ +} FuFmapArea; + +typedef struct __attribute__((packed)) { + guint8 signature[8]; /* "__FMAP__" (0x5F5F464D41505F5F) */ + guint8 ver_major; /* major version */ + guint8 ver_minor; /* minor version */ + guint64 base; /* address of the firmware binary */ + guint32 size; /* size of firmware binary in bytes */ + guint8 name[FU_FMAP_FIRMWARE_STRLEN]; /* name of this firmware binary */ + guint16 nareas; /* number of areas described by + areas[] below */ + FuFmapArea areas[]; +} FuFmap; + +FuFirmware *fu_fmap_firmware_new (void); diff -Nru fwupd-1.4.5/libfwupdplugin/fu-fuzzer-firmware.c.in fwupd-1.5.8/libfwupdplugin/fu-fuzzer-firmware.c.in --- fwupd-1.4.5/libfwupdplugin/fu-fuzzer-firmware.c.in 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-fuzzer-firmware.c.in 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" +#include "@INCLUDE@" + +int +LLVMFuzzerTestOneInput (const guint8 *data, gsize size) +{ + g_autoptr(FuFirmware) firmware = @FIRMWARENEW@ (); + g_autoptr(GBytes) fw = g_bytes_new (data, size); + gboolean ret = fu_firmware_parse (firmware, fw, FWUPD_INSTALL_FLAG_NONE, NULL); + if (!ret && fu_firmware_has_flag (firmware, FU_FIRMWARE_FLAG_HAS_CHECKSUM)) { + ret = fu_firmware_parse (firmware, fw, + FWUPD_INSTALL_FLAG_NO_SEARCH | + FWUPD_INSTALL_FLAG_IGNORE_VID_PID | + FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM, + NULL); + } + if (ret) { + g_autofree gchar *str = fu_firmware_to_string (firmware); + g_autoptr(GBytes) fw2 = fu_firmware_write (firmware, NULL); + g_print ("%s", str); + if (fw2 != NULL) { + g_print ("[%" G_GSIZE_FORMAT " bytes]\n", + g_bytes_get_size (fw2)); + } + } + return 0; +} diff -Nru fwupd-1.4.5/libfwupdplugin/fu-fuzzer-main.c fwupd-1.5.8/libfwupdplugin/fu-fuzzer-main.c --- fwupd-1.4.5/libfwupdplugin/fu-fuzzer-main.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-fuzzer-main.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include + +__attribute__((weak)) extern int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size); +__attribute__((weak)) extern int LLVMFuzzerInitialize(int *argc, char ***argv); + +int +main (int argc, char **argv) +{ + g_assert (LLVMFuzzerTestOneInput != NULL); + if (LLVMFuzzerInitialize != NULL) + LLVMFuzzerInitialize (&argc, &argv); + for (int i = 1; i < argc; i++) { + gsize bufsz = 0; + g_autofree gchar *buf = NULL; + g_autoptr(GError) error = NULL; + g_printerr ("Running: %s\n", argv[i]); + if (!g_file_get_contents (argv[i], &buf, &bufsz, &error)) { + g_printerr ("Failed to load: %s\n", error->message); + continue; + } + LLVMFuzzerTestOneInput ((const guint8 *)buf, bufsz); + g_printerr ("Done\n"); + } +} diff -Nru fwupd-1.4.5/libfwupdplugin/fu-hid-device.c fwupd-1.5.8/libfwupdplugin/fu-hid-device.c --- fwupd-1.4.5/libfwupdplugin/fu-hid-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-hid-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2020 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -17,6 +17,8 @@ #define FU_HID_REPORT_TYPE_OUTPUT 0x02 #define FU_HID_REPORT_TYPE_FEATURE 0x03 +#define FU_HID_DEVICE_RETRIES 10 + /** * SECTION:fu-hid-device * @short_description: a HID device @@ -31,6 +33,7 @@ FuUsbDevice *usb_device; guint8 interface; gboolean interface_autodetect; + FuHidDeviceFlags flags; } FuHidDevicePrivate; G_DEFINE_TYPE_WITH_PRIVATE (FuHidDevice, fu_hid_device, FU_TYPE_USB_DEVICE) @@ -75,12 +78,18 @@ } static gboolean -fu_hid_device_open (FuUsbDevice *device, GError **error) +fu_hid_device_open (FuDevice *device, GError **error) { FuHidDevice *self = FU_HID_DEVICE (device); FuHidDeviceClass *klass = FU_HID_DEVICE_GET_CLASS (device); +#ifdef HAVE_GUSB FuHidDevicePrivate *priv = GET_PRIVATE (self); - GUsbDevice *usb_device = fu_usb_device_get_dev (device); + GUsbDeviceClaimInterfaceFlags flags = 0; + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + + /* FuUsbDevice->open */ + if (!FU_DEVICE_CLASS (fu_hid_device_parent_class)->open (device, error)) + return FALSE; /* auto-detect */ if (priv->interface_autodetect) { @@ -107,15 +116,17 @@ } /* claim */ - if (!g_usb_device_claim_interface (usb_device, priv->interface, - G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, - error)) { + if ((priv->flags & FU_HID_DEVICE_FLAG_NO_KERNEL_UNBIND) == 0) + flags |= G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER; + if (!g_usb_device_claim_interface (usb_device, priv->interface, flags, error)) { g_prefix_error (error, "failed to claim HID interface: "); return FALSE; } +#endif /* subclassed */ if (klass->open != NULL) { + g_warning ("FuHidDevice->open is deprecated!"); if (!klass->open (self, error)) return FALSE; } @@ -125,29 +136,47 @@ } static gboolean -fu_hid_device_close (FuUsbDevice *device, GError **error) +fu_hid_device_close (FuDevice *device, GError **error) { FuHidDevice *self = FU_HID_DEVICE (device); FuHidDeviceClass *klass = FU_HID_DEVICE_GET_CLASS (device); +#ifdef HAVE_GUSB FuHidDevicePrivate *priv = GET_PRIVATE (self); - GUsbDevice *usb_device = fu_usb_device_get_dev (device); + GUsbDeviceClaimInterfaceFlags flags = 0; + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + g_autoptr(GError) error_local = NULL; +#endif /* subclassed */ if (klass->close != NULL) { + g_warning ("FuHidDevice->close is deprecated!"); if (!klass->close (self, error)) return FALSE; } +#ifdef HAVE_GUSB /* release */ - if (!g_usb_device_release_interface (usb_device, priv->interface, - G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, - error)) { - g_prefix_error (error, "failed to release HID interface: "); + if ((priv->flags & FU_HID_DEVICE_FLAG_NO_KERNEL_REBIND) == 0) + flags |= G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER; + if (!g_usb_device_release_interface (usb_device, priv->interface, flags, &error_local)) { + if (g_error_matches (error_local, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_NO_DEVICE) || + g_error_matches (error_local, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_INTERNAL)) { + g_debug ("ignoring: %s", error_local->message); + return TRUE; + } + g_propagate_prefixed_error (error, + g_steal_pointer (&error_local), + "failed to release HID interface: "); return FALSE; } +#endif - /* success */ - return TRUE; + /* FuUsbDevice->close */ + return FU_DEVICE_CLASS (fu_hid_device_parent_class)->close (device, error); } /** @@ -191,45 +220,52 @@ } /** - * fu_hid_device_set_report: + * fu_hid_device_add_flag: * @self: A #FuHidDevice - * @value: low byte of wValue - * @buf: (nullable): a mutable buffer of data to send - * @bufsz: Size of @buf - * @timeout: timeout in ms - * @flags: #FuHidDeviceFlags e.g. %FU_HID_DEVICE_FLAG_ALLOW_TRUNC - * @error: a #GError or %NULL + * @flag: #FuHidDeviceFlags, e.g. %FU_HID_DEVICE_FLAG_RETRY_FAILURE * - * Calls SetReport on the hardware. + * Adds a flag to be used for all set and get report messages. * - * Returns: %TRUE for success - * - * Since: 1.4.0 + * Since: 1.5.2 **/ -gboolean -fu_hid_device_set_report (FuHidDevice *self, - guint8 value, - guint8 *buf, - gsize bufsz, - guint timeout, - FuHidDeviceFlags flags, - GError **error) +void +fu_hid_device_add_flag (FuHidDevice *self, FuHidDeviceFlags flag) +{ + FuHidDevicePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_HID_DEVICE (self)); + priv->flags |= flag; +} + +typedef struct { + guint8 value; + guint8 *buf; + gsize bufsz; + guint timeout; + FuHidDeviceFlags flags; +} FuHidDeviceRetryHelper; + +static gboolean +fu_hid_device_set_report_internal (FuHidDevice *self, + FuHidDeviceRetryHelper *helper, + GError **error) { +#ifdef HAVE_GUSB FuHidDevicePrivate *priv = GET_PRIVATE (self); GUsbDevice *usb_device; gsize actual_len = 0; - guint16 wvalue = (FU_HID_REPORT_TYPE_OUTPUT << 8) | value; + guint16 wvalue = (FU_HID_REPORT_TYPE_OUTPUT << 8) | helper->value; /* special case */ - if (flags & FU_HID_DEVICE_FLAG_IS_FEATURE) - wvalue = (FU_HID_REPORT_TYPE_FEATURE << 8) | value; - - g_return_val_if_fail (FU_HID_DEVICE (self), FALSE); - g_return_val_if_fail (buf != NULL, FALSE); - g_return_val_if_fail (bufsz != 0, FALSE); + if (helper->flags & FU_HID_DEVICE_FLAG_IS_FEATURE) + wvalue = (FU_HID_REPORT_TYPE_FEATURE << 8) | helper->value; - if (g_getenv ("FU_HID_DEVICE_VERBOSE") != NULL) - fu_common_dump_raw (G_LOG_DOMAIN, "HID::SetReport", buf, bufsz); + if (g_getenv ("FU_HID_DEVICE_VERBOSE") != NULL) { + g_autofree gchar *title = NULL; + title = g_strdup_printf ("HID::SetReport [wValue=0x%04x ,wIndex=%u]", + wvalue, priv->interface); + fu_common_dump_raw (G_LOG_DOMAIN, title, + helper->buf, helper->bufsz); + } usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); if (!g_usb_device_control_transfer (usb_device, G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, @@ -237,24 +273,33 @@ G_USB_DEVICE_RECIPIENT_INTERFACE, FU_HID_REPORT_SET, wvalue, priv->interface, - buf, bufsz, + helper->buf, helper->bufsz, &actual_len, - timeout, + helper->timeout, NULL, error)) { g_prefix_error (error, "failed to SetReport: "); return FALSE; } - if ((flags & FU_HID_DEVICE_FLAG_ALLOW_TRUNC) == 0 && actual_len != bufsz) { + if ((helper->flags & FU_HID_DEVICE_FLAG_ALLOW_TRUNC) == 0 && actual_len != helper->bufsz) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "wrote %" G_GSIZE_FORMAT ", requested %" G_GSIZE_FORMAT " bytes", - actual_len, bufsz); + actual_len, helper->bufsz); return FALSE; } +#endif return TRUE; } +static gboolean +fu_hid_device_set_report_internal_cb (FuDevice *device, gpointer user_data, GError **error) +{ + FuHidDevice *self = FU_HID_DEVICE (device); + FuHidDeviceRetryHelper *helper = (FuHidDeviceRetryHelper *) user_data; + return fu_hid_device_set_report_internal (self, helper, error); +} + /** - * fu_hid_device_get_report: + * fu_hid_device_set_report: * @self: A #FuHidDevice * @value: low byte of wValue * @buf: (nullable): a mutable buffer of data to send @@ -263,14 +308,14 @@ * @flags: #FuHidDeviceFlags e.g. %FU_HID_DEVICE_FLAG_ALLOW_TRUNC * @error: a #GError or %NULL * - * Calls GetReport on the hardware. + * Calls SetReport on the hardware. * * Returns: %TRUE for success * * Since: 1.4.0 **/ gboolean -fu_hid_device_get_report (FuHidDevice *self, +fu_hid_device_set_report (FuHidDevice *self, guint8 value, guint8 *buf, gsize bufsz, @@ -278,21 +323,56 @@ FuHidDeviceFlags flags, GError **error) { + FuHidDeviceRetryHelper helper; FuHidDevicePrivate *priv = GET_PRIVATE (self); - GUsbDevice *usb_device; - gsize actual_len = 0; - guint16 wvalue = (FU_HID_REPORT_TYPE_INPUT << 8) | value; g_return_val_if_fail (FU_HID_DEVICE (self), FALSE); g_return_val_if_fail (buf != NULL, FALSE); g_return_val_if_fail (bufsz != 0, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* create helper */ + helper.value = value; + helper.buf = buf; + helper.bufsz = bufsz; + helper.timeout = timeout; + helper.flags = priv->flags | flags; /* special case */ - if (flags & FU_HID_DEVICE_FLAG_IS_FEATURE) - wvalue = (FU_HID_REPORT_TYPE_FEATURE << 8) | value; + if (flags & FU_HID_DEVICE_FLAG_RETRY_FAILURE) { + return fu_device_retry (FU_DEVICE (self), + fu_hid_device_set_report_internal_cb, + FU_HID_DEVICE_RETRIES, + &helper, + error); + } - if (g_getenv ("FU_HID_DEVICE_VERBOSE") != NULL) - fu_common_dump_raw (G_LOG_DOMAIN, "HID::GetReport", buf, actual_len); + /* just one */ + return fu_hid_device_set_report_internal (self, &helper, error); +} + +static gboolean +fu_hid_device_get_report_internal (FuHidDevice *self, + FuHidDeviceRetryHelper *helper, + GError **error) +{ +#ifdef HAVE_GUSB + FuHidDevicePrivate *priv = GET_PRIVATE (self); + GUsbDevice *usb_device; + gsize actual_len = 0; + guint16 wvalue = (FU_HID_REPORT_TYPE_INPUT << 8) | helper->value; + + /* special case */ + if (helper->flags & FU_HID_DEVICE_FLAG_IS_FEATURE) + wvalue = (FU_HID_REPORT_TYPE_FEATURE << 8) | helper->value; + + if (g_getenv ("FU_HID_DEVICE_VERBOSE") != NULL) { + g_autofree gchar *title = NULL; + title = g_strdup_printf ("HID::GetReport [wValue=0x%04x, wIndex=%u]", + wvalue, priv->interface); + fu_common_dump_raw (G_LOG_DOMAIN, title, + helper->buf, actual_len); + } usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); if (!g_usb_device_control_transfer (usb_device, G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, @@ -300,24 +380,90 @@ G_USB_DEVICE_RECIPIENT_INTERFACE, FU_HID_REPORT_GET, wvalue, priv->interface, - buf, bufsz, + helper->buf, helper->bufsz, &actual_len, /* actual length */ - timeout, + helper->timeout, NULL, error)) { g_prefix_error (error, "failed to GetReport: "); return FALSE; } - if (g_getenv ("FU_HID_DEVICE_VERBOSE") != NULL) - fu_common_dump_raw (G_LOG_DOMAIN, "HID::GetReport", buf, actual_len); - if ((flags & FU_HID_DEVICE_FLAG_ALLOW_TRUNC) == 0 && actual_len != bufsz) { + if (g_getenv ("FU_HID_DEVICE_VERBOSE") != NULL) { + g_autofree gchar *title = NULL; + title = g_strdup_printf ("HID::GetReport [wValue=0x%04x, wIndex=%u]", + wvalue, priv->interface); + fu_common_dump_raw (G_LOG_DOMAIN, title, helper->buf, actual_len); + } + if ((helper->flags & FU_HID_DEVICE_FLAG_ALLOW_TRUNC) == 0 && actual_len != helper->bufsz) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "read %" G_GSIZE_FORMAT ", requested %" G_GSIZE_FORMAT " bytes", - actual_len, bufsz); + actual_len, helper->bufsz); return FALSE; } +#endif return TRUE; } +static gboolean +fu_hid_device_get_report_internal_cb (FuDevice *device, gpointer user_data, GError **error) +{ + FuHidDevice *self = FU_HID_DEVICE (device); + FuHidDeviceRetryHelper *helper = (FuHidDeviceRetryHelper *) user_data; + return fu_hid_device_get_report_internal (self, helper, error); +} + +/** + * fu_hid_device_get_report: + * @self: A #FuHidDevice + * @value: low byte of wValue + * @buf: (nullable): a mutable buffer of data to send + * @bufsz: Size of @buf + * @timeout: timeout in ms + * @flags: #FuHidDeviceFlags e.g. %FU_HID_DEVICE_FLAG_ALLOW_TRUNC + * @error: a #GError or %NULL + * + * Calls GetReport on the hardware. + * + * Returns: %TRUE for success + * + * Since: 1.4.0 + **/ +gboolean +fu_hid_device_get_report (FuHidDevice *self, + guint8 value, + guint8 *buf, + gsize bufsz, + guint timeout, + FuHidDeviceFlags flags, + GError **error) +{ + FuHidDeviceRetryHelper helper; + FuHidDevicePrivate *priv = GET_PRIVATE (self); + + g_return_val_if_fail (FU_HID_DEVICE (self), FALSE); + g_return_val_if_fail (buf != NULL, FALSE); + g_return_val_if_fail (bufsz != 0, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* create helper */ + helper.value = value; + helper.buf = buf; + helper.bufsz = bufsz; + helper.timeout = timeout; + helper.flags = priv->flags | flags; + + /* special case */ + if (flags & FU_HID_DEVICE_FLAG_RETRY_FAILURE) { + return fu_device_retry (FU_DEVICE (self), + fu_hid_device_get_report_internal_cb, + FU_HID_DEVICE_RETRIES, + &helper, + error); + } + + /* just one */ + return fu_hid_device_get_report_internal (self, &helper, error); +} + static void fu_hid_device_init (FuHidDevice *self) { @@ -346,14 +492,14 @@ static void fu_hid_device_class_init (FuHidDeviceClass *klass) { - FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass); GParamSpec *pspec; object_class->get_property = fu_hid_device_get_property; object_class->set_property = fu_hid_device_set_property; - klass_usb_device->open = fu_hid_device_open; - klass_usb_device->close = fu_hid_device_close; + klass_device->open = fu_hid_device_open; + klass_device->close = fu_hid_device_close; pspec = g_param_spec_uint ("interface", NULL, NULL, 0x00, 0xff, 0x00, diff -Nru fwupd-1.4.5/libfwupdplugin/fu-hid-device.h fwupd-1.5.8/libfwupdplugin/fu-hid-device.h --- fwupd-1.4.5/libfwupdplugin/fu-hid-device.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-hid-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2020 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -28,6 +28,9 @@ * @FU_HID_DEVICE_FLAG_NONE: No flags set * @FU_HID_DEVICE_FLAG_ALLOW_TRUNC: Allow truncated reads and writes * @FU_HID_DEVICE_FLAG_IS_FEATURE: Use %FU_HID_REPORT_TYPE_FEATURE for wValue + * @FU_HID_DEVICE_FLAG_RETRY_FAILURE: Retry up to 10 times on failure + * @FU_HID_DEVICE_FLAG_NO_KERNEL_UNBIND: Do not unbind the kernel driver on open + * @FU_HID_DEVICE_FLAG_NO_KERNEL_REBIND: Do not rebind the kernel driver on close * * Flags used when calling fu_hid_device_get_report() and fu_hid_device_set_report(). **/ @@ -35,10 +38,16 @@ FU_HID_DEVICE_FLAG_NONE = 0, FU_HID_DEVICE_FLAG_ALLOW_TRUNC = 1 << 0, FU_HID_DEVICE_FLAG_IS_FEATURE = 1 << 1, + FU_HID_DEVICE_FLAG_RETRY_FAILURE = 1 << 2, + FU_HID_DEVICE_FLAG_NO_KERNEL_UNBIND = 1 << 3, + FU_HID_DEVICE_FLAG_NO_KERNEL_REBIND = 1 << 4, + /*< private >*/ FU_HID_DEVICE_FLAG_LAST } FuHidDeviceFlags; FuHidDevice *fu_hid_device_new (GUsbDevice *usb_device); +void fu_hid_device_add_flag (FuHidDevice *self, + FuHidDeviceFlags flag); void fu_hid_device_set_interface (FuHidDevice *self, guint8 interface); guint8 fu_hid_device_get_interface (FuHidDevice *self); @@ -48,11 +57,13 @@ gsize bufsz, guint timeout, FuHidDeviceFlags flags, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_hid_device_get_report (FuHidDevice *self, guint8 value, guint8 *buf, gsize bufsz, guint timeout, FuHidDeviceFlags flags, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; diff -Nru fwupd-1.4.5/libfwupdplugin/fu-hwids.c fwupd-1.5.8/libfwupdplugin/fu-hwids.c --- fwupd-1.4.5/libfwupdplugin/fu-hwids.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-hwids.c 2021-03-31 20:08:32.000000000 +0000 @@ -21,6 +21,7 @@ GObject parent_instance; GHashTable *hash_dmi_hw; /* BiosVersion->"1.2.3 " */ GHashTable *hash_dmi_display; /* BiosVersion->"1.2.3" */ + GHashTable *hash_smbios_override; /* BiosVersion->"1.2.3" */ GHashTable *hash_guid; /* a-c-b-d->1 */ GPtrArray *array_guids; /* a-c-b-d */ }; @@ -78,6 +79,39 @@ return self->array_guids; } +/** + * fu_hwids_get_keys: + * @self: A #FuHwids + * + * Returns all the defined HWID keys. + * + * Returns: (transfer container) (element-type utf8): All the known keys, + * e.g. %FU_HWIDS_KEY_FAMILY + * + * Since: 1.5.6 + **/ +GPtrArray * +fu_hwids_get_keys (FuHwids *self) +{ + GPtrArray *array = g_ptr_array_new (); + const gchar *keys[] = { + FU_HWIDS_KEY_BIOS_VENDOR, + FU_HWIDS_KEY_BIOS_VERSION, + FU_HWIDS_KEY_BIOS_MAJOR_RELEASE, + FU_HWIDS_KEY_BIOS_MINOR_RELEASE, + FU_HWIDS_KEY_MANUFACTURER, + FU_HWIDS_KEY_FAMILY, + FU_HWIDS_KEY_PRODUCT_NAME, + FU_HWIDS_KEY_PRODUCT_SKU, + FU_HWIDS_KEY_ENCLOSURE_KIND, + FU_HWIDS_KEY_BASEBOARD_MANUFACTURER, + FU_HWIDS_KEY_BASEBOARD_PRODUCT, + NULL }; + for (guint i = 0; keys[i] != NULL; i++) + g_ptr_array_add (array, (gpointer) keys[i]); + return array; +} + static gchar * fu_hwids_get_guid_for_str (const gchar *str, GError **error) { @@ -197,6 +231,26 @@ } /** + * fu_hwids_add_smbios_override: + * @self: A #FuHwids + * @key: A key, e.g. %FU_HWIDS_KEY_PRODUCT_SKU + * @value: (nullable): A new value, e.g. "ExampleModel" or %NULL + * + * Sets SMBIOS override values so you can emulate another system. + * + * This function has no effect if called after fu_hwids_setup() + * + * Since: 1.5.6 + **/ +void +fu_hwids_add_smbios_override (FuHwids *self, const gchar *key, const gchar *value) +{ + g_return_if_fail (FU_IS_HWIDS (self)); + g_return_if_fail (key != NULL); + g_hash_table_insert (self->hash_smbios_override, g_strdup (key), g_strdup (value)); +} + +/** * fu_hwids_get_replace_values: * @self: A #FuHwids * @keys: A key, e.g. `HardwareID-3` or %FU_HWIDS_KEY_PRODUCT_SKU @@ -214,6 +268,10 @@ g_auto(GStrv) split = NULL; g_autoptr(GString) str = g_string_new (NULL); + g_return_val_if_fail (FU_IS_HWIDS (self), NULL); + g_return_val_if_fail (keys != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + /* do any replacements */ keys = fu_hwids_get_replace_keys (self, keys); @@ -251,7 +309,13 @@ gchar * fu_hwids_get_guid (FuHwids *self, const gchar *keys, GError **error) { - g_autofree gchar *tmp = fu_hwids_get_replace_values (self, keys, error); + g_autofree gchar *tmp = NULL; + + g_return_val_if_fail (FU_IS_HWIDS (self), NULL); + g_return_val_if_fail (keys != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + tmp = fu_hwids_get_replace_values (self, keys, error); if (tmp == NULL) return NULL; return fu_hwids_get_guid_for_str (tmp, error); @@ -280,21 +344,10 @@ guint8 type, guint8 offset, GError **error) { - g_autoptr(GBytes) data = NULL; - const guint8 *data_raw; - gsize data_sz = 0; - data = fu_smbios_get_data (smbios, type, error); - if (data == NULL) + guint tmp = fu_smbios_get_integer (smbios, type, offset, error); + if (tmp == G_MAXUINT) return NULL; - data_raw = g_bytes_get_data (data, &data_sz); - if (offset >= data_sz) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "offset bigger than data"); - return NULL; - } - return g_strdup_printf ("%02x", data_raw[offset]); + return g_strdup_printf ("%02x", tmp); } static gchar * @@ -302,27 +355,16 @@ guint8 type, guint8 offset, GError **error) { - g_autoptr(GBytes) data = NULL; - const guint8 *data_raw; - gsize data_sz = 0; - data = fu_smbios_get_data (smbios, type, error); - if (data == NULL) - return NULL; - data_raw = g_bytes_get_data (data, &data_sz); - if (offset >= data_sz) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "offset bigger than data"); + guint tmp = fu_smbios_get_integer (smbios, type, offset, error); + if (tmp == G_MAXUINT) return NULL; - } - return g_strdup_printf ("%x", data_raw[offset]); + return g_strdup_printf ("%x", tmp); } /** * fu_hwids_setup: * @self: A #FuHwids - * @smbios: A #FuSmbios + * @smbios: (nullable): A #FuSmbios or %NULL * @error: A #GError or %NULL * * Reads all the SMBIOS values from the hardware. @@ -366,25 +408,39 @@ }; g_return_val_if_fail (FU_IS_HWIDS (self), FALSE); - g_return_val_if_fail (FU_IS_SMBIOS (smbios), FALSE); + g_return_val_if_fail (FU_IS_SMBIOS (smbios) || smbios == NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* get all DMI data */ for (guint i = 0; map[i].key != NULL; i++) { - const gchar *contents_hdr; + const gchar *contents_hdr = NULL; g_autofree gchar *contents = NULL; g_autofree gchar *contents_safe = NULL; g_autoptr(GError) error_local = NULL; - /* get the data from a SMBIOS table */ - contents = map[i].func (smbios, map[i].type, map[i].offset, &error_local); - if (contents == NULL) { - g_debug ("ignoring %s: %s", map[i].key, error_local->message); + /* get the data from a SMBIOS table unless an override exists */ + if (g_hash_table_lookup_extended (self->hash_smbios_override, + map[i].key, NULL, + (gpointer *) &contents_hdr)) { + if (contents_hdr == NULL) { + g_debug ("ignoring %s", map[i].key); + continue; + } + } else if (smbios != NULL) { + contents = map[i].func (smbios, map[i].type, + map[i].offset, &error_local); + if (contents == NULL) { + g_debug ("ignoring %s: %s", map[i].key, error_local->message); + continue; + } + contents_hdr = contents; + } else { + g_debug ("ignoring %s", map[i].key); continue; } - g_debug ("smbios property %s=%s", map[i].key, contents); + g_debug ("smbios property %s=%s", map[i].key, contents_hdr); /* weirdly, remove leading zeros */ - contents_hdr = contents; while (contents_hdr[0] == '0' && map[i].func != fu_hwids_convert_padded_integer_cb) contents_hdr++; @@ -432,6 +488,7 @@ g_hash_table_unref (self->hash_dmi_hw); g_hash_table_unref (self->hash_dmi_display); + g_hash_table_unref (self->hash_smbios_override); g_hash_table_unref (self->hash_guid); g_ptr_array_unref (self->array_guids); @@ -450,6 +507,7 @@ { self->hash_dmi_hw = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); self->hash_dmi_display = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + self->hash_smbios_override = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); self->hash_guid = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); self->array_guids = g_ptr_array_new_with_free_func (g_free); } diff -Nru fwupd-1.4.5/libfwupdplugin/fu-hwids.h fwupd-1.5.8/libfwupdplugin/fu-hwids.h --- fwupd-1.4.5/libfwupdplugin/fu-hwids.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-hwids.h 2021-03-31 20:08:32.000000000 +0000 @@ -27,20 +27,26 @@ #define FU_HWIDS_KEY_PRODUCT_SKU "ProductSku" FuHwids *fu_hwids_new (void); - +GPtrArray *fu_hwids_get_keys (FuHwids *self); const gchar *fu_hwids_get_value (FuHwids *self, const gchar *key); +void fu_hwids_add_smbios_override (FuHwids *self, + const gchar *key, + const gchar *value); const gchar *fu_hwids_get_replace_keys (FuHwids *self, const gchar *key); gchar *fu_hwids_get_replace_values (FuHwids *self, const gchar *keys, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gchar *fu_hwids_get_guid (FuHwids *self, const gchar *keys, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; GPtrArray *fu_hwids_get_guids (FuHwids *self); gboolean fu_hwids_has_guid (FuHwids *self, const gchar *guid); gboolean fu_hwids_setup (FuHwids *self, FuSmbios *smbios, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; diff -Nru fwupd-1.4.5/libfwupdplugin/fu-ihex-firmware.c fwupd-1.5.8/libfwupdplugin/fu-ihex-firmware.c --- fwupd-1.4.5/libfwupdplugin/fu-ihex-firmware.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-ihex-firmware.c 2021-03-31 20:08:32.000000000 +0000 @@ -30,14 +30,6 @@ G_DEFINE_TYPE (FuIhexFirmware, fu_ihex_firmware, FU_TYPE_FIRMWARE) -#define DFU_INHX32_RECORD_TYPE_DATA 0x00 -#define DFU_INHX32_RECORD_TYPE_EOF 0x01 -#define DFU_INHX32_RECORD_TYPE_EXTENDED_SEGMENT 0x02 -#define DFU_INHX32_RECORD_TYPE_START_SEGMENT 0x03 -#define DFU_INHX32_RECORD_TYPE_EXTENDED_LINEAR 0x04 -#define DFU_INHX32_RECORD_TYPE_START_LINEAR 0x05 -#define DFU_INHX32_RECORD_TYPE_SIGNATURE 0xfd - /** * fu_ihex_firmware_get_records: * @self: A #FuIhexFirmware @@ -62,36 +54,108 @@ fu_ihex_firmware_record_free (FuIhexFirmwareRecord *rcd) { g_string_free (rcd->buf, TRUE); + g_byte_array_unref (rcd->data); g_free (rcd); } G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuIhexFirmwareRecord, fu_ihex_firmware_record_free) static FuIhexFirmwareRecord * -fu_ihex_firmware_record_new (guint ln, const gchar *buf) +fu_ihex_firmware_record_new (guint ln, const gchar *line, + FwupdInstallFlags flags, GError **error) { - FuIhexFirmwareRecord *rcd = g_new0 (FuIhexFirmwareRecord, 1); + g_autoptr(FuIhexFirmwareRecord) rcd = NULL; + gsize linesz = strlen (line); + guint line_end; + guint16 addr16 = 0; + + /* check starting token */ + if (line[0] != ':') { + g_autofree gchar *strsafe = fu_common_strsafe (line, 5); + if (strsafe != NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "invalid starting token: %s", + strsafe); + return NULL; + } + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "invalid starting token"); + return NULL; + } + + /* length, 16-bit address, type */ + rcd = g_new0 (FuIhexFirmwareRecord, 1); rcd->ln = ln; - rcd->buf = g_string_new (buf); - return rcd; + rcd->data = g_byte_array_new (); + rcd->buf = g_string_new (line); + if (!fu_firmware_strparse_uint8_safe (line, linesz, 1, &rcd->byte_cnt, error)) + return NULL; + if (!fu_firmware_strparse_uint16_safe (line, linesz, 3, &addr16, error)) + return NULL; + rcd->addr = addr16; + if (!fu_firmware_strparse_uint8_safe (line, linesz, 7, &rcd->record_type, error)) + return NULL; + + /* position of checksum */ + line_end = 9 + rcd->byte_cnt * 2; + if (line_end > (guint) rcd->buf->len) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "line malformed, length: %u", + line_end); + return NULL; + } + + /* verify checksum */ + if ((flags & FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM) == 0) { + guint8 checksum = 0; + for (guint i = 1; i < line_end + 2; i += 2) { + guint8 data_tmp = 0; + if (!fu_firmware_strparse_uint8_safe (line, linesz, i, &data_tmp, error)) + return NULL; + checksum += data_tmp; + } + if (checksum != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "invalid checksum (0x%02x)", + checksum); + return NULL; + } + } + + /* add data */ + for (guint i = 9; i < line_end; i += 2) { + guint8 tmp_c = 0; + if (!fu_firmware_strparse_uint8_safe (line, linesz, i, &tmp_c, error)) + return NULL; + fu_byte_array_append_uint8 (rcd->data, tmp_c); + } + return g_steal_pointer (&rcd); } static const gchar * fu_ihex_firmware_record_type_to_string (guint8 record_type) { - if (record_type == DFU_INHX32_RECORD_TYPE_DATA) + if (record_type == FU_IHEX_FIRMWARE_RECORD_TYPE_DATA) return "DATA"; - if (record_type == DFU_INHX32_RECORD_TYPE_EOF) + if (record_type == FU_IHEX_FIRMWARE_RECORD_TYPE_EOF) return "EOF"; - if (record_type == DFU_INHX32_RECORD_TYPE_EXTENDED_SEGMENT) + if (record_type == FU_IHEX_FIRMWARE_RECORD_TYPE_EXTENDED_SEGMENT) return "EXTENDED_SEGMENT"; - if (record_type == DFU_INHX32_RECORD_TYPE_START_SEGMENT) + if (record_type == FU_IHEX_FIRMWARE_RECORD_TYPE_START_SEGMENT) return "START_SEGMENT"; - if (record_type == DFU_INHX32_RECORD_TYPE_EXTENDED_LINEAR) + if (record_type == FU_IHEX_FIRMWARE_RECORD_TYPE_EXTENDED_LINEAR) return "EXTENDED_LINEAR"; - if (record_type == DFU_INHX32_RECORD_TYPE_START_LINEAR) + if (record_type == FU_IHEX_FIRMWARE_RECORD_TYPE_START_LINEAR) return "ADDR32"; - if (record_type == DFU_INHX32_RECORD_TYPE_SIGNATURE) + if (record_type == FU_IHEX_FIRMWARE_RECORD_TYPE_SIGNATURE) return "SIGNATURE"; return NULL; } @@ -108,9 +172,15 @@ for (guint ln = 0; lines[ln] != NULL; ln++) { g_autoptr(FuIhexFirmwareRecord) rcd = NULL; g_strdelimit (lines[ln], "\r\x1a", '\0'); + if (g_str_has_prefix (lines[ln], ";")) + continue; if (lines[ln][0] == '\0') continue; - rcd = fu_ihex_firmware_record_new (ln + 1, lines[ln]); + rcd = fu_ihex_firmware_record_new (ln + 1, lines[ln], flags, error); + if (rcd == NULL) { + g_prefix_error (error, "invalid line %u: ", ln + 1); + return FALSE; + } g_ptr_array_add (self->records, g_steal_pointer (&rcd)); } return TRUE; @@ -126,6 +196,7 @@ { FuIhexFirmware *self = FU_IHEX_FIRMWARE (firmware); gboolean got_eof = FALSE; + gboolean got_sig = FALSE; guint32 abs_addr = 0x0; guint32 addr_last = 0x0; guint32 img_addr = G_MAXUINT32; @@ -133,87 +204,31 @@ g_autoptr(FuFirmwareImage) img = fu_firmware_image_new (NULL); g_autoptr(GBytes) img_bytes = NULL; g_autoptr(GByteArray) buf = g_byte_array_new (); - g_autoptr(GByteArray) buf_signature = g_byte_array_new (); /* parse records */ for (guint k = 0; k < self->records->len; k++) { FuIhexFirmwareRecord *rcd = g_ptr_array_index (self->records, k); - const gchar *line = rcd->buf->str; - guint32 addr; - guint8 byte_cnt; - guint8 record_type; - guint line_end; - - /* ignore comments */ - if (g_str_has_prefix (line, ";")) - continue; + guint16 addr16 = 0; + guint32 addr = rcd->addr + seg_addr + abs_addr; + guint32 len_hole; - /* ignore blank lines */ - if (rcd->buf->len == 0) - continue; - - /* check starting token */ - if (line[0] != ':') { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "invalid starting token on line %u: %s", - rcd->ln, line); - return FALSE; - } - - /* check there's enough data for the smallest possible record */ - if (rcd->buf->len < 11) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "line %u is incomplete, length %u", - rcd->ln, (guint) rcd->buf->len); - return FALSE; - } - - /* length, 16-bit address, type */ - byte_cnt = fu_firmware_strparse_uint8 (line + 1); - addr = fu_firmware_strparse_uint16 (line + 3); - record_type = fu_firmware_strparse_uint8 (line + 7); - g_debug ("%s:", fu_ihex_firmware_record_type_to_string (record_type)); - g_debug (" addr_start:\t0x%04x", addr); - g_debug (" length:\t0x%02x", byte_cnt); - addr += seg_addr; - addr += abs_addr; + g_debug ("%s:", fu_ihex_firmware_record_type_to_string (rcd->record_type)); + g_debug (" length:\t0x%02x", rcd->data->len); g_debug (" addr:\t0x%08x", addr); - /* position of checksum */ - line_end = 9 + byte_cnt * 2; - if (line_end > (guint) rcd->buf->len) { + /* sanity check */ + if (rcd->record_type != FU_IHEX_FIRMWARE_RECORD_TYPE_EOF && + rcd->data->len == 0) { g_set_error (error, FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "line %u malformed, length: %u", - rcd->ln, line_end); + FWUPD_ERROR_NOT_SUPPORTED, + "record 0x%x had zero size", k); return FALSE; } - /* verify checksum */ - if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { - guint8 checksum = 0; - for (guint i = 1; i < line_end + 2; i += 2) { - guint8 data_tmp = fu_firmware_strparse_uint8 (line + i); - checksum += data_tmp; - } - if (checksum != 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "line %u has invalid checksum (0x%02x)", - rcd->ln, checksum); - return FALSE; - } - } - /* process different record types */ - switch (record_type) { - case DFU_INHX32_RECORD_TYPE_DATA: + switch (rcd->record_type) { + case FU_IHEX_FIRMWARE_RECORD_TYPE_DATA: /* base address for element */ if (img_addr == G_MAXUINT32) img_addr = addr; @@ -230,37 +245,32 @@ return FALSE; } - /* parse bytes from line */ - g_debug ("writing data 0x%08x", (guint32) addr); - for (guint i = 9; i < line_end; i += 2) { - /* any holes in the hex record */ - guint32 len_hole = addr - addr_last; - guint8 data_tmp; - if (addr_last > 0 && len_hole > 0x100000) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "hole of 0x%x bytes too large to fill on line %u", - (guint) len_hole, - rcd->ln); - return FALSE; - } - if (addr_last > 0x0 && len_hole > 1) { - g_debug ("filling address 0x%08x to 0x%08x on line %u", - addr_last + 1, addr_last + len_hole - 1, rcd->ln); - for (guint j = 1; j < len_hole; j++) { - /* although 0xff might be clearer, - * we can't write 0xffff to pic14 */ - fu_byte_array_append_uint8 (buf, 0x00); - } + /* any holes in the hex record */ + len_hole = addr - addr_last; + if (addr_last > 0 && len_hole > 0x100000) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "hole of 0x%x bytes too large to fill on line %u", + (guint) len_hole, + rcd->ln); + return FALSE; + } + if (addr_last > 0x0 && len_hole > 1) { + g_debug ("filling address 0x%08x to 0x%08x on line %u", + addr_last + 1, addr_last + len_hole - 1, rcd->ln); + for (guint j = 1; j < len_hole; j++) { + /* although 0xff might be clearer, + * we can't write 0xffff to pic14 */ + fu_byte_array_append_uint8 (buf, 0x00); } - /* write into buf */ - data_tmp = fu_firmware_strparse_uint8 (line + i); - fu_byte_array_append_uint8 (buf, (gchar) data_tmp); - addr_last = addr++; } + addr_last = addr + rcd->data->len - 1; + + /* write into buf */ + g_byte_array_append (buf, rcd->data->data, rcd->data->len); break; - case DFU_INHX32_RECORD_TYPE_EOF: + case FU_IHEX_FIRMWARE_RECORD_TYPE_EOF: if (got_eof) { g_set_error_literal (error, FWUPD_ERROR, @@ -271,29 +281,50 @@ } got_eof = TRUE; break; - case DFU_INHX32_RECORD_TYPE_EXTENDED_LINEAR: - abs_addr = fu_firmware_strparse_uint16 (line + 9) << 16; + case FU_IHEX_FIRMWARE_RECORD_TYPE_EXTENDED_LINEAR: + if (!fu_common_read_uint16_safe (rcd->data->data, rcd->data->len, + 0x0, &addr16, G_BIG_ENDIAN, error)) + return FALSE; + abs_addr = (guint32) addr16 << 16; g_debug (" abs_addr:\t0x%02x on line %u", abs_addr, rcd->ln); break; - case DFU_INHX32_RECORD_TYPE_START_LINEAR: - abs_addr = fu_firmware_strparse_uint32 (line + 9); + case FU_IHEX_FIRMWARE_RECORD_TYPE_START_LINEAR: + if (!fu_common_read_uint32_safe (rcd->data->data, rcd->data->len, + 0x0, &abs_addr, G_BIG_ENDIAN, error)) + return FALSE; g_debug (" abs_addr:\t0x%08x on line %u", abs_addr, rcd->ln); break; - case DFU_INHX32_RECORD_TYPE_EXTENDED_SEGMENT: + case FU_IHEX_FIRMWARE_RECORD_TYPE_EXTENDED_SEGMENT: + if (!fu_common_read_uint16_safe (rcd->data->data, rcd->data->len, + 0x0, &addr16, G_BIG_ENDIAN, error)) + return FALSE; /* segment base address, so ~1Mb addressable */ - seg_addr = fu_firmware_strparse_uint16 (line + 9) * 16; + seg_addr = (guint32) addr16 * 16; g_debug (" seg_addr:\t0x%08x on line %u", seg_addr, rcd->ln); break; - case DFU_INHX32_RECORD_TYPE_START_SEGMENT: + case FU_IHEX_FIRMWARE_RECORD_TYPE_START_SEGMENT: /* initial content of the CS:IP registers */ - seg_addr = fu_firmware_strparse_uint32 (line + 9); + if (!fu_common_read_uint32_safe (rcd->data->data, rcd->data->len, + 0x0, &seg_addr, G_BIG_ENDIAN, error)) + return FALSE; g_debug (" seg_addr:\t0x%02x on line %u", seg_addr, rcd->ln); break; - case DFU_INHX32_RECORD_TYPE_SIGNATURE: - for (guint i = 9; i < line_end; i += 2) { - guint8 tmp_c = fu_firmware_strparse_uint8 (line + i); - fu_byte_array_append_uint8 (buf_signature, tmp_c); + case FU_IHEX_FIRMWARE_RECORD_TYPE_SIGNATURE: + if (got_sig) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "duplicate signature, perhaps " + "corrupt file"); + return FALSE; + } + if (rcd->data->len > 0) { + g_autoptr(GBytes) data_sig = g_bytes_new (rcd->data->data, rcd->data->len); + g_autoptr(FuFirmwareImage) img_sig = fu_firmware_image_new (data_sig); + fu_firmware_image_set_id (img_sig, FU_FIRMWARE_IMAGE_ID_SIGNATURE); + fu_firmware_add_image (firmware, img_sig); } + got_sig = TRUE; break; default: /* vendors sneak in nonstandard sections past the EOF */ @@ -303,7 +334,7 @@ FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "invalid ihex record type %i on line %u", - record_type, rcd->ln); + rcd->record_type, rcd->ln); return FALSE; } } @@ -323,14 +354,6 @@ if (img_addr != G_MAXUINT32) fu_firmware_image_set_addr (img, img_addr); fu_firmware_add_image (firmware, img); - - /* add optional signature */ - if (buf_signature->len > 0) { - g_autoptr(GBytes) data_sig = g_bytes_new (buf_signature->data, buf_signature->len); - g_autoptr(FuFirmwareImage) img_sig = fu_firmware_image_new (data_sig); - fu_firmware_image_set_id (img_sig, FU_FIRMWARE_IMAGE_ID_SIGNATURE); - fu_firmware_add_image (firmware, img_sig); - } return TRUE; } @@ -364,7 +387,7 @@ const guint chunk_size = 16; gsize len; guint32 address_offset_last = 0x0; - guint8 record_type = DFU_INHX32_RECORD_TYPE_DATA; + guint8 record_type = FU_IHEX_FIRMWARE_RECORD_TYPE_DATA; g_autoptr(GBytes) bytes = NULL; /* get data */ @@ -375,7 +398,7 @@ /* special case */ if (g_strcmp0 (fu_firmware_image_get_id (img), FU_FIRMWARE_IMAGE_ID_SIGNATURE) == 0) - record_type = DFU_INHX32_RECORD_TYPE_SIGNATURE; + record_type = FU_IHEX_FIRMWARE_RECORD_TYPE_SIGNATURE; /* get number of chunks */ data = g_bytes_get_data (bytes, &len); @@ -389,7 +412,7 @@ guint8 buf[2]; fu_common_write_uint16 (buf, address_offset, G_BIG_ENDIAN); fu_ihex_firmware_emit_chunk (str, 0x0, - DFU_INHX32_RECORD_TYPE_EXTENDED_LINEAR, + FU_IHEX_FIRMWARE_RECORD_TYPE_EXTENDED_LINEAR, buf, 2); address_offset_last = address_offset; } @@ -416,7 +439,7 @@ } /* add EOF */ - fu_ihex_firmware_emit_chunk (str, 0x0, DFU_INHX32_RECORD_TYPE_EOF, NULL, 0); + fu_ihex_firmware_emit_chunk (str, 0x0, FU_IHEX_FIRMWARE_RECORD_TYPE_EOF, NULL, 0); return g_bytes_new (str->str, str->len); } @@ -432,6 +455,7 @@ fu_ihex_firmware_init (FuIhexFirmware *self) { self->records = g_ptr_array_new_with_free_func ((GFreeFunc) fu_ihex_firmware_record_free); + fu_firmware_add_flag (FU_FIRMWARE (self), FU_FIRMWARE_FLAG_HAS_CHECKSUM); } static void diff -Nru fwupd-1.4.5/libfwupdplugin/fu-ihex-firmware.h fwupd-1.5.8/libfwupdplugin/fu-ihex-firmware.h --- fwupd-1.4.5/libfwupdplugin/fu-ihex-firmware.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-ihex-firmware.h 2021-03-31 20:08:32.000000000 +0000 @@ -14,7 +14,19 @@ typedef struct { guint ln; GString *buf; + guint8 byte_cnt; + guint32 addr; + guint8 record_type; + GByteArray *data; } FuIhexFirmwareRecord; +#define FU_IHEX_FIRMWARE_RECORD_TYPE_DATA 0x00 +#define FU_IHEX_FIRMWARE_RECORD_TYPE_EOF 0x01 +#define FU_IHEX_FIRMWARE_RECORD_TYPE_EXTENDED_SEGMENT 0x02 +#define FU_IHEX_FIRMWARE_RECORD_TYPE_START_SEGMENT 0x03 +#define FU_IHEX_FIRMWARE_RECORD_TYPE_EXTENDED_LINEAR 0x04 +#define FU_IHEX_FIRMWARE_RECORD_TYPE_START_LINEAR 0x05 +#define FU_IHEX_FIRMWARE_RECORD_TYPE_SIGNATURE 0xfd + FuFirmware *fu_ihex_firmware_new (void); GPtrArray *fu_ihex_firmware_get_records (FuIhexFirmware *self); diff -Nru fwupd-1.4.5/libfwupdplugin/fu-io-channel.c fwupd-1.5.8/libfwupdplugin/fu-io-channel.c --- fwupd-1.4.5/libfwupdplugin/fu-io-channel.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-io-channel.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -61,6 +61,7 @@ fu_io_channel_shutdown (FuIOChannel *self, GError **error) { g_return_val_if_fail (FU_IS_IO_CHANNEL (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); if (!g_close (self->fd, error)) return FALSE; self->fd = -1; @@ -159,6 +160,7 @@ gsize idx = 0; g_return_val_if_fail (FU_IS_IO_CHANNEL (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* flush pending reads */ if (flags & FU_IO_CHANNEL_FLAG_FLUSH_INPUT) { @@ -489,7 +491,12 @@ fu_io_channel_new_file (const gchar *filename, GError **error) { #ifdef HAVE_POLL_H - gint fd = g_open (filename, O_RDWR | O_NONBLOCK, S_IRWXU); + gint fd; + + g_return_val_if_fail (filename != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + fd = g_open (filename, O_RDWR | O_NONBLOCK, S_IRWXU); if (fd < 0) { g_set_error (error, FWUPD_ERROR, @@ -499,6 +506,8 @@ } return fu_io_channel_unix_new (fd); #else + g_return_val_if_fail (filename != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, diff -Nru fwupd-1.4.5/libfwupdplugin/fu-io-channel.h fwupd-1.5.8/libfwupdplugin/fu-io-channel.h --- fwupd-1.4.5/libfwupdplugin/fu-io-channel.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-io-channel.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -32,41 +32,49 @@ FuIOChannel *fu_io_channel_unix_new (gint fd); FuIOChannel *fu_io_channel_new_file (const gchar *filename, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gint fu_io_channel_unix_get_fd (FuIOChannel *self); gboolean fu_io_channel_shutdown (FuIOChannel *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_io_channel_write_raw (FuIOChannel *self, const guint8 *data, gsize datasz, guint timeout_ms, FuIOChannelFlags flags, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_io_channel_read_raw (FuIOChannel *self, guint8 *buf, gsize bufsz, gsize *bytes_read, guint timeout_ms, FuIOChannelFlags flags, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_io_channel_write_bytes (FuIOChannel *self, GBytes *bytes, guint timeout_ms, FuIOChannelFlags flags, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_io_channel_write_byte_array (FuIOChannel *self, GByteArray *buf, guint timeout_ms, FuIOChannelFlags flags, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; GBytes *fu_io_channel_read_bytes (FuIOChannel *self, gssize max_size, guint timeout_ms, FuIOChannelFlags flags, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; GByteArray *fu_io_channel_read_byte_array (FuIOChannel *self, gssize max_size, guint timeout_ms, FuIOChannelFlags flags, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; diff -Nru fwupd-1.4.5/libfwupdplugin/fu-plugin.c fwupd-1.5.8/libfwupdplugin/fu-plugin.c --- fwupd-1.4.5/libfwupdplugin/fu-plugin.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-plugin.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2018 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -36,12 +36,10 @@ typedef struct { GModule *module; - GUsbContext *usb_ctx; - gboolean enabled; guint order; guint priority; GPtrArray *rules[FU_PLUGIN_RULE_LAST]; - gchar *name; + GPtrArray *devices; /* (nullable) (element-type FuDevice) */ gchar *build_hash; FuHwids *hwids; FuQuirks *quirks; @@ -50,9 +48,9 @@ GPtrArray *udev_subsystems; FuSmbios *smbios; GType device_gtype; - GHashTable *devices; /* platform_id:GObject */ - GRWLock devices_mutex; - GHashTable *report_metadata; /* key:value */ + GHashTable *cache; /* (nullable): platform_id:GObject */ + GRWLock cache_mutex; + GHashTable *report_metadata; /* (nullable): key:value */ FuPluginData *data; } FuPluginPrivate; @@ -65,12 +63,13 @@ SIGNAL_SET_COLDPLUG_DELAY, SIGNAL_CHECK_SUPPORTED, SIGNAL_ADD_FIRMWARE_GTYPE, + SIGNAL_SECURITY_CHANGED, SIGNAL_LAST }; static guint signals[SIGNAL_LAST] = { 0 }; -G_DEFINE_TYPE_WITH_PRIVATE (FuPlugin, fu_plugin, G_TYPE_OBJECT) +G_DEFINE_TYPE_WITH_PRIVATE (FuPlugin, fu_plugin, FWUPD_TYPE_PLUGIN) #define GET_PRIVATE(o) (fu_plugin_get_instance_private (o)) typedef const gchar *(*FuPluginGetNameFunc) (void); @@ -98,12 +97,8 @@ GBytes *blob_fw, FwupdInstallFlags flags, GError **error); -typedef gboolean (*FuPluginUsbDeviceAddedFunc) (FuPlugin *self, - FuUsbDevice *device, - GError **error); -typedef gboolean (*FuPluginUdevDeviceAddedFunc) (FuPlugin *self, - FuUdevDevice *device, - GError **error); +typedef void (*FuPluginSecurityAttrsFunc) (FuPlugin *self, + FuSecurityAttrs *attrs); /** * fu_plugin_is_open: @@ -135,9 +130,8 @@ const gchar * fu_plugin_get_name (FuPlugin *self) { - FuPluginPrivate *priv = GET_PRIVATE (self); g_return_val_if_fail (FU_IS_PLUGIN (self), NULL); - return priv->name; + return fwupd_plugin_get_name (FWUPD_PLUGIN (self)); } /** @@ -152,11 +146,8 @@ void fu_plugin_set_name (FuPlugin *self, const gchar *name) { - FuPluginPrivate *priv = GET_PRIVATE (self); g_return_if_fail (FU_IS_PLUGIN (self)); - g_return_if_fail (name != NULL); - g_free (priv->name); - priv->name = g_strdup (name); + fwupd_plugin_set_name (FWUPD_PLUGIN (self), name); } /** @@ -175,6 +166,11 @@ FuPluginPrivate *priv = GET_PRIVATE (self); g_return_if_fail (FU_IS_PLUGIN (self)); g_return_if_fail (build_hash != NULL); + + /* not changed */ + if (g_strcmp0 (priv->build_hash, build_hash) == 0) + return; + g_free (priv->build_hash); priv->build_hash = g_strdup (build_hash); } @@ -212,11 +208,13 @@ fu_plugin_cache_lookup (FuPlugin *self, const gchar *id) { FuPluginPrivate *priv = GET_PRIVATE (self); - g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new (&priv->devices_mutex); + g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new (&priv->cache_mutex); g_return_val_if_fail (FU_IS_PLUGIN (self), NULL); g_return_val_if_fail (id != NULL, NULL); g_return_val_if_fail (locker != NULL, NULL); - return g_hash_table_lookup (priv->devices, id); + if (priv->cache == NULL) + return NULL; + return g_hash_table_lookup (priv->cache, id); } /** @@ -233,11 +231,17 @@ fu_plugin_cache_add (FuPlugin *self, const gchar *id, gpointer dev) { FuPluginPrivate *priv = GET_PRIVATE (self); - g_autoptr(GRWLockWriterLocker) locker = g_rw_lock_writer_locker_new (&priv->devices_mutex); + g_autoptr(GRWLockWriterLocker) locker = g_rw_lock_writer_locker_new (&priv->cache_mutex); g_return_if_fail (FU_IS_PLUGIN (self)); g_return_if_fail (id != NULL); g_return_if_fail (locker != NULL); - g_hash_table_insert (priv->devices, g_strdup (id), g_object_ref (dev)); + if (priv->cache == NULL) { + priv->cache = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + (GDestroyNotify) g_object_unref); + } + g_hash_table_insert (priv->cache, g_strdup (id), g_object_ref (dev)); } /** @@ -253,11 +257,13 @@ fu_plugin_cache_remove (FuPlugin *self, const gchar *id) { FuPluginPrivate *priv = GET_PRIVATE (self); - g_autoptr(GRWLockWriterLocker) locker = g_rw_lock_writer_locker_new (&priv->devices_mutex); + g_autoptr(GRWLockWriterLocker) locker = g_rw_lock_writer_locker_new (&priv->cache_mutex); g_return_if_fail (FU_IS_PLUGIN (self)); g_return_if_fail (id != NULL); g_return_if_fail (locker != NULL); - g_hash_table_remove (priv->devices, id); + if (priv->cache == NULL) + return; + g_hash_table_remove (priv->cache, id); } /** @@ -307,7 +313,8 @@ * fu_plugin_get_usb_context: * @self: A #FuPlugin * - * Gets the shared USB context that all plugins can use. + * This used to get the shared USB context that all plugins can use; it now + * returns %NULL; * * Returns: (transfer none): a #GUsbContext. * @@ -316,9 +323,8 @@ GUsbContext * fu_plugin_get_usb_context (FuPlugin *self) { - FuPluginPrivate *priv = GET_PRIVATE (self); g_return_val_if_fail (FU_IS_PLUGIN (self), NULL); - return priv->usb_ctx; + return NULL; } /** @@ -326,15 +332,13 @@ * @self: A #FuPlugin * @usb_ctx: A #FGUsbContext * - * Sets the shared USB context for a plugin + * This used to set the shared USB context for a plugin. It now does nothing. * * Since: 0.8.0 **/ void fu_plugin_set_usb_context (FuPlugin *self, GUsbContext *usb_ctx) { - FuPluginPrivate *priv = GET_PRIVATE (self); - g_set_object (&priv->usb_ctx, usb_ctx); } /** @@ -351,9 +355,8 @@ gboolean fu_plugin_get_enabled (FuPlugin *self) { - FuPluginPrivate *priv = GET_PRIVATE (self); g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE); - return priv->enabled; + return !fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED); } /** @@ -368,9 +371,13 @@ void fu_plugin_set_enabled (FuPlugin *self, gboolean enabled) { - FuPluginPrivate *priv = GET_PRIVATE (self); g_return_if_fail (FU_IS_PLUGIN (self)); - priv->enabled = enabled; + if (enabled) { + fwupd_plugin_remove_flag (FWUPD_PLUGIN (self), + FWUPD_PLUGIN_FLAG_DISABLED); + } else { + fu_plugin_add_flag (self, FWUPD_PLUGIN_FLAG_DISABLED); + } } /** @@ -414,6 +421,10 @@ FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginInitFunc func = NULL; + g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE); + g_return_val_if_fail (filename != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + priv->module = g_module_open (filename, 0); if (priv->module == NULL) { g_set_error (error, @@ -421,23 +432,57 @@ G_IO_ERROR_FAILED, "failed to open plugin %s: %s", filename, g_module_error ()); + fu_plugin_add_flag (self, FWUPD_PLUGIN_FLAG_FAILED_OPEN); + fu_plugin_add_flag (self, FWUPD_PLUGIN_FLAG_USER_WARNING); return FALSE; } /* set automatically */ - if (priv->name == NULL) - priv->name = fu_plugin_guess_name_from_fn (filename); + if (fu_plugin_get_name (self) == NULL) { + g_autofree gchar *str = fu_plugin_guess_name_from_fn (filename); + fu_plugin_set_name (self, str); + } /* optional */ g_module_symbol (priv->module, "fu_plugin_init", (gpointer *) &func); if (func != NULL) { - g_debug ("performing init() on %s", filename); + g_debug ("init(%s)", filename); func (self); } return TRUE; } +/* order of usefulness to the user */ +static const gchar * +fu_plugin_build_device_update_error (FuPlugin *self) +{ + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_NO_HARDWARE)) + return "Not updatable as required hardware was not found"; + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_LEGACY_BIOS)) + return "Not updatable in legacy BIOS mode"; + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_CAPSULES_UNSUPPORTED)) + return "Not updatable as UEFI capsule updates not enabled in firmware setup"; + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_UNLOCK_REQUIRED)) + return "Not updatable as requires unlock"; + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_EFIVAR_NOT_MOUNTED)) + return "Not updatable as efivarfs was not found"; + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_ESP_NOT_FOUND)) + return "Not updatable as UEFI ESP partition not detected"; + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) + return "Not updatable as plugin was disabled"; + return NULL; +} + +static void +fu_plugin_ensure_devices (FuPlugin *self) +{ + FuPluginPrivate *priv = GET_PRIVATE (self); + if (priv->devices != NULL) + return; + priv->devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); +} + /** * fu_plugin_device_add: * @self: A #FuPlugin @@ -456,6 +501,7 @@ void fu_plugin_device_add (FuPlugin *self, FuDevice *device) { + FuPluginPrivate *priv = GET_PRIVATE (self); GPtrArray *children; g_autoptr(GError) error = NULL; @@ -468,6 +514,25 @@ return; } + /* add to array */ + fu_plugin_ensure_devices (self); + g_ptr_array_add (priv->devices, g_object_ref (device)); + + /* proxy to device where required */ + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE)) { + g_debug ("plugin %s has _CLEAR_UPDATABLE, so removing from %s", + fu_plugin_get_name (self), + fu_device_get_id (device)); + fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + } + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_USER_WARNING) && + fu_device_get_update_error (device) == NULL) { + const gchar *tmp = fu_plugin_build_device_update_error (self); + g_debug ("setting %s update error to '%s' from %s", + fu_device_get_id (device), tmp, fu_plugin_get_name (self)); + fu_device_set_update_error (device, tmp); + } + g_debug ("emit added from %s: %s", fu_plugin_get_name (self), fu_device_get_id (device)); @@ -485,6 +550,26 @@ } /** + * fu_plugin_get_devices: + * @self: A #FuPlugin + * + * Returns all devices added by the plugin using fu_plugin_device_add() and + * not yet removed with fu_plugin_device_remove(). + * + * Returns: (transfer none) (element-type FuDevice): devices + * + * Since: 1.5.6 + **/ +GPtrArray * +fu_plugin_get_devices (FuPlugin *self) +{ + FuPluginPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_PLUGIN (self), NULL); + fu_plugin_ensure_devices (self); + return priv->devices; +} + +/** * fu_plugin_device_register: * @self: A #FuPlugin * @device: A #FuDevice @@ -530,9 +615,15 @@ void fu_plugin_device_remove (FuPlugin *self, FuDevice *device) { + FuPluginPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_PLUGIN (self)); g_return_if_fail (FU_IS_DEVICE (device)); + /* remove from array */ + if (priv->devices != NULL) + g_ptr_array_remove (priv->devices, device); + g_debug ("emit removed from %s: %s", fu_plugin_get_name (self), fu_device_get_id (device)); @@ -556,6 +647,21 @@ } /** + * fu_plugin_security_changed: + * @self: A #FuPlugin + * + * Informs the daemon that the HSI state may have changed. + * + * Since: 1.5.0 + **/ +void +fu_plugin_security_changed (FuPlugin *self) +{ + g_return_if_fail (FU_IS_PLUGIN (self)); + g_signal_emit (self, signals[SIGNAL_SECURITY_CHANGED], 0); +} + +/** * fu_plugin_check_hwid: * @self: A #FuPlugin * @hwid: A Hardware ID GUID, e.g. `6de5d951-d755-576b-bd09-c5cf66b27234` @@ -647,10 +753,9 @@ for (guint i = 0; i < hwids->len; i++) { const gchar *hwid = g_ptr_array_index (hwids, i); const gchar *value; - g_autofree gchar *key = g_strdup_printf ("HwId=%s", hwid); /* does prefixed quirk exist */ - value = fu_quirks_lookup_by_id (priv->quirks, key, FU_QUIRKS_FLAGS); + value = fu_quirks_lookup_by_id (priv->quirks, hwid, FU_QUIRKS_FLAGS); if (value != NULL) { g_auto(GStrv) quirks = g_strsplit (value, ",", -1); if (g_strv_contains ((const gchar * const *) quirks, flag)) @@ -955,7 +1060,7 @@ * * Set the minimum time that should be waited in-between the call to * fu_plugin_coldplug_prepare() and fu_plugin_coldplug(). This is usually going - * to be the minimum hardware initialisation time from a datasheet. + * to be the minimum hardware initialization time from a datasheet. * * It is better to use this function rather than using a sleep() in the plugin * itself as then only one delay is done in the daemon rather than waiting for @@ -1024,6 +1129,32 @@ locker = fu_device_locker_new (device, error); if (locker == NULL) return FALSE; + + /* back the old firmware up to /var/lib/fwupd */ + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_BACKUP_BEFORE_INSTALL)) { + g_autoptr(GBytes) fw_old = NULL; + g_autofree gchar *path = NULL; + g_autofree gchar *fn = NULL; + g_autofree gchar *localstatedir = NULL; + + fw_old = fu_device_dump_firmware (device, error); + if (fw_old == NULL) { + g_prefix_error (error, "failed to backup old firmware: "); + return FALSE; + } + localstatedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); + fn = g_strdup_printf ("%s.bin", fu_device_get_version (device)); + path = g_build_filename (localstatedir, + "backup", + fu_device_get_id (device), + fu_device_get_serial (device) != NULL ? + fu_device_get_serial (device) : + "default", + fn, NULL); + if (!fu_common_set_contents_bytes (path, fw_old, error)) + return FALSE; + } + return fu_device_write_firmware (device, fw, flags, error); } @@ -1085,7 +1216,7 @@ g_autoptr(GError) error_local = NULL; /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return TRUE; /* no object loaded */ @@ -1096,11 +1227,11 @@ g_module_symbol (priv->module, "fu_plugin_startup", (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("performing startup() on %s", priv->name); + g_debug ("startup(%s)", fu_plugin_get_name (self)); if (!func (self, &error_local)) { if (error_local == NULL) { - g_critical ("unset error in plugin %s for startup()", - priv->name); + g_critical ("unset plugin error in startup(%s)", + fu_plugin_get_name (self)); g_set_error_literal (&error_local, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -1108,7 +1239,7 @@ } g_propagate_prefixed_error (error, g_steal_pointer (&error_local), "failed to startup using %s: ", - priv->name); + fu_plugin_get_name (self)); return FALSE; } return TRUE; @@ -1125,7 +1256,7 @@ g_autoptr(GError) error_local = NULL; /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return TRUE; /* no object loaded */ @@ -1136,17 +1267,17 @@ g_module_symbol (priv->module, symbol_name, (gpointer *) &func); if (func == NULL) { if (device_func != NULL) { - g_debug ("running superclassed %s() on %s", - symbol_name + 10, priv->name); + g_debug ("running superclassed %s(%s)", + symbol_name + 10, fu_plugin_get_name (self)); return device_func (self, device, error); } return TRUE; } - g_debug ("performing %s() on %s", symbol_name + 10, priv->name); + g_debug ("%s(%s)", symbol_name + 10, fu_plugin_get_name (self)); if (!func (self, device, &error_local)) { if (error_local == NULL) { - g_critical ("unset error in plugin %s for %s()", - priv->name, symbol_name + 10); + g_critical ("unset plugin error in %s(%s)", + fu_plugin_get_name (self), symbol_name + 10); g_set_error_literal (&error_local, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -1154,7 +1285,7 @@ } g_propagate_prefixed_error (error, g_steal_pointer (&error_local), "failed to %s using %s: ", - symbol_name + 10, priv->name); + symbol_name + 10, fu_plugin_get_name (self)); return FALSE; } return TRUE; @@ -1170,7 +1301,7 @@ g_autoptr(GError) error_local = NULL; /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return TRUE; /* no object loaded */ @@ -1181,11 +1312,11 @@ g_module_symbol (priv->module, symbol_name, (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("performing %s() on %s", symbol_name + 10, priv->name); + g_debug ("%s(%s)", symbol_name + 10, fu_plugin_get_name (self)); if (!func (self, flags, device, &error_local)) { if (error_local == NULL) { - g_critical ("unset error in plugin %s for %s()", - priv->name, symbol_name + 10); + g_critical ("unset plugin error in %s(%s)", + fu_plugin_get_name (self), symbol_name + 10); g_set_error_literal (&error_local, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -1193,7 +1324,7 @@ } g_propagate_prefixed_error (error, g_steal_pointer (&error_local), "failed to %s using %s: ", - symbol_name + 10, priv->name); + symbol_name + 10, fu_plugin_get_name (self)); return FALSE; } return TRUE; @@ -1209,7 +1340,7 @@ g_autoptr(GError) error_local = NULL; /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return TRUE; /* no object loaded */ @@ -1220,11 +1351,11 @@ g_module_symbol (priv->module, symbol_name, (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("performing %s() on %s", symbol_name + 10, priv->name); + g_debug ("%s(%s)", symbol_name + 10, fu_plugin_get_name (self)); if (!func (self, devices, &error_local)) { if (error_local == NULL) { - g_critical ("unset error in plugin %s for %s()", - priv->name, symbol_name + 10); + g_critical ("unset plugin error in for %s(%s)", + fu_plugin_get_name (self), symbol_name + 10); g_set_error_literal (&error_local, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -1232,7 +1363,7 @@ } g_propagate_prefixed_error (error, g_steal_pointer (&error_local), "failed to %s using %s: ", - symbol_name + 10, priv->name); + symbol_name + 10, fu_plugin_get_name (self)); return FALSE; } return TRUE; @@ -1257,7 +1388,7 @@ g_autoptr(GError) error_local = NULL; /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return TRUE; /* no object loaded */ @@ -1268,18 +1399,18 @@ g_module_symbol (priv->module, "fu_plugin_coldplug", (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("performing coldplug() on %s", priv->name); + g_debug ("coldplug(%s)", fu_plugin_get_name (self)); if (!func (self, &error_local)) { if (error_local == NULL) { - g_critical ("unset error in plugin %s for coldplug()", - priv->name); + g_critical ("unset plugin error in coldplug(%s)", + fu_plugin_get_name (self)); g_set_error_literal (&error_local, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "unspecified error"); } g_propagate_prefixed_error (error, g_steal_pointer (&error_local), - "failed to coldplug using %s: ", priv->name); + "failed to coldplug using %s: ", fu_plugin_get_name (self)); return FALSE; } return TRUE; @@ -1304,7 +1435,7 @@ g_autoptr(GError) error_local = NULL; /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return TRUE; /* no object loaded */ @@ -1315,11 +1446,11 @@ g_module_symbol (priv->module, "fu_plugin_recoldplug", (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("performing recoldplug() on %s", priv->name); + g_debug ("recoldplug(%s)", fu_plugin_get_name (self)); if (!func (self, &error_local)) { if (error_local == NULL) { - g_critical ("unset error in plugin %s for recoldplug()", - priv->name); + g_critical ("unset plugin error in recoldplug(%s)", + fu_plugin_get_name (self)); g_set_error_literal (&error_local, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -1327,7 +1458,7 @@ } g_propagate_prefixed_error (error, g_steal_pointer (&error_local), "failed to recoldplug using %s: ", - priv->name); + fu_plugin_get_name (self)); return FALSE; } return TRUE; @@ -1352,7 +1483,7 @@ g_autoptr(GError) error_local = NULL; /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return TRUE; /* no object loaded */ @@ -1363,11 +1494,11 @@ g_module_symbol (priv->module, "fu_plugin_coldplug_prepare", (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("performing coldplug_prepare() on %s", priv->name); + g_debug ("coldplug_prepare(%s)", fu_plugin_get_name (self)); if (!func (self, &error_local)) { if (error_local == NULL) { - g_critical ("unset error in plugin %s for coldplug_prepare()", - priv->name); + g_critical ("unset plugin error in coldplug_prepare(%s)", + fu_plugin_get_name (self)); g_set_error_literal (&error_local, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -1375,7 +1506,7 @@ } g_propagate_prefixed_error (error, g_steal_pointer (&error_local), "failed to coldplug_prepare using %s: ", - priv->name); + fu_plugin_get_name (self)); return FALSE; } return TRUE; @@ -1400,7 +1531,7 @@ g_autoptr(GError) error_local = NULL; /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return TRUE; /* no object loaded */ @@ -1411,11 +1542,11 @@ g_module_symbol (priv->module, "fu_plugin_coldplug_cleanup", (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("performing coldplug_cleanup() on %s", priv->name); + g_debug ("coldplug_cleanup(%s)", fu_plugin_get_name (self)); if (!func (self, &error_local)) { if (error_local == NULL) { - g_critical ("unset error in plugin %s for coldplug_cleanup()", - priv->name); + g_critical ("unset plugin error in coldplug_cleanup(%s)", + fu_plugin_get_name (self)); g_set_error_literal (&error_local, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -1423,7 +1554,7 @@ } g_propagate_prefixed_error (error, g_steal_pointer (&error_local), "failed to coldplug_cleanup using %s: ", - priv->name); + fu_plugin_get_name (self)); return FALSE; } return TRUE; @@ -1472,6 +1603,8 @@ /** * fu_plugin_runner_update_prepare: * @self: a #FuPlugin + * @flags: #FwupdInstallFlags + * @device: a #FuDevice * @error: a #GError or NULL * * Runs the update_prepare routine for the plugin @@ -1492,6 +1625,8 @@ /** * fu_plugin_runner_update_cleanup: * @self: a #FuPlugin + * @flags: #FwupdInstallFlags + * @device: a #FuDevice * @error: a #GError or NULL * * Runs the update_cleanup routine for the plugin @@ -1554,6 +1689,7 @@ /** * fu_plugin_runner_update_reload: * @self: a #FuPlugin + * @device: A #FuDevice * @error: a #GError or NULL * * Runs reload routine for a device @@ -1565,11 +1701,10 @@ gboolean fu_plugin_runner_update_reload (FuPlugin *self, FuDevice *device, GError **error) { - FuPluginPrivate *priv = GET_PRIVATE (self); g_autoptr(FuDeviceLocker) locker = NULL; /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return TRUE; /* no object loaded */ @@ -1580,6 +1715,34 @@ } /** + * fu_plugin_runner_add_security_attrs: + * @self: a #FuPlugin + * @attrs: a #FuSecurityAttrs + * + * Runs the `add_security_attrs()` routine for the plugin + * + * Since: 1.5.0 + **/ +void +fu_plugin_runner_add_security_attrs (FuPlugin *self, FuSecurityAttrs *attrs) +{ + FuPluginPrivate *priv = GET_PRIVATE (self); + FuPluginSecurityAttrsFunc func = NULL; + const gchar *symbol_name = "fu_plugin_add_security_attrs"; + + /* no object loaded */ + if (priv->module == NULL) + return; + + /* optional, but gets called even for disabled plugins */ + g_module_symbol (priv->module, symbol_name, (gpointer *) &func); + if (func == NULL) + return; + g_debug ("%s(%s)", symbol_name + 10, fu_plugin_get_name (self)); + func (self, attrs); +} + +/** * fu_plugin_add_udev_subsystem: * @self: a #FuPlugin * @subsystem: a subsystem name, e.g. `pciport` @@ -1594,6 +1757,8 @@ fu_plugin_add_udev_subsystem (FuPlugin *self, const gchar *subsystem) { FuPluginPrivate *priv = GET_PRIVATE (self); + if (priv->udev_subsystems == NULL) + priv->udev_subsystems = g_ptr_array_new_with_free_func (g_free); for (guint i = 0; i < priv->udev_subsystems->len; i++) { const gchar *subsystem_tmp = g_ptr_array_index (priv->udev_subsystems, i); if (g_strcmp0 (subsystem_tmp, subsystem) == 0) @@ -1610,7 +1775,7 @@ * * Sets the device #GType which is used when creating devices. * - * If this method is used then fu_plugin_usb_device_added() is not called, and + * If this method is used then fu_plugin_backend_device_added() is not called, and * instead the object is created in the daemon for the plugin. * * Plugins can use this method only in fu_plugin_init() @@ -1624,14 +1789,55 @@ priv->device_gtype = device_gtype; } +static gchar * +fu_common_string_uncamelcase (const gchar *str) +{ + GString *tmp = g_string_new (NULL); + for (guint i = 0; str[i] != '\0'; i++) { + if (g_ascii_islower (str[i]) || + g_ascii_isdigit (str[i])) { + g_string_append_c (tmp, str[i]); + continue; + } + if (i > 0) + g_string_append_c (tmp, '-'); + g_string_append_c (tmp, g_ascii_tolower (str[i])); + } + return g_string_free (tmp, FALSE); +} + +/** + * fu_plugin_add_possible_quirk_key: + * @self: a #FuPlugin + * @possible_key: A quirk string, e.g. `DfuVersion` + * + * Adds a possible quirk key. If added by a plugin it should be namespaced + * using the plugin name, where possible. + * + * Plugins can use this method only in fu_plugin_init() + * + * Since: 1.5.8 + **/ +void +fu_plugin_add_possible_quirk_key (FuPlugin *self, const gchar *possible_key) +{ + FuPluginPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_PLUGIN (self)); + g_return_if_fail (possible_key != NULL); + if (priv->quirks == NULL) + return; + fu_quirks_add_possible_key (priv->quirks, possible_key); +} + /** * fu_plugin_add_firmware_gtype: * @self: a #FuPlugin - * @id: A string describing the type - * @gtype: a #GType `FU_TYPE_DEVICE` + * @id: (nullable): An optional string describing the type, e.g. "ihex" + * @gtype: a #GType e.g. `FU_TYPE_FOO_FIRMWARE` + * + * Adds a firmware #GType which is used when creating devices. If @id is not + * specified then it is guessed using the #GType name. * - * Adds a firmware #GType which is used when creating devices. - * * * Plugins can use this method only in fu_plugin_init() * * Since: 1.3.3 @@ -1639,7 +1845,17 @@ void fu_plugin_add_firmware_gtype (FuPlugin *self, const gchar *id, GType gtype) { - g_signal_emit (self, signals[SIGNAL_ADD_FIRMWARE_GTYPE], 0, id, gtype); + g_autofree gchar *id_safe = NULL; + if (id != NULL) { + id_safe = g_strdup (id); + } else { + g_autoptr(GString) str = g_string_new (g_type_name (gtype)); + if (g_str_has_prefix (str->str, "Fu")) + g_string_erase (str, 0, 2); + fu_common_string_replace (str, "Firmware", ""); + id_safe = fu_common_string_uncamelcase (str->str); + } + g_signal_emit (self, signals[SIGNAL_ADD_FIRMWARE_GTYPE], 0, id_safe, gtype); } static gboolean @@ -1656,7 +1872,7 @@ } static gboolean -fu_plugin_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError **error) +fu_plugin_backend_device_added (FuPlugin *self, FuDevice *device, GError **error) { FuPluginPrivate *priv = GET_PRIVATE (self); GType device_gtype = fu_device_get_specialized_gtype (FU_DEVICE (device)); @@ -1675,7 +1891,7 @@ /* there are a lot of different devices that match, but not all respond * well to opening -- so limit some ones with issued updates */ - if (fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_ONLY_SUPPORTED)) { + if (fu_device_has_internal_flag (dev, FU_DEVICE_INTERNAL_FLAG_ONLY_SUPPORTED)) { if (!fu_device_probe (dev, error)) return FALSE; fu_device_convert_instance_ids (dev); @@ -1691,57 +1907,7 @@ if (locker == NULL) return FALSE; fu_plugin_device_add (self, dev); - return TRUE; -} - -static gboolean -fu_plugin_udev_device_changed (FuPlugin *self, FuUdevDevice *device, GError **error) -{ - g_autoptr(FuDeviceLocker) locker = NULL; - - /* open */ - locker = fu_device_locker_new (FU_DEVICE (device), error); - if (locker == NULL) - return FALSE; - return fu_device_rescan (FU_DEVICE (device), error); -} - -static gboolean -fu_plugin_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError **error) -{ - FuPluginPrivate *priv = GET_PRIVATE (self); - GType device_gtype = fu_device_get_specialized_gtype (FU_DEVICE (device)); - g_autoptr(FuDevice) dev = NULL; - g_autoptr(FuDeviceLocker) locker = NULL; - - /* fall back to plugin default */ - if (device_gtype == G_TYPE_INVALID) - device_gtype = priv->device_gtype; - - /* create new device and incorporate existing properties */ - dev = g_object_new (device_gtype, NULL); - fu_device_incorporate (FU_DEVICE (dev), FU_DEVICE (device)); - if (!fu_plugin_runner_device_created (self, dev, error)) - return FALSE; - - /* there are a lot of different devices that match, but not all respond - * well to opening -- so limit some ones with issued updates */ - if (fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_ONLY_SUPPORTED)) { - if (!fu_device_probe (dev, error)) - return FALSE; - fu_device_convert_instance_ids (dev); - if (!fu_plugin_check_supported_device (self, dev)) { - g_autofree gchar *guids = fu_device_get_guids_as_str (dev); - g_debug ("%s has no updates, so ignoring device", guids); - return TRUE; - } - } - - /* open and add */ - locker = fu_device_locker_new (dev, error); - if (locker == NULL) - return FALSE; - fu_plugin_device_add (self, FU_DEVICE (dev)); + fu_plugin_runner_device_added (self, dev); return TRUE; } @@ -1751,7 +1917,7 @@ * @device: a #FuUsbDevice * @error: a #GError or NULL * - * Call the usb_device_added routine for the plugin + * Call the backend_device_added routine for the plugin * * Returns: #TRUE for success, #FALSE for failure * @@ -1760,44 +1926,7 @@ gboolean fu_plugin_runner_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError **error) { - FuPluginPrivate *priv = GET_PRIVATE (self); - FuPluginUsbDeviceAddedFunc func = NULL; - g_autoptr(GError) error_local = NULL; - - /* not enabled */ - if (!priv->enabled) - return TRUE; - - /* no object loaded */ - if (priv->module == NULL) - return TRUE; - - /* optional */ - g_module_symbol (priv->module, "fu_plugin_usb_device_added", (gpointer *) &func); - if (func == NULL) { - if (priv->device_gtype != G_TYPE_INVALID || - fu_device_get_specialized_gtype (FU_DEVICE (device)) != G_TYPE_INVALID) { - if (!fu_plugin_usb_device_added (self, device, error)) - return FALSE; - } - return TRUE; - } - g_debug ("performing usb_device_added() on %s", priv->name); - if (!func (self, device, &error_local)) { - if (error_local == NULL) { - g_critical ("unset error in plugin %s for usb_device_added()", - priv->name); - g_set_error_literal (&error_local, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "unspecified error"); - } - g_propagate_prefixed_error (error, g_steal_pointer (&error_local), - "failed to add device using on %s: ", - priv->name); - return FALSE; - } - return TRUE; + return fu_plugin_runner_backend_device_added (self, FU_DEVICE (device), error); } /** @@ -1806,7 +1935,7 @@ * @device: a #FuUdevDevice * @error: a #GError or NULL * - * Call the udev_device_added routine for the plugin + * Call the backend_device_added routine for the plugin * * Returns: #TRUE for success, #FALSE for failure * @@ -1815,12 +1944,34 @@ gboolean fu_plugin_runner_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError **error) { + return fu_plugin_runner_backend_device_added (self, FU_DEVICE (device), error); +} + +/** + * fu_plugin_runner_backend_device_added: + * @self: a #FuPlugin + * @device: a #FuDevice + * @error: a #GError or NULL + * + * Call the backend_device_added routine for the plugin + * + * Returns: #TRUE for success, #FALSE for failure + * + * Since: 1.5.6 + **/ +gboolean +fu_plugin_runner_backend_device_added (FuPlugin *self, FuDevice *device, GError **error) +{ FuPluginPrivate *priv = GET_PRIVATE (self); - FuPluginUdevDeviceAddedFunc func = NULL; + FuPluginDeviceFunc func = NULL; g_autoptr(GError) error_local = NULL; + g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE); + g_return_val_if_fail (FU_IS_DEVICE (device), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return TRUE; /* no object loaded */ @@ -1828,20 +1979,23 @@ return TRUE; /* optional */ - g_module_symbol (priv->module, "fu_plugin_udev_device_added", (gpointer *) &func); + g_module_symbol (priv->module, "fu_plugin_backend_device_added", (gpointer *) &func); if (func == NULL) { if (priv->device_gtype != G_TYPE_INVALID || - fu_device_get_specialized_gtype (FU_DEVICE (device)) != G_TYPE_INVALID) { - if (!fu_plugin_udev_device_added (self, device, error)) - return FALSE; + fu_device_get_specialized_gtype (device) != G_TYPE_INVALID) { + return fu_plugin_backend_device_added (self, device, error); } - return TRUE; + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "No device GType set"); + return FALSE; } - g_debug ("performing udev_device_added() on %s", priv->name); + g_debug ("backend_device_added(%s)", fu_plugin_get_name (self)); if (!func (self, device, &error_local)) { if (error_local == NULL) { - g_critical ("unset error in plugin %s for udev_device_added()", - priv->name); + g_critical ("unset plugin error in backend_device_added(%s)", + fu_plugin_get_name (self)); g_set_error_literal (&error_local, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -1849,7 +2003,7 @@ } g_propagate_prefixed_error (error, g_steal_pointer (&error_local), "failed to add device using on %s: ", - priv->name); + fu_plugin_get_name (self)); return FALSE; } return TRUE; @@ -1861,7 +2015,7 @@ * @device: a #FuUdevDevice * @error: a #GError or NULL * - * Call the udev_device_changed routine for the plugin + * Call the backend_device_changed routine for the plugin * * Returns: #TRUE for success, #FALSE for failure * @@ -1870,12 +2024,34 @@ gboolean fu_plugin_runner_udev_device_changed (FuPlugin *self, FuUdevDevice *device, GError **error) { + return fu_plugin_runner_backend_device_changed (self, FU_DEVICE (device), error); +} + +/** + * fu_plugin_runner_backend_device_changed: + * @self: a #FuPlugin + * @device: a #FuDevice + * @error: a #GError or NULL + * + * Call the backend_device_changed routine for the plugin + * + * Returns: #TRUE for success, #FALSE for failure + * + * Since: 1.5.6 + **/ +gboolean +fu_plugin_runner_backend_device_changed (FuPlugin *self, FuDevice *device, GError **error) +{ FuPluginPrivate *priv = GET_PRIVATE (self); - FuPluginUdevDeviceAddedFunc func = NULL; + FuPluginDeviceFunc func = NULL; g_autoptr(GError) error_local = NULL; + g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE); + g_return_val_if_fail (FU_IS_DEVICE (device), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return TRUE; /* no object loaded */ @@ -1883,20 +2059,14 @@ return TRUE; /* optional */ - g_module_symbol (priv->module, "fu_plugin_udev_device_changed", (gpointer *) &func); - if (func == NULL) { - if (priv->device_gtype != G_TYPE_INVALID || - fu_device_get_specialized_gtype (FU_DEVICE (device)) != G_TYPE_INVALID) { - if (!fu_plugin_udev_device_changed (self, device, error)) - return FALSE; - } + g_module_symbol (priv->module, "fu_plugin_backend_device_changed", (gpointer *) &func); + if (func == NULL) return TRUE; - } - g_debug ("performing udev_device_changed() on %s", priv->name); + g_debug ("udev_device_changed(%s)", fu_plugin_get_name (self)); if (!func (self, device, &error_local)) { if (error_local == NULL) { - g_critical ("unset error in plugin %s for udev_device_changed()", - priv->name); + g_critical ("unset plugin error in udev_device_changed(%s)", + fu_plugin_get_name (self)); g_set_error_literal (&error_local, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -1904,13 +2074,42 @@ } g_propagate_prefixed_error (error, g_steal_pointer (&error_local), "failed to change device on %s: ", - priv->name); + fu_plugin_get_name (self)); return FALSE; } return TRUE; } /** + * fu_plugin_runner_device_added: + * @self: a #FuPlugin + * @device: a #FuDevice + * + * Call the device_added routine for the plugin + * + * Since: 1.5.0 + **/ +void +fu_plugin_runner_device_added (FuPlugin *self, FuDevice *device) +{ + FuPluginPrivate *priv = GET_PRIVATE (self); + FuPluginDeviceRegisterFunc func = NULL; + + /* not enabled */ + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) + return; + if (priv->module == NULL) + return; + + /* optional */ + g_module_symbol (priv->module, "fu_plugin_device_added", (gpointer *) &func); + if (func == NULL) + return; + g_debug ("fu_plugin_device_added(%s)", fu_plugin_get_name (self)); + func (self, device); +} + +/** * fu_plugin_runner_device_removed: * @self: a #FuPlugin * @device: a #FuDevice @@ -1925,7 +2124,7 @@ g_autoptr(GError) error_local= NULL; if (!fu_plugin_runner_device_generic (self, device, - "fu_plugin_device_removed", + "fu_plugin_backend_device_removed", NULL, &error_local)) g_warning ("%s", error_local->message); @@ -1947,19 +2146,15 @@ FuPluginDeviceRegisterFunc func = NULL; /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return; if (priv->module == NULL) return; - /* don't notify plugins on their own devices */ - if (g_strcmp0 (fu_device_get_plugin (device), fu_plugin_get_name (self)) == 0) - return; - /* optional */ g_module_symbol (priv->module, "fu_plugin_device_registered", (gpointer *) &func); if (func != NULL) { - g_debug ("performing fu_plugin_device_registered() on %s", priv->name); + g_debug ("fu_plugin_device_registered(%s)", fu_plugin_get_name (self)); func (self, device); } } @@ -1982,8 +2177,12 @@ FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginDeviceFunc func = NULL; + g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE); + g_return_val_if_fail (FU_IS_DEVICE (device), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return TRUE; if (priv->module == NULL) return TRUE; @@ -1992,7 +2191,7 @@ g_module_symbol (priv->module, "fu_plugin_device_created", (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("performing fu_plugin_device_created() on %s", priv->name); + g_debug ("fu_plugin_device_created(%s)", fu_plugin_get_name (self)); return func (self, device, error); } @@ -2020,8 +2219,12 @@ GPtrArray *checksums; g_autoptr(GError) error_local = NULL; + g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE); + g_return_val_if_fail (FU_IS_DEVICE (device), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return TRUE; /* no object loaded */ @@ -2031,6 +2234,14 @@ /* optional */ g_module_symbol (priv->module, "fu_plugin_verify", (gpointer *) &func); if (func == NULL) { + if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_CAN_VERIFY)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "device %s does not support verification", + fu_device_get_id (device)); + return FALSE; + } return fu_plugin_device_read_firmware (self, device, error); } @@ -2046,12 +2257,12 @@ return FALSE; /* run vfunc */ - g_debug ("performing verify() on %s", priv->name); + g_debug ("verify(%s)", fu_plugin_get_name (self)); if (!func (self, device, flags, &error_local)) { g_autoptr(GError) error_attach = NULL; if (error_local == NULL) { - g_critical ("unset error in plugin %s for verify()", - priv->name); + g_critical ("unset plugin error in verify(%s)", + fu_plugin_get_name (self)); g_set_error_literal (&error_local, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -2059,7 +2270,7 @@ } g_propagate_prefixed_error (error, g_steal_pointer (&error_local), "failed to verify using %s: ", - priv->name); + fu_plugin_get_name (self)); /* make the device "work" again, but don't prefix the error */ if (!fu_plugin_runner_device_generic (self, device, "fu_plugin_update_attach", @@ -2099,6 +2310,10 @@ { guint64 flags; + g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE); + g_return_val_if_fail (FU_IS_DEVICE (device), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + /* final check */ flags = fu_device_get_flags (device); if ((flags & FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION) == 0) { @@ -2119,6 +2334,12 @@ /* update with correct flags */ fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION); + + /* allow it to be updatable again */ + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN)) { + fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + } fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC); return TRUE; } @@ -2140,6 +2361,10 @@ { guint64 flags; + g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE); + g_return_val_if_fail (FU_IS_DEVICE (device), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + /* final check */ flags = fu_device_get_flags (device); if ((flags & FWUPD_DEVICE_FLAG_LOCKED) == 0) { @@ -2159,8 +2384,7 @@ return FALSE; /* update with correct flags */ - flags = fu_device_get_flags (device); - fu_device_set_flags (device, flags &= ~FWUPD_DEVICE_FLAG_LOCKED); + fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_LOCKED); fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC); return TRUE; } @@ -2190,8 +2414,12 @@ FuPluginUpdateFunc update_func; g_autoptr(GError) error_local = NULL; + g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE); + g_return_val_if_fail (FU_IS_DEVICE (device), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + /* not enabled */ - if (!priv->enabled) { + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) { g_debug ("plugin not enabled, skipping"); return TRUE; } @@ -2205,15 +2433,15 @@ /* optional */ g_module_symbol (priv->module, "fu_plugin_update", (gpointer *) &update_func); if (update_func == NULL) { - g_debug ("running superclassed write_firmware() on %s", priv->name); + g_debug ("superclassed write_firmware(%s)", fu_plugin_get_name (self)); return fu_plugin_device_write_firmware (self, device, blob_fw, flags, error); } /* online */ if (!update_func (self, device, blob_fw, flags, &error_local)) { if (error_local == NULL) { - g_critical ("unset error in plugin %s for update()", - priv->name); + g_critical ("unset plugin error in update(%s)", + fu_plugin_get_name (self)); g_set_error_literal (&error_local, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -2255,8 +2483,12 @@ FuPluginDeviceFunc func = NULL; g_autoptr(GError) error_local = NULL; + g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE); + g_return_val_if_fail (FU_IS_DEVICE (device), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return TRUE; /* no object loaded */ @@ -2267,11 +2499,11 @@ g_module_symbol (priv->module, "fu_plugin_clear_results", (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("performing clear_result() on %s", priv->name); + g_debug ("clear_result(%s)", fu_plugin_get_name (self)); if (!func (self, device, &error_local)) { if (error_local == NULL) { - g_critical ("unset error in plugin %s for clear_result()", - priv->name); + g_critical ("unset plugin error in clear_result(%s)", + fu_plugin_get_name (self)); g_set_error_literal (&error_local, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -2279,7 +2511,7 @@ } g_propagate_prefixed_error (error, g_steal_pointer (&error_local), "failed to clear_result using %s: ", - priv->name); + fu_plugin_get_name (self)); return FALSE; } return TRUE; @@ -2304,8 +2536,12 @@ FuPluginDeviceFunc func = NULL; g_autoptr(GError) error_local = NULL; + g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE); + g_return_val_if_fail (FU_IS_DEVICE (device), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + /* not enabled */ - if (!priv->enabled) + if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) return TRUE; /* no object loaded */ @@ -2316,11 +2552,11 @@ g_module_symbol (priv->module, "fu_plugin_get_results", (gpointer *) &func); if (func == NULL) return TRUE; - g_debug ("performing get_results() on %s", priv->name); + g_debug ("get_results(%s)", fu_plugin_get_name (self)); if (!func (self, device, &error_local)) { if (error_local == NULL) { - g_critical ("unset error in plugin %s for get_results()", - priv->name); + g_critical ("unset plugin error in get_results(%s)", + fu_plugin_get_name (self)); g_set_error_literal (&error_local, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -2328,7 +2564,7 @@ } g_propagate_prefixed_error (error, g_steal_pointer (&error_local), "failed to get_results using %s: ", - priv->name); + fu_plugin_get_name (self)); return FALSE; } return TRUE; @@ -2421,6 +2657,8 @@ fu_plugin_add_rule (FuPlugin *self, FuPluginRule rule, const gchar *name) { FuPluginPrivate *priv = fu_plugin_get_instance_private (self); + if (priv->rules[rule] == NULL) + priv->rules[rule] = g_ptr_array_new_with_free_func (g_free); g_ptr_array_add (priv->rules[rule], g_strdup (name)); g_signal_emit (self, signals[SIGNAL_RULES_CHANGED], 0); } @@ -2432,7 +2670,7 @@ * * Gets the plugin IDs that should be run after this plugin. * - * Returns: (element-type utf8) (transfer none): the list of plugin names, e.g. ['appstream'] + * Returns: (element-type utf8) (transfer none) (nullable): the list of plugin names, e.g. ['appstream'] * * Since: 1.0.0 **/ @@ -2460,6 +2698,8 @@ fu_plugin_has_rule (FuPlugin *self, FuPluginRule rule, const gchar *name) { FuPluginPrivate *priv = fu_plugin_get_instance_private (self); + if (priv->rules[rule] == NULL) + return FALSE; for (guint i = 0; i < priv->rules[rule]->len; i++) { const gchar *tmp = g_ptr_array_index (priv->rules[rule], i); if (g_strcmp0 (tmp, name) == 0) @@ -2486,6 +2726,12 @@ fu_plugin_add_report_metadata (FuPlugin *self, const gchar *key, const gchar *value) { FuPluginPrivate *priv = fu_plugin_get_instance_private (self); + if (priv->report_metadata == NULL) { + priv->report_metadata = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + g_free); + } g_hash_table_insert (priv->report_metadata, g_strdup (key), g_strdup (value)); } @@ -2495,7 +2741,7 @@ * * Returns the list of additional metadata to be added when filing a report. * - * Returns: (transfer none): the map of report metadata + * Returns: (transfer none) (nullable): the map of report metadata * * Since: 1.0.4 **/ @@ -2571,9 +2817,7 @@ gint fu_plugin_name_compare (FuPlugin *plugin1, FuPlugin *plugin2) { - FuPluginPrivate *priv1 = fu_plugin_get_instance_private (plugin1); - FuPluginPrivate *priv2 = fu_plugin_get_instance_private (plugin2); - return g_strcmp0 (priv1->name, priv2->name); + return g_strcmp0 (fu_plugin_get_name (plugin1), fu_plugin_get_name (plugin2)); } /** @@ -2628,6 +2872,12 @@ G_STRUCT_OFFSET (FuPluginClass, recoldplug), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + signals[SIGNAL_SECURITY_CHANGED] = + g_signal_new ("security-changed", + G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (FuPluginClass, security_changed), + NULL, NULL, g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); signals[SIGNAL_SET_COLDPLUG_DELAY] = g_signal_new ("set-coldplug-delay", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, @@ -2658,14 +2908,7 @@ fu_plugin_init (FuPlugin *self) { FuPluginPrivate *priv = GET_PRIVATE (self); - priv->enabled = TRUE; - priv->udev_subsystems = g_ptr_array_new_with_free_func (g_free); - priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, (GDestroyNotify) g_object_unref); - g_rw_lock_init (&priv->devices_mutex); - priv->report_metadata = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); - for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++) - priv->rules[i] = g_ptr_array_new_with_free_func (g_free); + g_rw_lock_init (&priv->cache_mutex); } static void @@ -2675,20 +2918,23 @@ FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginInitFunc func = NULL; + g_rw_lock_clear (&priv->cache_mutex); + /* optional */ if (priv->module != NULL) { g_module_symbol (priv->module, "fu_plugin_destroy", (gpointer *) &func); if (func != NULL) { - g_debug ("performing destroy() on %s", priv->name); + g_debug ("destroy(%s)", fu_plugin_get_name (self)); func (self); } } - for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++) - g_ptr_array_unref (priv->rules[i]); - - if (priv->usb_ctx != NULL) - g_object_unref (priv->usb_ctx); + for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++) { + if (priv->rules[i] != NULL) + g_ptr_array_unref (priv->rules[i]); + } + if (priv->devices != NULL) + g_ptr_array_unref (priv->devices); if (priv->hwids != NULL) g_object_unref (priv->hwids); if (priv->quirks != NULL) @@ -2701,18 +2947,20 @@ g_hash_table_unref (priv->runtime_versions); if (priv->compile_versions != NULL) g_hash_table_unref (priv->compile_versions); - g_hash_table_unref (priv->devices); - g_hash_table_unref (priv->report_metadata); - g_rw_lock_clear (&priv->devices_mutex); + if (priv->report_metadata != NULL) + g_hash_table_unref (priv->report_metadata); + if (priv->cache != NULL) + g_hash_table_unref (priv->cache); g_free (priv->build_hash); - g_free (priv->name); g_free (priv->data); /* Must happen as the last step to avoid prematurely * freeing memory held by the plugin */ -#ifndef RUNNING_ON_VALGRIND +#ifdef RUNNING_ON_VALGRIND + if (priv->module != NULL && RUNNING_ON_VALGRIND == 0) +#else if (priv->module != NULL) - g_module_close (priv->module); #endif + g_module_close (priv->module); G_OBJECT_CLASS (fu_plugin_parent_class)->finalize (object); } diff -Nru fwupd-1.4.5/libfwupdplugin/fu-plugin.h fwupd-1.5.8/libfwupdplugin/fu-plugin.h --- fwupd-1.4.5/libfwupdplugin/fu-plugin.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-plugin.h 2021-03-31 20:08:32.000000000 +0000 @@ -7,8 +7,11 @@ #pragma once #include +#ifdef HAVE_GUSB #include +#endif +#include "fu-bluez-device.h" #include "fu-common.h" #include "fu-common-guid.h" #include "fu-common-version.h" @@ -21,14 +24,20 @@ #ifdef HAVE_GUDEV #include "fu-udev-device.h" #endif -#include "fwupd-common.h" +#include +#include #define FU_TYPE_PLUGIN (fu_plugin_get_type ()) -G_DECLARE_DERIVABLE_TYPE (FuPlugin, fu_plugin, FU, PLUGIN, GObject) +G_DECLARE_DERIVABLE_TYPE (FuPlugin, fu_plugin, FU, PLUGIN, FwupdPlugin) + +#define fu_plugin_get_flags(p) fwupd_plugin_get_flags(FWUPD_PLUGIN(p)) +#define fu_plugin_has_flag(p,f) fwupd_plugin_has_flag(FWUPD_PLUGIN(p),f) +#define fu_plugin_add_flag(p,f) fwupd_plugin_add_flag(FWUPD_PLUGIN(p),f) +#define fu_plugin_remove_flag(p,f) fwupd_plugin_remove_flag(FWUPD_PLUGIN(p),f) struct _FuPluginClass { - GObjectClass parent_class; + FwupdPluginClass parent_class; /* signals */ void (* device_added) (FuPlugin *self, FuDevice *device); @@ -49,8 +58,9 @@ gboolean (* add_firmware_gtype) (FuPlugin *self, const gchar *id, GType gtype); + void (* security_changed) (FuPlugin *self); /*< private >*/ - gpointer padding[21]; + gpointer padding[20]; }; /** @@ -95,9 +105,11 @@ FuPluginData *fu_plugin_get_data (FuPlugin *self); FuPluginData *fu_plugin_alloc_data (FuPlugin *self, gsize data_sz); -gboolean fu_plugin_get_enabled (FuPlugin *self); +gboolean fu_plugin_get_enabled (FuPlugin *self) +G_DEPRECATED_FOR(fu_plugin_has_flag); void fu_plugin_set_enabled (FuPlugin *self, - gboolean enabled); + gboolean enabled) +G_DEPRECATED_FOR(fu_plugin_add_flag); void fu_plugin_set_build_hash (FuPlugin *self, const gchar *build_hash); GUsbContext *fu_plugin_get_usb_context (FuPlugin *self); @@ -108,6 +120,7 @@ void fu_plugin_device_register (FuPlugin *self, FuDevice *device); void fu_plugin_request_recoldplug (FuPlugin *self); +void fu_plugin_security_changed (FuPlugin *self); void fu_plugin_set_coldplug_delay (FuPlugin *self, guint duration); void fu_plugin_set_device_gtype (FuPlugin *self, @@ -115,6 +128,8 @@ void fu_plugin_add_firmware_gtype (FuPlugin *self, const gchar *id, GType gtype); +void fu_plugin_add_possible_quirk_key (FuPlugin *self, + const gchar *possible_key); gpointer fu_plugin_cache_lookup (FuPlugin *self, const gchar *id); void fu_plugin_cache_remove (FuPlugin *self, @@ -126,7 +141,9 @@ const gchar *hwid); gchar *fu_plugin_get_hwid_replace_value (FuPlugin *self, const gchar *keys, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +GPtrArray *fu_plugin_get_devices (FuPlugin *self); GPtrArray *fu_plugin_get_hwids (FuPlugin *self); const gchar *fu_plugin_get_dmi_value (FuPlugin *self, const gchar *dmi_id); diff -Nru fwupd-1.4.5/libfwupdplugin/fu-plugin-private.h fwupd-1.5.8/libfwupdplugin/fu-plugin-private.h --- fwupd-1.4.5/libfwupdplugin/fu-plugin-private.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-plugin-private.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2018 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -8,6 +8,7 @@ #include "fu-quirks.h" #include "fu-plugin.h" +#include "fu-security-attrs.h" #include "fu-smbios.h" FuPlugin *fu_plugin_new (void); @@ -43,52 +44,82 @@ GHashTable *fu_plugin_get_report_metadata (FuPlugin *self); gboolean fu_plugin_open (FuPlugin *self, const gchar *filename, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_plugin_runner_startup (FuPlugin *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_plugin_runner_coldplug (FuPlugin *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_plugin_runner_coldplug_prepare (FuPlugin *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_plugin_runner_coldplug_cleanup (FuPlugin *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_plugin_runner_recoldplug (FuPlugin *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_plugin_runner_update_prepare (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_plugin_runner_update_cleanup (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_plugin_runner_composite_prepare (FuPlugin *self, GPtrArray *devices, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_plugin_runner_composite_cleanup (FuPlugin *self, GPtrArray *devices, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_plugin_runner_update_attach (FuPlugin *self, FuDevice *device, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_plugin_runner_update_detach (FuPlugin *self, FuDevice *device, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_plugin_runner_update_reload (FuPlugin *self, FuDevice *device, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +G_DEPRECATED_FOR(fu_plugin_runner_backend_device_added) gboolean fu_plugin_runner_usb_device_added (FuPlugin *self, FuUsbDevice *device, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +G_DEPRECATED_FOR(fu_plugin_runner_backend_device_added) gboolean fu_plugin_runner_udev_device_added (FuPlugin *self, FuUdevDevice *device, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +G_DEPRECATED_FOR(fu_plugin_runner_backend_device_changed) gboolean fu_plugin_runner_udev_device_changed (FuPlugin *self, FuUdevDevice *device, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fu_plugin_runner_backend_device_added (FuPlugin *self, + FuDevice *device, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fu_plugin_runner_backend_device_changed (FuPlugin *self, + FuDevice *device, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_plugin_runner_device_created (FuPlugin *self, FuDevice *device, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fu_plugin_runner_device_added (FuPlugin *self, + FuDevice *device); void fu_plugin_runner_device_removed (FuPlugin *self, FuDevice *device); void fu_plugin_runner_device_register (FuPlugin *self, @@ -97,23 +128,30 @@ FuDevice *device, GBytes *blob_fw, FwupdInstallFlags flags, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_plugin_runner_verify (FuPlugin *self, FuDevice *device, FuPluginVerifyFlags flags, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_plugin_runner_activate (FuPlugin *self, FuDevice *device, GError **error); gboolean fu_plugin_runner_unlock (FuPlugin *self, FuDevice *device, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_plugin_runner_clear_results (FuPlugin *self, FuDevice *device, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_plugin_runner_get_results (FuPlugin *self, FuDevice *device, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +void fu_plugin_runner_add_security_attrs (FuPlugin *self, + FuSecurityAttrs*attrs); gint fu_plugin_name_compare (FuPlugin *plugin1, FuPlugin *plugin2); gint fu_plugin_order_compare (FuPlugin *plugin1, diff -Nru fwupd-1.4.5/libfwupdplugin/fu-plugin-vfuncs.h fwupd-1.5.8/libfwupdplugin/fu-plugin-vfuncs.h --- fwupd-1.4.5/libfwupdplugin/fu-plugin-vfuncs.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-plugin-vfuncs.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2017 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -8,6 +8,14 @@ #include "fu-plugin.h" #include "fu-device.h" +#include "fu-security-attrs.h" + +/* for in-tree plugins only */ +#ifdef FWUPD_COMPILATION +#include "fu-hash.h" +/* only until HSI is declared stable */ +#include "fwupd-security-attr-private.h" +#endif /** * SECTION:fu-plugin-vfuncs @@ -273,61 +281,59 @@ GPtrArray *devices, GError **error); /** - * fu_plugin_usb_device_added + * fu_plugin_backend_device_added * @plugin: A #FuPlugin - * @device: A #FuUsbDevice + * @device: A #FuDevice * @error: A #GError or NULL * - * Function run after USB device added to daemon. + * Function to run after a device is added by a backend, e.g. by USB or Udev. * - * Since: 1.0.2 + * Since: 1.5.6 **/ -gboolean fu_plugin_usb_device_added (FuPlugin *plugin, - FuUsbDevice *device, +gboolean fu_plugin_backend_device_added (FuPlugin *plugin, + FuDevice *device, GError **error); /** - * fu_plugin_udev_device_added + * fu_plugin_backend_device_changed * @plugin: A #FuPlugin - * @device: A #FuUdevDevice + * @device: A #FuDevice * @error: A #GError or NULL * - * Function run after Udev device added to daemon. + * Function run when the device changed. * - * Since: 1.1.2 + * Since: 1.5.6 **/ -gboolean fu_plugin_udev_device_added (FuPlugin *plugin, - FuUdevDevice *device, +gboolean fu_plugin_backend_device_changed (FuPlugin *plugin, + FuDevice *device, GError **error); /** - * fu_plugin_udev_device_changed + * fu_plugin_backend_device_removed * @plugin: A #FuPlugin - * @device: A #FuUdevDevice + * @device: A #FuDevice * @error: A #GError or NULL * - * Function run when Udev device changed. + * Function to run when device is physically removed. * - * Since: 1.1.2 + * Since: 1.5.6 **/ -gboolean fu_plugin_udev_device_changed (FuPlugin *plugin, - FuUdevDevice *device, +gboolean fu_plugin_backend_device_removed (FuPlugin *plugin, + FuDevice *device, GError **error); /** - * fu_plugin_device_removed + * fu_plugin_device_added * @plugin: A #FuPlugin - * @device: A #FuDevice - * @error: A #GError or NULL + * @dev: A #FuDevice * - * Function run when device removed. + * Function run when the subclassed device has been added. * - * Since: 1.1.2 + * Since: 1.5.0 **/ -gboolean fu_plugin_device_removed (FuPlugin *plugin, - FuDevice *device, - GError **error); +void fu_plugin_device_added (FuPlugin *plugin, + FuDevice *dev); /** * fu_plugin_device_created * @plugin: A #FuPlugin - * @device: A #FuDevice + * @dev: A #FuDevice * @error: A #GError or %NULL * * Function run when the subclassed device has been created. @@ -340,7 +346,7 @@ /** * fu_plugin_device_registered * @plugin: A #FuPlugin - * @device: A #FuDevice + * @dev: A #FuDevice * * Function run when device registered from another plugin. * @@ -348,3 +354,14 @@ **/ void fu_plugin_device_registered (FuPlugin *plugin, FuDevice *dev); +/** + * fu_plugin_add_security_attrs + * @plugin: A #FuPlugin + * @attrs: A #FuSecurityAttrs + * + * Function that asks plugins to add Host Security Attributes. + * + * Since: 1.5.0 + **/ +void fu_plugin_add_security_attrs (FuPlugin *plugin, + FuSecurityAttrs *attrs); diff -Nru fwupd-1.4.5/libfwupdplugin/fu-quirks.c fwupd-1.5.8/libfwupdplugin/fu-quirks.c --- fwupd-1.4.5/libfwupdplugin/fu-quirks.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-quirks.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -25,7 +25,7 @@ * SECTION:fu-quirks * @short_description: device quirks * - * Quirks can be used to modify device behaviour. + * Quirks can be used to modify device behavior. * When fwupd is installed in long-term support distros it's very hard to * backport new versions as new hardware is released. * @@ -52,6 +52,8 @@ { GObject parent_instance; FuQuirksLoadFlags load_flags; + GHashTable *possible_keys; + GPtrArray *invalid_keys; XbSilo *silo; }; @@ -66,6 +68,8 @@ for (guint i = 0; guid_prefixes[i] != NULL; i++) { if (g_str_has_prefix (group, guid_prefixes[i])) { gsize len = strlen (guid_prefixes[i]); + g_warning ("using %s in quirk files is deprecated!", + guid_prefixes[i]); if (fwupd_guid_is_valid (group + len)) return g_strdup (group + len); return fwupd_guid_hash_string (group + len); @@ -73,16 +77,19 @@ } /* fallback */ - return g_strdup (group); + if (fwupd_guid_is_valid (group)) + return g_strdup (group); + return fwupd_guid_hash_string (group); } static GInputStream * -fu_quirks_convert_quirk_to_xml_cb (XbBuilderSource *self, +fu_quirks_convert_quirk_to_xml_cb (XbBuilderSource *source, XbBuilderSourceCtx *ctx, gpointer user_data, GCancellable *cancellable, GError **error) { + FuQuirks *self = FU_QUIRKS (user_data); g_autofree gchar *xml = NULL; g_auto(GStrv) groups = NULL; g_autoptr(GBytes) bytes = NULL; @@ -106,6 +113,16 @@ g_auto(GStrv) keys = NULL; g_autofree gchar *group_id = NULL; g_autoptr(XbBuilderNode) bn = NULL; + + /* sanity check group */ + if (g_str_has_prefix (groups[i], "HwID") || + g_str_has_prefix (groups[i], "DeviceInstanceID") || + g_str_has_prefix (groups[i], "GUID")) { + g_warning ("invalid group name '%s'", groups[i]); + continue; + } + + /* get all KVs for the entry */ keys = g_key_file_get_keys (kf, groups[i], NULL, error); if (keys == NULL) return NULL; @@ -113,6 +130,17 @@ bn = xb_builder_node_insert (root, "device", "id", group_id, NULL); for (guint j = 0; keys[j] != NULL; j++) { g_autofree gchar *value = NULL; + + /* sanity check key */ + if (g_hash_table_lookup (self->possible_keys, keys[j]) == NULL) { + if (!g_ptr_array_find_with_equal_func (self->invalid_keys, + keys[j], + g_str_equal, + NULL)) { + g_ptr_array_add (self->invalid_keys, + g_strdup (keys[j])); + } + } value = g_key_file_get_value (kf, groups[i], keys[j], error); if (value == NULL) return NULL; @@ -149,10 +177,8 @@ /* add valid files to the array */ path_hw = g_build_filename (path, "quirks.d", NULL); - if (!g_file_test (path_hw, G_FILE_TEST_EXISTS)) { - g_debug ("no %s, skipping", path_hw); + if (!g_file_test (path_hw, G_FILE_TEST_EXISTS)) return TRUE; - } dir = g_dir_open (path_hw, 0, error); if (dir == NULL) return FALSE; @@ -177,11 +203,11 @@ #if LIBXMLB_CHECK_VERSION(0,1,15) xb_builder_source_add_simple_adapter (source, "text/plain,.quirk", fu_quirks_convert_quirk_to_xml_cb, - NULL, NULL); + self, NULL); #else xb_builder_source_add_adapter (source, "text/plain,.quirk", fu_quirks_convert_quirk_to_xml_cb, - NULL, NULL); + self, NULL); #endif if (!xb_builder_source_load_file (source, file, XB_BUILDER_SOURCE_FLAG_WATCH_FILE | @@ -199,6 +225,14 @@ return TRUE; } +static gint +fu_quirks_strcasecmp_cb (gconstpointer a, gconstpointer b) +{ + const gchar *entry1 = *((const gchar **) a); + const gchar *entry2 = *((const gchar **) b); + return g_ascii_strcasecmp (entry1, entry2); +} + static gboolean fu_quirks_check_silo (FuQuirks *self, GError **error) { @@ -229,7 +263,7 @@ cachedirpkg = fu_common_get_path (FU_PATH_KIND_CACHEDIR_PKG); xmlbfn = g_build_filename (cachedirpkg, "quirks.xmlb", NULL); file = g_file_new_for_path (xmlbfn); - if (g_getenv ("XMLB_VERBOSE") != NULL) { + if (g_getenv ("FWUPD_XMLB_VERBOSE") != NULL) { xb_builder_set_profile_flags (builder, XB_SILO_PROFILE_FLAG_XPATH | XB_SILO_PROFILE_FLAG_DEBUG); @@ -237,7 +271,19 @@ if (self->load_flags & FU_QUIRKS_LOAD_FLAG_READONLY_FS) compile_flags |= XB_BUILDER_COMPILE_FLAG_IGNORE_GUID; self->silo = xb_builder_ensure (builder, file, compile_flags, NULL, error); - return self->silo != NULL; + if (self->silo == NULL) + return FALSE; + + /* dump warnings to console, just once */ + if (self->invalid_keys->len > 0) { + g_autofree gchar *str = NULL; + g_ptr_array_sort (self->invalid_keys, fu_quirks_strcasecmp_cb); + str = fu_common_strjoin_array (",", self->invalid_keys); + g_warning ("invalid key names: %s", str); + } + + /* success */ + return TRUE; } /** @@ -259,6 +305,9 @@ g_autoptr(GError) error = NULL; g_autoptr(XbNode) n = NULL; g_autoptr(XbQuery) query = NULL; +#if LIBXMLB_CHECK_VERSION(0,3,0) + g_auto(XbQueryContext) context = XB_QUERY_CONTEXT_INIT (); +#endif g_return_val_if_fail (FU_IS_QUIRKS (self), NULL); g_return_val_if_fail (group != NULL, NULL); @@ -284,6 +333,12 @@ g_warning ("failed to build query: %s", error->message); return NULL; } + +#if LIBXMLB_CHECK_VERSION(0,3,0) + xb_value_bindings_bind_str (xb_query_context_get_bindings (&context), 0, group_key, NULL); + xb_value_bindings_bind_str (xb_query_context_get_bindings (&context), 1, key, NULL); + n = xb_silo_query_first_with_context (self->silo, query, &context, &error); +#else if (!xb_query_bind_str (query, 0, group_key, &error)) { g_warning ("failed to bind 0: %s", error->message); return NULL; @@ -293,6 +348,8 @@ return NULL; } n = xb_silo_query_first_full (self->silo, query, &error); +#endif + if (n == NULL) { if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) return NULL; @@ -325,6 +382,9 @@ g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) results = NULL; g_autoptr(XbQuery) query = NULL; +#if LIBXMLB_CHECK_VERSION(0,3,0) + g_auto(XbQueryContext) context = XB_QUERY_CONTEXT_INIT (); +#endif g_return_val_if_fail (FU_IS_QUIRKS (self), FALSE); g_return_val_if_fail (group != NULL, FALSE); @@ -350,11 +410,18 @@ g_warning ("failed to build query: %s", error->message); return FALSE; } + +#if LIBXMLB_CHECK_VERSION(0,3,0) + xb_value_bindings_bind_str (xb_query_context_get_bindings (&context), 0, group_key, NULL); + results = xb_silo_query_with_context (self->silo, query, &context, &error); +#else if (!xb_query_bind_str (query, 0, group_key, &error)) { g_warning ("failed to bind 0: %s", error->message); return FALSE; } results = xb_silo_query_full (self->silo, query, &error); +#endif + if (results == NULL) { if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) return FALSE; @@ -389,10 +456,29 @@ fu_quirks_load (FuQuirks *self, FuQuirksLoadFlags load_flags, GError **error) { g_return_val_if_fail (FU_IS_QUIRKS (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); self->load_flags = load_flags; return fu_quirks_check_silo (self, error); } +/** + * fu_quirks_add_possible_key: + * @self: A #FuQuirks + * @possible_key: A key name, e.g. `Flags` + * + * Adds a possible quirk key. If added by a plugin it should be namespaced + * using the plugin name, where possible. + * + * Since: 1.5.8 + **/ +void +fu_quirks_add_possible_key (FuQuirks *self, const gchar *possible_key) +{ + g_return_if_fail (FU_IS_QUIRKS (self)); + g_return_if_fail (possible_key != NULL); + g_hash_table_add (self->possible_keys, g_strdup (possible_key)); +} + static void fu_quirks_class_init (FuQuirksClass *klass) { @@ -403,6 +489,35 @@ static void fu_quirks_init (FuQuirks *self) { + self->possible_keys = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + self->invalid_keys = g_ptr_array_new_with_free_func (g_free); + + /* built in */ + fu_quirks_add_possible_key (self, FU_QUIRKS_BRANCH); + fu_quirks_add_possible_key (self, FU_QUIRKS_CHILDREN); + fu_quirks_add_possible_key (self, FU_QUIRKS_COUNTERPART_GUID); + fu_quirks_add_possible_key (self, FU_QUIRKS_FIRMWARE_SIZE); + fu_quirks_add_possible_key (self, FU_QUIRKS_FIRMWARE_SIZE_MAX); + fu_quirks_add_possible_key (self, FU_QUIRKS_FIRMWARE_SIZE_MIN); + fu_quirks_add_possible_key (self, FU_QUIRKS_FLAGS); + fu_quirks_add_possible_key (self, FU_QUIRKS_GTYPE); + fu_quirks_add_possible_key (self, FU_QUIRKS_GUID); + fu_quirks_add_possible_key (self, FU_QUIRKS_ICON); + fu_quirks_add_possible_key (self, FU_QUIRKS_INSTALL_DURATION); + fu_quirks_add_possible_key (self, FU_QUIRKS_NAME); + fu_quirks_add_possible_key (self, FU_QUIRKS_PARENT_GUID); + fu_quirks_add_possible_key (self, FU_QUIRKS_PLUGIN); + fu_quirks_add_possible_key (self, FU_QUIRKS_PRIORITY); + fu_quirks_add_possible_key (self, FU_QUIRKS_PROTOCOL); + fu_quirks_add_possible_key (self, FU_QUIRKS_PROXY_GUID); + fu_quirks_add_possible_key (self, FU_QUIRKS_REMOVE_DELAY); + fu_quirks_add_possible_key (self, FU_QUIRKS_SUMMARY); + fu_quirks_add_possible_key (self, FU_QUIRKS_UPDATE_IMAGE); + fu_quirks_add_possible_key (self, FU_QUIRKS_UPDATE_MESSAGE); + fu_quirks_add_possible_key (self, FU_QUIRKS_VENDOR); + fu_quirks_add_possible_key (self, FU_QUIRKS_VENDOR_ID); + fu_quirks_add_possible_key (self, FU_QUIRKS_VERSION); + fu_quirks_add_possible_key (self, FU_QUIRKS_VERSION_FORMAT); } static void @@ -411,6 +526,8 @@ FuQuirks *self = FU_QUIRKS (obj); if (self->silo != NULL) g_object_unref (self->silo); + g_hash_table_unref (self->possible_keys); + g_ptr_array_unref (self->invalid_keys); G_OBJECT_CLASS (fu_quirks_parent_class)->finalize (obj); } diff -Nru fwupd-1.4.5/libfwupdplugin/fu-quirks.h fwupd-1.5.8/libfwupdplugin/fu-quirks.h --- fwupd-1.4.5/libfwupdplugin/fu-quirks.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-quirks.h 2021-03-31 20:08:32.000000000 +0000 @@ -34,7 +34,8 @@ FuQuirks *fu_quirks_new (void); gboolean fu_quirks_load (FuQuirks *self, FuQuirksLoadFlags load_flags, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; const gchar *fu_quirks_lookup_by_id (FuQuirks *self, const gchar *group, const gchar *key); @@ -42,12 +43,15 @@ const gchar *group, FuQuirksIter iter_cb, gpointer user_data); +void fu_quirks_add_possible_key (FuQuirks *self, + const gchar *possible_key); #define FU_QUIRKS_PLUGIN "Plugin" #define FU_QUIRKS_FLAGS "Flags" #define FU_QUIRKS_SUMMARY "Summary" #define FU_QUIRKS_ICON "Icon" #define FU_QUIRKS_NAME "Name" +#define FU_QUIRKS_BRANCH "Branch" #define FU_QUIRKS_GUID "Guid" #define FU_QUIRKS_COUNTERPART_GUID "CounterpartGuid" #define FU_QUIRKS_PARENT_GUID "ParentGuid" diff -Nru fwupd-1.4.5/libfwupdplugin/fu-security-attrs.c fwupd-1.5.8/libfwupdplugin/fu-security-attrs.c --- fwupd-1.4.5/libfwupdplugin/fu-security-attrs.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-security-attrs.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,334 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuSecurityAttrs" + +#include "config.h" + +#include + +#include "fu-security-attrs.h" +#include "fu-security-attrs-private.h" +#include "fwupd-security-attr-private.h" + +struct _FuSecurityAttrs { + GObject parent_instance; + GPtrArray *attrs; +}; + +/* probably sane to *not* make this part of the ABI */ +#define FWUPD_SECURITY_ATTR_ID_DOC_URL "https://fwupd.github.io/hsi.html" + +G_DEFINE_TYPE (FuSecurityAttrs, fu_security_attrs, G_TYPE_OBJECT) + +static void +fu_security_attrs_finalize (GObject *obj) +{ + FuSecurityAttrs *self = FU_SECURITY_ATTRS (obj); + g_ptr_array_unref (self->attrs); + G_OBJECT_CLASS (fu_security_attrs_parent_class)->finalize (obj); +} + +static void +fu_security_attrs_class_init (FuSecurityAttrsClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fu_security_attrs_finalize; +} + +static void +fu_security_attrs_init (FuSecurityAttrs *self) +{ + self->attrs = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); +} + +/** + * fu_security_attrs_append: + * @self: A #FuSecurityAttrs + * @attr: a #FwupdSecurityAttr + * + * Adds a #FwupdSecurityAttr to the array. + * + * Since: 1.5.0 + **/ +void +fu_security_attrs_append (FuSecurityAttrs *self, FwupdSecurityAttr *attr) +{ + g_return_if_fail (FU_IS_SECURITY_ATTRS (self)); + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (attr)); + + /* sanity check */ + if (fwupd_security_attr_get_plugin (attr) == NULL) { + g_warning ("%s has no plugin set", + fwupd_security_attr_get_appstream_id (attr)); + } + + /* sanity check, and correctly prefix the URLs with the current mirror */ + if (fwupd_security_attr_get_url (attr) == NULL) { + g_autofree gchar *url = NULL; + url = g_strdup_printf ("%s#%s", + FWUPD_SECURITY_ATTR_ID_DOC_URL, + fwupd_security_attr_get_appstream_id (attr)); + fwupd_security_attr_set_url (attr, url); + } else if (g_str_has_prefix (fwupd_security_attr_get_url (attr), "#")) { + g_autofree gchar *url = NULL; + url = g_strdup_printf ("%s%s", + FWUPD_SECURITY_ATTR_ID_DOC_URL, + fwupd_security_attr_get_url (attr)); + fwupd_security_attr_set_url (attr, url); + } + g_ptr_array_add (self->attrs, g_object_ref (attr)); +} + +/** + * fu_security_attrs_to_variant: + * @self: A #FuSecurityAttrs + * + * Converts the #FwupdSecurityAttr objects into a variant array. + * + * Returns: a #GVariant or %NULL + * + * Since: 1.5.0 + **/ +GVariant * +fu_security_attrs_to_variant (FuSecurityAttrs *self) +{ + GVariantBuilder builder; + + g_return_val_if_fail (FU_IS_SECURITY_ATTRS (self), NULL); + g_return_val_if_fail (self->attrs->len > 0, NULL); + g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); + + for (guint i = 0; i < self->attrs->len; i++) { + FwupdSecurityAttr *security_attr = g_ptr_array_index (self->attrs, i); + GVariant *tmp = fwupd_security_attr_to_variant (security_attr); + g_variant_builder_add_value (&builder, tmp); + } + return g_variant_new ("(aa{sv})", &builder); +} + +/** + * fu_security_attrs_get_all: + * @self: A #FuSecurityAttrs + * + * Gets all the attributes in the object. + * + * Returns: (transfer container) (element-type FwupdSecurityAttr): attributes + * + * Since: 1.5.0 + **/ +GPtrArray * +fu_security_attrs_get_all (FuSecurityAttrs *self) +{ + g_return_val_if_fail (FU_IS_SECURITY_ATTRS (self), NULL); + return g_ptr_array_ref (self->attrs); +} + +/** + * fu_security_attrs_remove_all: + * @self: A #FuSecurityAttrs + * + * Removes all the attributes in the object. + * + * Since: 1.5.0 + **/ +void +fu_security_attrs_remove_all (FuSecurityAttrs *self) +{ + g_return_if_fail (FU_IS_SECURITY_ATTRS (self)); + return g_ptr_array_set_size (self->attrs, 0); +} + +/** + * fu_security_attrs_calculate_hsi: + * @self: A #FuSecurityAttrs + * @flags: Flags to use while calcuating the HSI + * + * Calculates the HSI string from the appended attributes. + * + * Returns: (transfer full): a string or %NULL + * + * Since: 1.5.0 + **/ +gchar * +fu_security_attrs_calculate_hsi (FuSecurityAttrs *self, + FuSecurityAttrsFlags flags) +{ + guint hsi_number = 0; + FwupdSecurityAttrFlags attr_flags = FWUPD_SECURITY_ATTR_FLAG_NONE; + GString *str = g_string_new ("HSI:"); + const FwupdSecurityAttrFlags hpi_suffixes[] = { + FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE, + FWUPD_SECURITY_ATTR_FLAG_NONE, + }; + + g_return_val_if_fail (FU_IS_SECURITY_ATTRS (self), NULL); + + /* find the highest HSI number where there are no failures and at least + * one success */ + for (guint j = 1; j <= FWUPD_SECURITY_ATTR_LEVEL_LAST; j++) { + gboolean success_cnt = 0; + gboolean failure_cnt = 0; + for (guint i = 0; i < self->attrs->len; i++) { + FwupdSecurityAttr *attr = g_ptr_array_index (self->attrs, i); + if (fwupd_security_attr_get_level (attr) != j) + continue; + if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) + success_cnt++; + else if (!fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)) + failure_cnt++; + } + + /* abort */ + if (failure_cnt > 0) { + hsi_number = j - 1; + break; + } + + /* we matched at least one thing on this level */ + if (success_cnt > 0) + hsi_number = j; + } + + /* get a logical OR of the runtime flags */ + for (guint i = 0; i < self->attrs->len; i++) { + FwupdSecurityAttr *attr = g_ptr_array_index (self->attrs, i); + if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)) + continue; + if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE) && + fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) + continue; + attr_flags |= fwupd_security_attr_get_flags (attr); + } + + g_string_append_printf (str, "%u", hsi_number); + if (attr_flags & FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE) { + for (guint j = 0; hpi_suffixes[j] != FWUPD_SECURITY_ATTR_FLAG_NONE; j++) { + if (attr_flags & hpi_suffixes[j]) + g_string_append (str, fwupd_security_attr_flag_to_suffix (hpi_suffixes[j])); + } + } + + if (flags & FU_SECURITY_ATTRS_FLAG_ADD_VERSION) { + g_string_append_printf (str, " (v%d.%d.%d)", + FWUPD_MAJOR_VERSION, + FWUPD_MINOR_VERSION, + FWUPD_MICRO_VERSION); + } + + return g_string_free (str, FALSE); +} + +static gchar * +fu_security_attrs_get_sort_key (FwupdSecurityAttr *attr) +{ + GString *str = g_string_new (NULL); + + /* level */ + g_string_append_printf (str, "%u", fwupd_security_attr_get_level (attr)); + + /* success -> fail -> obsoletes */ + if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) { + g_string_append (str, "0"); + } else if (!fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS) && + !fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)) { + g_string_append (str, "1"); + } else { + g_string_append (str, "9"); + } + + /* prefer name, but fallback to appstream-id for tests */ + if (fwupd_security_attr_get_name (attr) != NULL) { + g_string_append (str, fwupd_security_attr_get_name (attr)); + } else { + g_string_append (str, fwupd_security_attr_get_appstream_id (attr)); + } + return g_string_free (str, FALSE); +} + +static gint +fu_security_attrs_sort_cb (gconstpointer item1, gconstpointer item2) +{ + FwupdSecurityAttr *attr1 = *((FwupdSecurityAttr **) item1); + FwupdSecurityAttr *attr2 = *((FwupdSecurityAttr **) item2); + g_autofree gchar *sort1 = fu_security_attrs_get_sort_key (attr1); + g_autofree gchar *sort2 = fu_security_attrs_get_sort_key (attr2); + return g_strcmp0 (sort1, sort2); +} + +/** + * fu_security_attrs_depsolve: + * @self: A #FuSecurityAttrs + * + * Marks any attributes with %FWUPD_SECURITY_ATTR_FLAG_OBSOLETED that have been + * defined as obsoleted by other attributes. + * + * It is only required to call this function once, and should be done when all + * attributes have been added. This will also sort the attrs. + * + * Since: 1.5.0 + **/ +void +fu_security_attrs_depsolve (FuSecurityAttrs *self) +{ + g_autoptr(GHashTable) attrs_by_id = NULL; + + g_return_if_fail (FU_IS_SECURITY_ATTRS (self)); + + /* make hash of ID -> object */ + attrs_by_id = g_hash_table_new (g_str_hash, g_str_equal); + for (guint i = 0; i < self->attrs->len; i++) { + FwupdSecurityAttr *attr = g_ptr_array_index (self->attrs, i); + g_hash_table_insert (attrs_by_id, + (gpointer) fwupd_security_attr_get_appstream_id (attr), + (gpointer) attr); + } + + /* set flat where required */ + for (guint i = 0; i < self->attrs->len; i++) { + FwupdSecurityAttr *attr = g_ptr_array_index (self->attrs, i); + GPtrArray *obsoletes = fwupd_security_attr_get_obsoletes (attr); + for (guint j = 0; j < obsoletes->len; j++) { + const gchar *obsolete = g_ptr_array_index (obsoletes, j); + FwupdSecurityAttr *attr_tmp = g_hash_table_lookup (attrs_by_id, obsolete); + + /* by AppStream ID */ + if (attr_tmp != NULL) { + g_debug ("security attr %s obsoleted by %s", obsolete, + fwupd_security_attr_get_appstream_id (attr_tmp)); + fwupd_security_attr_add_flag (attr_tmp, + FWUPD_SECURITY_ATTR_FLAG_OBSOLETED); + } + + /* by plugin name */ + for (guint k = 0; k < self->attrs->len; k++) { + attr_tmp = g_ptr_array_index (self->attrs, k); + if (g_strcmp0 (obsolete, fwupd_security_attr_get_plugin (attr_tmp)) == 0) { + g_debug ("security attr %s obsoleted by %s", obsolete, + fwupd_security_attr_get_appstream_id (attr_tmp)); + fwupd_security_attr_add_flag (attr_tmp, + FWUPD_SECURITY_ATTR_FLAG_OBSOLETED); + } + } + } + } + + /* sort */ + g_ptr_array_sort (self->attrs, fu_security_attrs_sort_cb); +} + +/** + * fu_security_attrs_new: + * + * Returns: a #FuSecurityAttrs + * + * Since: 1.5.0 + **/ +FuSecurityAttrs * +fu_security_attrs_new (void) +{ + return g_object_new (FU_TYPE_SECURITY_ATTRS, NULL); +} diff -Nru fwupd-1.4.5/libfwupdplugin/fu-security-attrs.h fwupd-1.5.8/libfwupdplugin/fu-security-attrs.h --- fwupd-1.4.5/libfwupdplugin/fu-security-attrs.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-security-attrs.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include +#include + +#define FU_TYPE_SECURITY_ATTRS (fu_security_attrs_get_type ()) + +G_DECLARE_FINAL_TYPE (FuSecurityAttrs, fu_security_attrs, FU, SECURITY_ATTRS, GObject) + +void fu_security_attrs_append (FuSecurityAttrs *self, + FwupdSecurityAttr *attr); +void fu_security_attrs_remove_all (FuSecurityAttrs *self); diff -Nru fwupd-1.4.5/libfwupdplugin/fu-security-attrs-private.h fwupd-1.5.8/libfwupdplugin/fu-security-attrs-private.h --- fwupd-1.4.5/libfwupdplugin/fu-security-attrs-private.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-security-attrs-private.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +/** + * FuSecurityAttrsFlags: + * @FU_SECURITY_ATTRS_FLAG_NONE: No flags set + * @FU_SECURITY_ATTRS_FLAG_ADD_VERSION: Add the daemon version to the HSI string + * + * The flags to use when calculating an HSI version. + **/ +typedef enum { + FU_SECURITY_ATTRS_FLAG_NONE = 0, + FU_SECURITY_ATTRS_FLAG_ADD_VERSION = 1 << 0, + /*< private >*/ + FU_SECURITY_ATTRS_FLAG_LAST +} FuSecurityAttrsFlags; + +#include "fu-security-attrs.h" + +FuSecurityAttrs *fu_security_attrs_new (void); +gchar *fu_security_attrs_calculate_hsi (FuSecurityAttrs *self, + FuSecurityAttrsFlags flags); +void fu_security_attrs_depsolve (FuSecurityAttrs *self); +GVariant *fu_security_attrs_to_variant (FuSecurityAttrs *self); +GPtrArray *fu_security_attrs_get_all (FuSecurityAttrs *self); diff -Nru fwupd-1.4.5/libfwupdplugin/fu-self-test.c fwupd-1.5.8/libfwupdplugin/fu-self-test.c --- fwupd-1.4.5/libfwupdplugin/fu-self-test.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-self-test.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,11 +1,12 @@ /* - * Copyright (C) 2015-2018 Richard Hughes + * Copyright (C) 2015 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" +#include #include #include #include @@ -14,7 +15,9 @@ #include "fu-device-private.h" #include "fu-plugin-private.h" +#include "fu-security-attrs-private.h" #include "fu-smbios-private.h" +#include "fwupd-security-attr-private.h" static GMainLoop *_test_loop = NULL; static guint _test_loop_timeout_id = 0; @@ -59,6 +62,11 @@ g_autoptr(GBytes) data = NULL; g_autoptr(GError) error = NULL; +#ifndef HAVE_LIBARCHIVE + g_test_skip ("no libarchive support"); + return; +#endif + filename = g_build_filename (TESTDATADIR_SRC, "metadata.xml", NULL); data = fu_common_get_contents_bytes (filename, &error); g_assert_no_error (error); @@ -80,6 +88,11 @@ g_autoptr(GError) error = NULL; GBytes *data_tmp; +#ifndef HAVE_LIBARCHIVE + g_test_skip ("no libarchive support"); + return; +#endif + filename = g_build_filename (TESTDATADIR_DST, "colorhug", "colorhug-als-3.0.2.cab", NULL); data = fu_common_get_contents_bytes (filename, &error); g_assert_no_error (error); @@ -107,6 +120,33 @@ } static void +fu_common_byte_array_func (void) +{ + g_autoptr(GByteArray) array = g_byte_array_new (); + + fu_byte_array_append_uint8 (array, (guint8) 'h'); + fu_byte_array_append_uint8 (array, (guint8) 'e'); + fu_byte_array_append_uint8 (array, (guint8) 'l'); + fu_byte_array_append_uint8 (array, (guint8) 'l'); + fu_byte_array_append_uint8 (array, (guint8) 'o'); + g_assert_cmpint (array->len, ==, 5); + g_assert_cmpint (memcmp (array->data, "hello", array->len), ==, 0); + + fu_byte_array_set_size (array, 10); + g_assert_cmpint (array->len, ==, 10); + g_assert_cmpint (memcmp (array->data, "hello\0\0\0\0\0", array->len), ==, 0); +} + +static void +fu_common_crc_func (void) +{ + guint8 buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09 }; + g_assert_cmpint (fu_common_crc8 (buf, sizeof(buf)), ==, 0x7A); + g_assert_cmpint (fu_common_crc16 (buf, sizeof(buf)), ==, 0x4DF1); + g_assert_cmpint (fu_common_crc32 (buf, sizeof(buf)), ==, 0x40EFAB9E); +} + +static void fu_common_string_append_kv_func (void) { g_autoptr(GString) str = g_string_new (NULL); @@ -118,11 +158,11 @@ fu_common_string_append_kv (str, 2, "key3", "value3"); g_assert_cmpstr (str->str, ==, "hdr:\n" - "key: value\n" - "key1: value1\n" - " key2: value2\n" - " value2\n" - " key3: value3\n"); + "key: value\n" + "key1: value1\n" + " key2: value2\n" + " value2\n" + " key3: value3\n"); } static void @@ -144,7 +184,7 @@ fu_device_version_format_func (void) { g_autoptr(FuDevice) device = fu_device_new (); - fu_device_add_flag (device, FWUPD_DEVICE_FLAG_ENSURE_SEMVER); + fu_device_add_internal_flag (device, FU_DEVICE_INTERNAL_FLAG_ENSURE_SEMVER); fu_device_set_version_format (device, FWUPD_VERSION_FORMAT_TRIPLET); fu_device_set_version (device, "Ver1.2.3 RELEASE"); g_assert_cmpstr (fu_device_get_version (device), ==, "1.2.3"); @@ -193,14 +233,14 @@ g_assert_false (fu_device_get_metadata_boolean (device, "unknown")); /* integer */ - fu_device_set_metadata_integer (device, "dum", 12345); - g_assert_cmpstr (fu_device_get_metadata (device, "dum"), ==, "12345"); - g_assert_cmpint (fu_device_get_metadata_integer (device, "dum"), ==, 12345); + fu_device_set_metadata_integer (device, "bam", 12345); + g_assert_cmpstr (fu_device_get_metadata (device, "bam"), ==, "12345"); + g_assert_cmpint (fu_device_get_metadata_integer (device, "bam"), ==, 12345); g_assert_cmpint (fu_device_get_metadata_integer (device, "unknown"), ==, G_MAXUINT); /* broken integer */ - fu_device_set_metadata (device, "dum", "123junk"); - g_assert_cmpint (fu_device_get_metadata_integer (device, "dum"), ==, G_MAXUINT); + fu_device_set_metadata (device, "bam", "123junk"); + g_assert_cmpint (fu_device_get_metadata_integer (device, "bam"), ==, G_MAXUINT); fu_device_set_metadata (device, "huge", "4294967296"); /* not 32 bit */ g_assert_cmpint (fu_device_get_metadata_integer (device, "huge"), ==, G_MAXUINT); } @@ -266,6 +306,72 @@ } static void +fu_smbios_dt_func (void) +{ + const gchar *str; + gboolean ret; + g_autofree gchar *path = NULL; + g_autoptr(FuSmbios) smbios = NULL; + g_autoptr(GError) error = NULL; + + path = g_build_filename (TESTDATADIR_SRC, "devicetree", "base", NULL); + smbios = fu_smbios_new (); + ret = fu_smbios_setup_from_path (smbios, path, &error); + g_assert_no_error (error); + g_assert (ret); + if (g_getenv ("VERBOSE") != NULL) { + g_autofree gchar *dump = fu_smbios_to_string (smbios); + g_debug ("%s", dump); + } + + /* get vendor */ + str = fu_smbios_get_string (smbios, FU_SMBIOS_STRUCTURE_TYPE_SYSTEM, 0x04, &error); + g_assert_no_error (error); + g_assert_cmpstr (str, ==, "Hughski Limited"); +} + +static void +fu_common_strsafe_func (void) +{ + struct { + const gchar *in; + const gchar *op; + } strs[] = { + { "dave123", "dave123" }, + { "dave123XXX", "dave123" }, + { "dave\x03XXX", "dave.XX" }, + { "dave\x03\x04XXX", "dave..X" }, + { "\x03\x03", NULL }, + { NULL, NULL } + }; + for (guint i = 0; strs[i].in != NULL; i++) { + g_autofree gchar *tmp = fu_common_strsafe (strs[i].in, 7); + g_assert_cmpstr (tmp, ==, strs[i].op); + } +} + +static void +fu_common_uri_scheme_func (void) +{ + struct { + const gchar *in; + const gchar *op; + } strs[] = { + { "https://foo.bar/baz", "https" }, + { "HTTP://FOO.BAR/BAZ", "http" }, + { "ftp://", "ftp" }, + { "ftp:", "ftp" }, + { "foobarbaz", NULL }, + { "", NULL }, + { NULL, NULL } + }; + for (guint i = 0; strs[i].in != NULL; i++) { + g_autofree gchar *tmp = fu_common_uri_get_scheme (strs[i].in); + g_assert_cmpstr (tmp, ==, strs[i].op); + } +} + +static void fu_hwids_func (void) { g_autoptr(FuHwids) hwids = NULL; @@ -340,6 +446,24 @@ } static void +fu_plugin_devices_func (void) +{ + g_autoptr(FuDevice) device = fu_device_new (); + g_autoptr(FuPlugin) plugin = fu_plugin_new (); + GPtrArray *devices; + + devices = fu_plugin_get_devices (plugin); + g_assert_nonnull (devices); + g_assert_cmpint (devices->len, ==, 0); + + fu_device_set_id (device, "testdev"); + fu_plugin_device_add (plugin, device); + g_assert_cmpint (devices->len, ==, 1); + fu_plugin_device_remove (plugin, device); + g_assert_cmpint (devices->len, ==, 0); +} + +static void fu_plugin_delay_func (void) { FuDevice *device_tmp; @@ -386,9 +510,9 @@ /* exact */ tmp = fu_plugin_lookup_quirk_by_id (plugin, "USB\\VID_0A5C&PID_6412", "Flags"); g_assert_cmpstr (tmp, ==, "ignore-runtime"); - tmp = fu_plugin_lookup_quirk_by_id (plugin, "ACME Inc.=True", "Test"); + tmp = fu_plugin_lookup_quirk_by_id (plugin, "ACME Inc.=True", "Name"); g_assert_cmpstr (tmp, ==, "awesome"); - tmp = fu_plugin_lookup_quirk_by_id (plugin, "CORP*", "Test"); + tmp = fu_plugin_lookup_quirk_by_id (plugin, "CORP*", "Name"); g_assert_cmpstr (tmp, ==, "town"); tmp = fu_plugin_lookup_quirk_by_id (plugin, "baz", "Unfound"); g_assert_cmpstr (tmp, ==, NULL); @@ -416,7 +540,7 @@ /* lookup */ g_timer_reset (timer); for (guint j = 0; j < 1000; j++) { - const gchar *group = "DeviceInstanceId=USB\\VID_0BDA&PID_1100"; + const gchar *group = "USB\\VID_0BDA&PID_1100"; for (guint i = 0; keys[i] != NULL; i++) { const gchar *tmp = fu_quirks_lookup_by_id (quirks, group, keys[i]); g_assert_cmpstr (tmp, !=, NULL); @@ -1013,6 +1137,43 @@ } static void +fu_device_func (void) +{ + g_autoptr(FuDevice) device = fu_device_new (); + g_autoptr(GPtrArray) possible_plugins = NULL; + + /* only add one plugin name of the same type */ + fu_device_add_possible_plugin (device, "test"); + fu_device_add_possible_plugin (device, "test"); + possible_plugins = fu_device_get_possible_plugins (device); + g_assert_cmpint (possible_plugins->len, ==, 1); +} + +static void +fu_device_instance_ids_func (void) +{ + gboolean ret; + g_autoptr(FuDevice) device = fu_device_new (); + g_autoptr(GError) error = NULL; + + /* sanity check */ + g_assert_false (fu_device_has_guid (device, "c0a26214-223b-572a-9477-cde897fe8619")); + + /* add a deferred instance ID that only gets converted on ->setup */ + fu_device_add_instance_id (device, "foobarbaz"); + g_assert_false (fu_device_has_guid (device, "c0a26214-223b-572a-9477-cde897fe8619")); + + ret = fu_device_setup (device, &error); + g_assert_no_error (error); + g_assert_true (ret); + g_assert_true (fu_device_has_guid (device, "c0a26214-223b-572a-9477-cde897fe8619")); + + /* this gets added immediately */ + fu_device_add_instance_id (device, "bazbarfoo"); + g_assert_true (fu_device_has_guid (device, "77e49bb0-2cd6-5faf-bcee-5b7fbe6e944d")); +} + +static void fu_device_flags_func (void) { g_autoptr(FuDevice) device = fu_device_new (); @@ -1041,6 +1202,33 @@ } static void +fu_device_children_func (void) +{ + gboolean ret; + g_autoptr(FuDevice) child = fu_device_new (); + g_autoptr(FuDevice) parent = fu_device_new (); + g_autoptr(GError) error = NULL; + + fu_device_set_physical_id (child, "dummy"); + fu_device_set_physical_id (parent, "dummy"); + + /* set up family */ + fu_device_add_child (parent, child); + + /* set an instance ID that will be converted to a GUID when the parent + * calls ->setup */ + fu_device_add_instance_id (child, "foo"); + g_assert_false (fu_device_has_guid (child, "b84ed8ed-a7b1-502f-83f6-90132e68adef")); + + /* setup parent, which also calls setup on child too (and thus also + * converts the instance ID to a GUID) */ + ret = fu_device_setup (parent, &error); + g_assert_no_error (error); + g_assert_true (ret); + g_assert_true (fu_device_has_guid (child, "b84ed8ed-a7b1-502f-83f6-90132e68adef")); +} + +static void fu_device_parent_func (void) { g_autoptr(FuDevice) child = fu_device_new (); @@ -1050,6 +1238,10 @@ g_autoptr(FuDevice) parent = fu_device_new (); g_autoptr(FuDevice) parent_root = NULL; + fu_device_set_physical_id (child, "dummy"); + fu_device_set_physical_id (grandparent, "dummy"); + fu_device_set_physical_id (parent, "dummy"); + /* set up three layer family */ fu_device_add_child (grandparent, parent); fu_device_add_child (parent, child); @@ -1117,34 +1309,117 @@ chunked3 = fu_chunk_array_new ((const guint8 *) "123456", 6, 0x0, 3, 3); chunked3_str = fu_chunk_array_to_string (chunked3); - g_print ("\n%s", chunked3_str); - g_assert_cmpstr (chunked3_str, ==, "#00: page:00 addr:0000 len:03 123\n" - "#01: page:01 addr:0000 len:03 456\n"); + g_assert_cmpstr (chunked3_str, ==, "FuChunk:\n" + " Index: 0x0\n" + " Page: 0x0\n" + " Address: 0x0\n" + " Data: 123\n" + " DataSz: 0x3\n" + "\n" + "FuChunk:\n" + " Index: 0x1\n" + " Page: 0x1\n" + " Address: 0x0\n" + " Data: 456\n" + " DataSz: 0x3\n"); chunked4 = fu_chunk_array_new ((const guint8 *) "123456", 6, 0x4, 4, 4); chunked4_str = fu_chunk_array_to_string (chunked4); - g_print ("\n%s", chunked4_str); - g_assert_cmpstr (chunked4_str, ==, "#00: page:01 addr:0000 len:04 1234\n" - "#01: page:02 addr:0000 len:02 56\n"); + g_assert_cmpstr (chunked4_str, ==, "FuChunk:\n" + " Index: 0x0\n" + " Page: 0x1\n" + " Address: 0x0\n" + " Data: 1234\n" + " DataSz: 0x4\n" + "\n" + "FuChunk:\n" + " Index: 0x1\n" + " Page: 0x2\n" + " Address: 0x0\n" + " Data: 56\n" + " DataSz: 0x2\n"); chunked1 = fu_chunk_array_new ((const guint8 *) "0123456789abcdef", 16, 0x0, 10, 4); chunked1_str = fu_chunk_array_to_string (chunked1); - g_print ("\n%s", chunked1_str); - g_assert_cmpstr (chunked1_str, ==, "#00: page:00 addr:0000 len:04 0123\n" - "#01: page:00 addr:0004 len:04 4567\n" - "#02: page:00 addr:0008 len:02 89\n" - "#03: page:01 addr:0000 len:04 abcd\n" - "#04: page:01 addr:0004 len:02 ef\n"); + g_assert_cmpstr (chunked1_str, ==, "FuChunk:\n" + " Index: 0x0\n" + " Page: 0x0\n" + " Address: 0x0\n" + " Data: 0123\n" + " DataSz: 0x4\n" + "\n" + "FuChunk:\n" + " Index: 0x1\n" + " Page: 0x0\n" + " Address: 0x4\n" + " Data: 4567\n" + " DataSz: 0x4\n" + "\n" + "FuChunk:\n" + " Index: 0x2\n" + " Page: 0x0\n" + " Address: 0x8\n" + " Data: 89\n" + " DataSz: 0x2\n" + "\n" + "FuChunk:\n" + " Index: 0x3\n" + " Page: 0x1\n" + " Address: 0x0\n" + " Data: abcd\n" + " DataSz: 0x4\n" + "\n" + "FuChunk:\n" + " Index: 0x4\n" + " Page: 0x1\n" + " Address: 0x4\n" + " Data: ef\n" + " DataSz: 0x2\n"); chunked2 = fu_chunk_array_new ((const guint8 *) "XXXXXXYYYYYYZZZZZZ", 18, 0x0, 6, 4); chunked2_str = fu_chunk_array_to_string (chunked2); g_print ("\n%s", chunked2_str); - g_assert_cmpstr (chunked2_str, ==, "#00: page:00 addr:0000 len:04 XXXX\n" - "#01: page:00 addr:0004 len:02 XX\n" - "#02: page:01 addr:0000 len:04 YYYY\n" - "#03: page:01 addr:0004 len:02 YY\n" - "#04: page:02 addr:0000 len:04 ZZZZ\n" - "#05: page:02 addr:0004 len:02 ZZ\n"); + g_assert_cmpstr (chunked2_str, ==, "FuChunk:\n" + " Index: 0x0\n" + " Page: 0x0\n" + " Address: 0x0\n" + " Data: XXXX\n" + " DataSz: 0x4\n" + "\n" + "FuChunk:\n" + " Index: 0x1\n" + " Page: 0x0\n" + " Address: 0x4\n" + " Data: XX\n" + " DataSz: 0x2\n" + "\n" + "FuChunk:\n" + " Index: 0x2\n" + " Page: 0x1\n" + " Address: 0x0\n" + " Data: YYYY\n" + " DataSz: 0x4\n" + "\n" + "FuChunk:\n" + " Index: 0x3\n" + " Page: 0x1\n" + " Address: 0x4\n" + " Data: YY\n" + " DataSz: 0x2\n" + "\n" + "FuChunk:\n" + " Index: 0x4\n" + " Page: 0x2\n" + " Address: 0x0\n" + " Data: ZZZZ\n" + " DataSz: 0x4\n" + "\n" + "FuChunk:\n" + " Index: 0x5\n" + " Page: 0x2\n" + " Address: 0x4\n" + " Data: ZZ\n" + " DataSz: 0x2\n"); } static void @@ -1169,6 +1444,35 @@ } static void +fu_common_version_semver_func (void) +{ + struct { + const gchar *old; + const gchar *new; + } map[] = { + { "1.2.3", "1.2.3" }, + { "1.2-3", "1.2.3" }, + { "1~2-3", "1.2.3" }, + { ".1.2", "1.2" }, + { "1.2.", "1.2" }, + { "1..2", "1.2" }, + { "CBET1.2.3", "1.2.3" }, + { "1.2.3alpha", "1.2.3" }, + { "5", "5" }, + { "\t5\n", "5" }, + { "0x123456", "0.18.13398" }, + { "coreboot-unknown", NULL }, + { "", NULL }, + { " ", NULL }, + { NULL, NULL } + }; + for (guint i = 0; map[i].old != NULL; i++) { + g_autofree gchar *tmp = fu_common_version_ensure_semver (map[i].old); + g_assert_cmpstr (tmp, ==, map[i].new); + } +} + +static void fu_common_version_func (void) { guint i; @@ -1277,48 +1581,49 @@ fu_common_vercmp_func (void) { /* same */ - g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.3"), ==, 0); - g_assert_cmpint (fu_common_vercmp ("001.002.003", "001.002.003"), ==, 0); + g_assert_cmpint (fu_common_vercmp_full ("1.2.3", "1.2.3", FWUPD_VERSION_FORMAT_UNKNOWN), ==, 0); + g_assert_cmpint (fu_common_vercmp_full ("001.002.003", "001.002.003", FWUPD_VERSION_FORMAT_UNKNOWN), ==, 0); + g_assert_cmpint (fu_common_vercmp_full ("0x00000002", "0x2", FWUPD_VERSION_FORMAT_HEX), ==, 0); /* upgrade and downgrade */ - g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.4"), <, 0); - g_assert_cmpint (fu_common_vercmp ("001.002.000", "001.002.009"), <, 0); - g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.2"), >, 0); - g_assert_cmpint (fu_common_vercmp ("001.002.009", "001.002.000"), >, 0); + g_assert_cmpint (fu_common_vercmp_full ("1.2.3", "1.2.4", FWUPD_VERSION_FORMAT_UNKNOWN), <, 0); + g_assert_cmpint (fu_common_vercmp_full ("001.002.000", "001.002.009", FWUPD_VERSION_FORMAT_UNKNOWN), <, 0); + g_assert_cmpint (fu_common_vercmp_full ("1.2.3", "1.2.2", FWUPD_VERSION_FORMAT_UNKNOWN), >, 0); + g_assert_cmpint (fu_common_vercmp_full ("001.002.009", "001.002.000", FWUPD_VERSION_FORMAT_UNKNOWN), >, 0); /* unequal depth */ - g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.3.1"), <, 0); - g_assert_cmpint (fu_common_vercmp ("1.2.3.1", "1.2.4"), <, 0); + g_assert_cmpint (fu_common_vercmp_full ("1.2.3", "1.2.3.1", FWUPD_VERSION_FORMAT_UNKNOWN), <, 0); + g_assert_cmpint (fu_common_vercmp_full ("1.2.3.1", "1.2.4", FWUPD_VERSION_FORMAT_UNKNOWN), <, 0); /* mixed-alpha-numeric */ - g_assert_cmpint (fu_common_vercmp ("1.2.3a", "1.2.3a"), ==, 0); - g_assert_cmpint (fu_common_vercmp ("1.2.3a", "1.2.3b"), <, 0); - g_assert_cmpint (fu_common_vercmp ("1.2.3b", "1.2.3a"), >, 0); + g_assert_cmpint (fu_common_vercmp_full ("1.2.3a", "1.2.3a", FWUPD_VERSION_FORMAT_UNKNOWN), ==, 0); + g_assert_cmpint (fu_common_vercmp_full ("1.2.3a", "1.2.3b", FWUPD_VERSION_FORMAT_UNKNOWN), <, 0); + g_assert_cmpint (fu_common_vercmp_full ("1.2.3b", "1.2.3a", FWUPD_VERSION_FORMAT_UNKNOWN), >, 0); /* alpha version append */ - g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.3a"), <, 0); - g_assert_cmpint (fu_common_vercmp ("1.2.3a", "1.2.3"), >, 0); + g_assert_cmpint (fu_common_vercmp_full ("1.2.3", "1.2.3a", FWUPD_VERSION_FORMAT_UNKNOWN), <, 0); + g_assert_cmpint (fu_common_vercmp_full ("1.2.3a", "1.2.3", FWUPD_VERSION_FORMAT_UNKNOWN), >, 0); /* alpha only */ - g_assert_cmpint (fu_common_vercmp ("alpha", "alpha"), ==, 0); - g_assert_cmpint (fu_common_vercmp ("alpha", "beta"), <, 0); - g_assert_cmpint (fu_common_vercmp ("beta", "alpha"), >, 0); + g_assert_cmpint (fu_common_vercmp_full ("alpha", "alpha", FWUPD_VERSION_FORMAT_UNKNOWN), ==, 0); + g_assert_cmpint (fu_common_vercmp_full ("alpha", "beta", FWUPD_VERSION_FORMAT_UNKNOWN), <, 0); + g_assert_cmpint (fu_common_vercmp_full ("beta", "alpha", FWUPD_VERSION_FORMAT_UNKNOWN), >, 0); /* alpha-compare */ - g_assert_cmpint (fu_common_vercmp ("1.2a.3", "1.2a.3"), ==, 0); - g_assert_cmpint (fu_common_vercmp ("1.2a.3", "1.2b.3"), <, 0); - g_assert_cmpint (fu_common_vercmp ("1.2b.3", "1.2a.3"), >, 0); + g_assert_cmpint (fu_common_vercmp_full ("1.2a.3", "1.2a.3", FWUPD_VERSION_FORMAT_UNKNOWN), ==, 0); + g_assert_cmpint (fu_common_vercmp_full ("1.2a.3", "1.2b.3", FWUPD_VERSION_FORMAT_UNKNOWN), <, 0); + g_assert_cmpint (fu_common_vercmp_full ("1.2b.3", "1.2a.3", FWUPD_VERSION_FORMAT_UNKNOWN), >, 0); /* tilde is all-powerful */ - g_assert_cmpint (fu_common_vercmp ("1.2.3~rc1", "1.2.3~rc1"), ==, 0); - g_assert_cmpint (fu_common_vercmp ("1.2.3~rc1", "1.2.3"), <, 0); - g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.3~rc1"), >, 0); - g_assert_cmpint (fu_common_vercmp ("1.2.3~rc2", "1.2.3~rc1"), >, 0); + g_assert_cmpint (fu_common_vercmp_full ("1.2.3~rc1", "1.2.3~rc1", FWUPD_VERSION_FORMAT_UNKNOWN), ==, 0); + g_assert_cmpint (fu_common_vercmp_full ("1.2.3~rc1", "1.2.3", FWUPD_VERSION_FORMAT_UNKNOWN), <, 0); + g_assert_cmpint (fu_common_vercmp_full ("1.2.3", "1.2.3~rc1", FWUPD_VERSION_FORMAT_UNKNOWN), >, 0); + g_assert_cmpint (fu_common_vercmp_full ("1.2.3~rc2", "1.2.3~rc1", FWUPD_VERSION_FORMAT_UNKNOWN), >, 0); /* invalid */ - g_assert_cmpint (fu_common_vercmp ("1", NULL), ==, G_MAXINT); - g_assert_cmpint (fu_common_vercmp (NULL, "1"), ==, G_MAXINT); - g_assert_cmpint (fu_common_vercmp (NULL, NULL), ==, G_MAXINT); + g_assert_cmpint (fu_common_vercmp_full ("1", NULL, FWUPD_VERSION_FORMAT_UNKNOWN), ==, G_MAXINT); + g_assert_cmpint (fu_common_vercmp_full (NULL, "1", FWUPD_VERSION_FORMAT_UNKNOWN), ==, G_MAXINT); + g_assert_cmpint (fu_common_vercmp_full (NULL, NULL, FWUPD_VERSION_FORMAT_UNKNOWN), ==, G_MAXINT); } static void @@ -1336,13 +1641,10 @@ g_autoptr(GBytes) data_hex = NULL; g_autoptr(GBytes) data_ref = NULL; g_autoptr(GError) error = NULL; - g_autoptr(GFile) file_ref = NULL; - g_autoptr(GFile) file_hex = NULL; /* load a Intel hex32 file */ filename_hex = g_build_filename (TESTDATADIR_SRC, "firmware.hex", NULL); - file_hex = g_file_new_for_path (filename_hex); - data_file = g_file_load_bytes (file_hex, NULL, NULL, &error); + data_file = fu_common_get_contents_bytes (filename_hex, &error); g_assert_no_error (error); g_assert (data_file != NULL); ret = fu_firmware_parse (firmware, data_file, FWUPD_INSTALL_FLAG_NONE, &error); @@ -1355,8 +1657,7 @@ /* did we match the reference file? */ filename_ref = g_build_filename (TESTDATADIR_SRC, "firmware.bin", NULL); - file_ref = g_file_new_for_path (filename_ref); - data_ref = g_file_load_bytes (file_ref, NULL, NULL, &error); + data_ref = fu_common_get_contents_bytes (filename_ref, &error); g_assert_no_error (error); g_assert (data_ref != NULL); ret = fu_common_bytes_compare (data_fw, data_ref, &error); @@ -1395,12 +1696,10 @@ g_autoptr(GBytes) data_fw = NULL; g_autoptr(GBytes) data_sig = NULL; g_autoptr(GError) error = NULL; - g_autoptr(GFile) file_hex = NULL; /* load a signed Intel hex32 file */ filename_shex = g_build_filename (TESTDATADIR_SRC, "firmware.shex", NULL); - file_hex = g_file_new_for_path (filename_shex); - data_file = g_file_load_bytes (file_hex, NULL, NULL, &error); + data_file = fu_common_get_contents_bytes (filename_shex, &error); g_assert_no_error (error); g_assert (data_file != NULL); ret = fu_firmware_parse (firmware, data_file, FWUPD_INSTALL_FLAG_NONE, &error); @@ -1479,12 +1778,9 @@ g_autoptr(GBytes) data_srec = NULL; g_autoptr(GBytes) data_bin = NULL; g_autoptr(GError) error = NULL; - g_autoptr(GFile) file_bin = NULL; - g_autoptr(GFile) file_srec = NULL; filename_srec = g_build_filename (TESTDATADIR_SRC, "firmware.srec", NULL); - file_srec = g_file_new_for_path (filename_srec); - data_srec = g_file_load_bytes (file_srec, NULL, NULL, &error); + data_srec = fu_common_get_contents_bytes (filename_srec, &error); g_assert_no_error (error); g_assert (data_srec != NULL); ret = fu_firmware_parse (firmware, data_srec, FWUPD_INSTALL_FLAG_NONE, &error); @@ -1497,8 +1793,7 @@ /* did we match the reference file? */ filename_ref = g_build_filename (TESTDATADIR_SRC, "firmware.bin", NULL); - file_bin = g_file_new_for_path (filename_ref); - data_ref = g_file_load_bytes (file_bin, NULL, NULL, &error); + data_ref = fu_common_get_contents_bytes (filename_ref, &error); g_assert_no_error (error); g_assert (data_ref != NULL); ret = fu_common_bytes_compare (data_bin, data_ref, &error); @@ -1539,6 +1834,217 @@ } static void +fu_firmware_build_func (void) +{ + gboolean ret; + g_autofree gchar *str = NULL; + g_autoptr(FuFirmware) firmware = fu_firmware_new (); + g_autoptr(FuFirmwareImage) img = NULL; + g_autoptr(GBytes) blob = NULL; + g_autoptr(GBytes) blob2 = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(XbBuilder) builder = xb_builder_new (); + g_autoptr(XbBuilderSource) source = xb_builder_source_new (); + g_autoptr(XbNode) n = NULL; + g_autoptr(XbSilo) silo = NULL; + const gchar *buf = + "\n" + "\n" + " 1.2.3\n" + " \n" + " 4.5.6\n" + " header\n" + " 456\n" + " 0x456\n" + " aGVsbG8=\n" + " \n" + " \n" + " 7.8.9\n" + " header\n" + " 789\n" + " 0x789\n" + " \n" + "\n"; + blob = g_bytes_new_static (buf, strlen (buf)); + g_assert_no_error (error); + g_assert_nonnull (blob); + + /* parse XML */ + ret = xb_builder_source_load_bytes (source, blob, XB_BUILDER_SOURCE_FLAG_NONE, &error); + g_assert_no_error (error); + g_assert (ret); + xb_builder_import_source (builder, source); + silo = xb_builder_compile (builder, XB_BUILDER_COMPILE_FLAG_NONE, NULL, &error); + g_assert_no_error (error); + g_assert_nonnull (silo); + n = xb_silo_query_first (silo, "firmware", &error); + g_assert_no_error (error); + g_assert_nonnull (n); + + /* build object */ + ret = fu_firmware_build (firmware, n, &error); + g_assert_no_error (error); + g_assert (ret); + g_assert_cmpstr (fu_firmware_get_version (firmware), ==, "1.2.3"); + + /* verify image */ + img = fu_firmware_get_image_by_id (firmware, "header", &error); + g_assert_no_error (error); + g_assert_nonnull (img); + g_assert_cmpstr (fu_firmware_image_get_version (img), ==, "4.5.6"); + g_assert_cmpint (fu_firmware_image_get_idx (img), ==, 456); + g_assert_cmpint (fu_firmware_image_get_addr (img), ==, 0x456); + blob2 = fu_firmware_image_write (img, &error); + g_assert_no_error (error); + g_assert_nonnull (blob2); + g_assert_cmpint (g_bytes_get_size (blob2), ==, 5); + str = g_strndup (g_bytes_get_data (blob2, NULL), g_bytes_get_size (blob2)); + g_assert_cmpstr (str, ==, "hello"); +} + +static gsize +fu_firmware_dfuse_image_get_size (FuFirmwareImage *self) +{ + g_autoptr(GPtrArray) chunks = fu_firmware_image_get_chunks (self, NULL); + gsize length = 0; + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + length += fu_chunk_get_data_sz (chk); + } + return length; +} + +static gsize +fu_firmware_dfuse_get_size (FuFirmware *firmware) +{ + gsize length = 0; + g_autoptr(GPtrArray) images = fu_firmware_get_images (firmware); + for (guint i = 0; i < images->len; i++) { + FuFirmwareImage *image = g_ptr_array_index (images, i); + length += fu_firmware_dfuse_image_get_size (image); + } + return length; +} + +static void +fu_firmware_dfuse_func (void) +{ + gboolean ret; + g_autofree gchar *filename = NULL; + g_autoptr(FuFirmware) firmware = fu_dfuse_firmware_new (); + g_autoptr(GBytes) roundtrip_orig = NULL; + g_autoptr(GBytes) roundtrip = NULL; + g_autoptr(GError) error = NULL; + + /* load a DfuSe firmware */ + filename = g_build_filename (TESTDATADIR_SRC, "firmware.dfuse", NULL); + g_assert (filename != NULL); + roundtrip_orig = fu_common_get_contents_bytes (filename, &error); + ret = fu_firmware_parse (firmware, roundtrip_orig, FWUPD_INSTALL_FLAG_NONE, &error); + g_assert_no_error (error); + g_assert (ret); + g_assert_cmpint (fu_dfu_firmware_get_vid (FU_DFU_FIRMWARE (firmware)), ==, 0x1234); + g_assert_cmpint (fu_dfu_firmware_get_pid (FU_DFU_FIRMWARE (firmware)), ==, 0x5678); + g_assert_cmpint (fu_dfu_firmware_get_release (FU_DFU_FIRMWARE (firmware)), ==, 0x8642); + g_assert_cmpint (fu_firmware_dfuse_get_size (firmware), ==, 0x21); + + /* can we roundtrip without losing data */ + roundtrip = fu_firmware_write (firmware, &error); + g_assert_no_error (error); + g_assert (roundtrip != NULL); + ret = fu_common_bytes_compare (roundtrip, roundtrip_orig, &error); + g_assert_no_error (error); + g_assert_true (ret); +} + +static void +fu_firmware_fmap_func (void) +{ + gboolean ret; + g_autofree gchar *filename = NULL; + g_autofree gchar *img_str = NULL; + g_autoptr(FuFirmware) firmware = fu_fmap_firmware_new (); + g_autoptr(FuFirmwareImage) img = NULL; + g_autoptr(GBytes) img_blob = NULL; + g_autoptr(GBytes) roundtrip = NULL; + g_autoptr(GBytes) roundtrip_orig = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) images = NULL; + + /* load firmware */ + filename = g_build_filename (TESTDATADIR_SRC, "firmware.fmap", NULL); + g_assert (filename != NULL); + roundtrip_orig = fu_common_get_contents_bytes (filename, &error); + ret = fu_firmware_parse (firmware, roundtrip_orig, FWUPD_INSTALL_FLAG_NONE, &error); + g_assert_no_error (error); + g_assert (ret); + + /* check image count */ + images = fu_firmware_get_images (firmware); + g_assert_cmpint (images->len, ==, 2); + + /* get a specific image */ + img = fu_firmware_get_image_by_id (firmware, "FMAP", &error); + g_assert_no_error (error); + g_assert_nonnull (img); + img_blob = fu_firmware_image_get_bytes (img); + g_assert_cmpint (g_bytes_get_size (img_blob), ==, 0xb); + img_str = g_strndup (g_bytes_get_data (img_blob, NULL), + g_bytes_get_size (img_blob)); + g_assert_cmpstr (img_str, ==, "hello world"); + + /* can we roundtrip without losing data */ + roundtrip = fu_firmware_write (firmware, &error); + g_assert_no_error (error); + g_assert (roundtrip != NULL); + ret = fu_common_bytes_compare (roundtrip, roundtrip_orig, &error); + g_assert_no_error (error); + g_assert_true (ret); +} + +static void +fu_firmware_new_from_gtypes_func (void) +{ + g_autofree gchar *fn = NULL; + g_autoptr(FuFirmware) firmware1 = NULL; + g_autoptr(FuFirmware) firmware2 = NULL; + g_autoptr(FuFirmware) firmware3 = NULL; + g_autoptr(GBytes) blob = NULL; + g_autoptr(GError) error = NULL; + + fn = g_build_filename (TESTDATADIR_SRC, "firmware.dfu", NULL); + blob = fu_common_get_contents_bytes (fn, &error); + g_assert_no_error (error); + g_assert (blob != NULL); + + /* dfu -> FuDfuFirmware */ + firmware1 = fu_firmware_new_from_gtypes (blob, FWUPD_INSTALL_FLAG_NONE, &error, + FU_TYPE_SREC_FIRMWARE, + FU_TYPE_DFUSE_FIRMWARE, + FU_TYPE_DFU_FIRMWARE, + G_TYPE_INVALID); + g_assert_no_error (error); + g_assert_nonnull (firmware1); + g_assert_cmpstr (G_OBJECT_TYPE_NAME (firmware1), ==, "FuDfuFirmware"); + + /* dfu -> FuFirmware */ + firmware2 = fu_firmware_new_from_gtypes (blob, FWUPD_INSTALL_FLAG_NONE, &error, + FU_TYPE_SREC_FIRMWARE, + FU_TYPE_FIRMWARE, + G_TYPE_INVALID); + g_assert_no_error (error); + g_assert_nonnull (firmware2); + g_assert_cmpstr (G_OBJECT_TYPE_NAME (firmware2), ==, "FuFirmware"); + + /* dfu -> error */ + firmware3 = fu_firmware_new_from_gtypes (blob, FWUPD_INSTALL_FLAG_NONE, &error, + FU_TYPE_SREC_FIRMWARE, + G_TYPE_INVALID); + g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); + g_assert_null (firmware3); +} + +static void fu_firmware_dfu_func (void) { gboolean ret; @@ -1549,12 +2055,9 @@ g_autoptr(GBytes) data_dfu = NULL; g_autoptr(GBytes) data_bin = NULL; g_autoptr(GError) error = NULL; - g_autoptr(GFile) file_bin = NULL; - g_autoptr(GFile) file_dfu = NULL; filename_dfu = g_build_filename (TESTDATADIR_SRC, "firmware.dfu", NULL); - file_dfu = g_file_new_for_path (filename_dfu); - data_dfu = g_file_load_bytes (file_dfu, NULL, NULL, &error); + data_dfu = fu_common_get_contents_bytes (filename_dfu, &error); g_assert_no_error (error); g_assert (data_dfu != NULL); ret = fu_firmware_parse (firmware, data_dfu, FWUPD_INSTALL_FLAG_NONE, &error); @@ -1570,8 +2073,7 @@ /* did we match the reference file? */ filename_ref = g_build_filename (TESTDATADIR_SRC, "firmware.bin", NULL); - file_bin = g_file_new_for_path (filename_ref); - data_ref = g_file_load_bytes (file_bin, NULL, NULL, &error); + data_ref = fu_common_get_contents_bytes (filename_ref, &error); g_assert_no_error (error); g_assert (data_ref != NULL); ret = fu_common_bytes_compare (data_bin, data_ref, &error); @@ -1582,17 +2084,20 @@ static void fu_firmware_func (void) { + gboolean ret; g_autoptr(FuFirmware) firmware = fu_firmware_new (); g_autoptr(FuFirmwareImage) img1 = fu_firmware_image_new (NULL); g_autoptr(FuFirmwareImage) img2 = fu_firmware_image_new (NULL); g_autoptr(FuFirmwareImage) img_id = NULL; g_autoptr(FuFirmwareImage) img_idx = NULL; g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) images = NULL; g_autofree gchar *str = NULL; fu_firmware_image_set_addr (img1, 0x200); fu_firmware_image_set_idx (img1, 13); fu_firmware_image_set_id (img1, "primary"); + fu_firmware_image_set_filename (img1, "BIOS.bin"); fu_firmware_add_image (firmware, img1); fu_firmware_image_set_addr (img2, 0x400); fu_firmware_image_set_idx (img2, 23); @@ -1624,13 +2129,72 @@ str = fu_firmware_to_string (firmware); g_assert_cmpstr (str, ==, "FuFirmware:\n" " FuFirmwareImage:\n" - " ID: primary\n" - " Index: 0xd\n" - " Address: 0x200\n" + " ID: primary\n" + " Index: 0xd\n" + " Address: 0x200\n" + " Filename: BIOS.bin\n" " FuFirmwareImage:\n" - " ID: secondary\n" - " Index: 0x17\n" - " Address: 0x400\n"); + " ID: secondary\n" + " Index: 0x17\n" + " Address: 0x400\n"); + + ret = fu_firmware_remove_image_by_idx (firmware, 0xd, &error); + g_assert_no_error (error); + g_assert_true (ret); + ret = fu_firmware_remove_image_by_id (firmware, "secondary", &error); + g_assert_no_error (error); + g_assert_true (ret); + images = fu_firmware_get_images (firmware); + g_assert_nonnull (images); + g_assert_cmpint (images->len, ==, 0); + ret = fu_firmware_remove_image_by_id (firmware, "NOTGOINGTOEXIST", &error); + g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND); + g_assert_false (ret); +} + +static void +fu_firmware_dedupe_func (void) +{ + g_autoptr(FuFirmware) firmware = fu_firmware_new (); + g_autoptr(FuFirmwareImage) img1 = fu_firmware_image_new (NULL); + g_autoptr(FuFirmwareImage) img1_old = fu_firmware_image_new (NULL); + g_autoptr(FuFirmwareImage) img2 = fu_firmware_image_new (NULL); + g_autoptr(FuFirmwareImage) img2_old = fu_firmware_image_new (NULL); + g_autoptr(FuFirmwareImage) img_id = NULL; + g_autoptr(FuFirmwareImage) img_idx = NULL; + g_autoptr(GError) error = NULL; + + fu_firmware_add_flag (firmware, FU_FIRMWARE_FLAG_DEDUPE_ID); + fu_firmware_add_flag (firmware, FU_FIRMWARE_FLAG_DEDUPE_IDX); + + fu_firmware_image_set_idx (img1_old, 13); + fu_firmware_image_set_id (img1_old, "DAVE"); + fu_firmware_add_image (firmware, img1_old); + + fu_firmware_image_set_idx (img1, 13); + fu_firmware_image_set_id (img1, "primary"); + fu_firmware_add_image (firmware, img1); + + + fu_firmware_image_set_idx (img2_old, 123456); + fu_firmware_image_set_id (img2_old, "secondary"); + fu_firmware_add_image (firmware, img2_old); + + fu_firmware_image_set_idx (img2, 23); + fu_firmware_image_set_id (img2, "secondary"); + fu_firmware_add_image (firmware, img2); + + img_id = fu_firmware_get_image_by_id (firmware, "primary", &error); + g_assert_no_error (error); + g_assert_nonnull (img_id); + g_assert_cmpint (fu_firmware_image_get_idx (img_id), ==, 13); + g_assert_cmpstr (fu_firmware_image_get_id (img_id), ==, "primary"); + + img_idx = fu_firmware_get_image_by_idx (firmware, 23, &error); + g_assert_no_error (error); + g_assert_nonnull (img_idx); + g_assert_cmpint (fu_firmware_image_get_idx (img_idx), ==, 23); + g_assert_cmpstr (fu_firmware_image_get_id (img_idx), ==, "secondary"); } static void @@ -1639,18 +2203,31 @@ gboolean ret; gsize sz = 0; guint32 attr = 0; + guint64 total; g_autofree guint8 *data = NULL; g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) names = NULL; /* check supported */ ret = fu_efivar_supported (&error); g_assert_no_error (error); g_assert_true (ret); + /* check we can get the space used */ + total = fu_efivar_space_used (&error); + g_assert_no_error (error); + g_assert_cmpint (total, >=, 0x2000); + /* check existing keys */ g_assert_false (fu_efivar_exists (FU_EFIVAR_GUID_EFI_GLOBAL, "NotGoingToExist")); g_assert_true (fu_efivar_exists (FU_EFIVAR_GUID_EFI_GLOBAL, "SecureBoot")); + /* list a few keys */ + names = fu_efivar_get_names (FU_EFIVAR_GUID_EFI_GLOBAL, &error); + g_assert_no_error (error); + g_assert_nonnull (names); + g_assert_cmpint (names->len, ==, 2); + /* write and read a key */ ret = fu_efivar_set_data (FU_EFIVAR_GUID_EFI_GLOBAL, "Test", (guint8 *) "1", 1, @@ -1781,6 +2358,106 @@ g_assert_cmpint (helper.cnt_failed, ==, 2); } +static void +fu_security_attrs_hsi_func (void) +{ + g_autofree gchar *hsi1 = NULL; + g_autofree gchar *hsi2 = NULL; + g_autofree gchar *hsi3 = NULL; + g_autofree gchar *hsi4 = NULL; + g_autofree gchar *hsi5 = NULL; + g_autofree gchar *hsi6 = NULL; + g_autofree gchar *hsi7 = NULL; + g_autofree gchar *hsi8 = NULL; + g_autofree gchar *expected_hsi8 = NULL; + g_autoptr(FuSecurityAttrs) attrs = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* no attrs */ + attrs = fu_security_attrs_new (); + hsi1 = fu_security_attrs_calculate_hsi (attrs, FU_SECURITY_ATTRS_FLAG_NONE); + g_assert_cmpstr (hsi1, ==, "HSI:0"); + + /* just success from HSI:1 */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SPI_BIOSWE); + fwupd_security_attr_set_plugin (attr, "test"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_url (attr, "http://test"); + fu_security_attrs_append (attrs, attr); + hsi2 = fu_security_attrs_calculate_hsi (attrs, FU_SECURITY_ATTRS_FLAG_NONE); + g_assert_cmpstr (hsi2, ==, "HSI:1"); + g_clear_object (&attr); + + /* add failed from HSI:2, so still HSI:1 */ + attr = fwupd_security_attr_new ("org.fwupd.hsi.PRX"); + fwupd_security_attr_set_plugin (attr, "test"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT); + fwupd_security_attr_set_url (attr, "http://test"); + fu_security_attrs_append (attrs, attr); + hsi3 = fu_security_attrs_calculate_hsi (attrs, FU_SECURITY_ATTRS_FLAG_NONE); + g_assert_cmpstr (hsi3, ==, "HSI:1"); + g_clear_object (&attr); + + /* add attr from HSI:3, obsoleting the failure */ + attr = fwupd_security_attr_new ("org.fwupd.hsi.BIOSGuard"); + fwupd_security_attr_set_plugin (attr, "test"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_add_obsolete (attr, "org.fwupd.hsi.PRX"); + fwupd_security_attr_set_url (attr, "http://test"); + fu_security_attrs_append (attrs, attr); + fu_security_attrs_depsolve (attrs); + hsi4 = fu_security_attrs_calculate_hsi (attrs, FU_SECURITY_ATTRS_FLAG_NONE); + g_assert_cmpstr (hsi4, ==, "HSI:3"); + g_clear_object (&attr); + + /* add taint that was fine */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_FWUPD_PLUGINS); + fwupd_security_attr_set_plugin (attr, "test"); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); + fwupd_security_attr_set_url (attr, "http://test"); + fu_security_attrs_append (attrs, attr); + hsi5 = fu_security_attrs_calculate_hsi (attrs, FU_SECURITY_ATTRS_FLAG_NONE); + g_assert_cmpstr (hsi5, ==, "HSI:3"); + g_clear_object (&attr); + + /* add updates and attestation */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_FWUPD_UPDATES); + fwupd_security_attr_set_plugin (attr, "test"); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_url (attr, "http://test"); + fu_security_attrs_append (attrs, attr); + hsi6 = fu_security_attrs_calculate_hsi (attrs, FU_SECURITY_ATTRS_FLAG_NONE); + g_assert_cmpstr (hsi6, ==, "HSI:3"); + g_clear_object (&attr); + + /* add issue that was uncool */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_KERNEL_SWAP); + fwupd_security_attr_set_plugin (attr, "test"); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); + fwupd_security_attr_set_url (attr, "http://test"); + fu_security_attrs_append (attrs, attr); + hsi7 = fu_security_attrs_calculate_hsi (attrs, FU_SECURITY_ATTRS_FLAG_NONE); + g_assert_cmpstr (hsi7, ==, "HSI:3!"); + g_clear_object (&attr); + + /* show version in the attribute */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_KERNEL_SWAP); + fwupd_security_attr_set_plugin (attr, "test"); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); + fwupd_security_attr_set_url (attr, "http://test"); + fu_security_attrs_append (attrs, attr); + hsi8 = fu_security_attrs_calculate_hsi (attrs, FU_SECURITY_ATTRS_FLAG_ADD_VERSION); + expected_hsi8 = g_strdup_printf ("HSI:3! (v%d.%d.%d)", + FWUPD_MAJOR_VERSION, + FWUPD_MINOR_VERSION, + FWUPD_MICRO_VERSION); + g_assert_cmpstr (hsi8, ==, expected_hsi8); + g_clear_object (&attr); +} + int main (int argc, char **argv) { @@ -1796,14 +2473,19 @@ g_setenv ("FWUPD_OFFLINE_TRIGGER", "/tmp/fwupd-self-test/system-update", TRUE); g_setenv ("FWUPD_LOCALSTATEDIR", "/tmp/fwupd-self-test/var", TRUE); + g_test_add_func ("/fwupd/security-attrs{hsi}", fu_security_attrs_hsi_func); + g_test_add_func ("/fwupd/plugin{devices}", fu_plugin_devices_func); g_test_add_func ("/fwupd/plugin{delay}", fu_plugin_delay_func); g_test_add_func ("/fwupd/plugin{quirks}", fu_plugin_quirks_func); g_test_add_func ("/fwupd/plugin{quirks-performance}", fu_plugin_quirks_performance_func); g_test_add_func ("/fwupd/plugin{quirks-device}", fu_plugin_quirks_device_func); g_test_add_func ("/fwupd/chunk", fu_chunk_func); + g_test_add_func ("/fwupd/common{byte-array}", fu_common_byte_array_func); + g_test_add_func ("/fwupd/common{crc}", fu_common_crc_func); g_test_add_func ("/fwupd/common{string-append-kv}", fu_common_string_append_kv_func); g_test_add_func ("/fwupd/common{version-guess-format}", fu_common_version_guess_format_func); g_test_add_func ("/fwupd/common{version}", fu_common_version_func); + g_test_add_func ("/fwupd/common{version-semver}", fu_common_version_semver_func); g_test_add_func ("/fwupd/common{vercmp}", fu_common_vercmp_func); g_test_add_func ("/fwupd/common{strstrip}", fu_common_strstrip_func); g_test_add_func ("/fwupd/common{endian}", fu_common_endian_func); @@ -1819,21 +2501,32 @@ g_test_add_func ("/fwupd/common{spawn-timeout)", fu_common_spawn_timeout_func); // Requires 'sysctl kernel.unprivileged_userns_clone=1': g_test_add_func ("/fwupd/common{firmware-builder}", fu_common_firmware_builder_func); g_test_add_func ("/fwupd/common{kernel-lockdown}", fu_common_kernel_lockdown_func); + g_test_add_func ("/fwupd/common{strsafe}", fu_common_strsafe_func); + g_test_add_func ("/fwupd/common{uri-scheme}", fu_common_uri_scheme_func); g_test_add_func ("/fwupd/efivar", fu_efivar_func); g_test_add_func ("/fwupd/hwids", fu_hwids_func); g_test_add_func ("/fwupd/smbios", fu_smbios_func); g_test_add_func ("/fwupd/smbios3", fu_smbios3_func); + g_test_add_func ("/fwupd/smbios{dt}", fu_smbios_dt_func); g_test_add_func ("/fwupd/firmware", fu_firmware_func); + g_test_add_func ("/fwupd/firmware{dedupe}", fu_firmware_dedupe_func); + g_test_add_func ("/fwupd/firmware{build}", fu_firmware_build_func); g_test_add_func ("/fwupd/firmware{ihex}", fu_firmware_ihex_func); g_test_add_func ("/fwupd/firmware{ihex-offset}", fu_firmware_ihex_offset_func); g_test_add_func ("/fwupd/firmware{ihex-signed}", fu_firmware_ihex_signed_func); g_test_add_func ("/fwupd/firmware{srec-tokenization}", fu_firmware_srec_tokenization_func); g_test_add_func ("/fwupd/firmware{srec}", fu_firmware_srec_func); g_test_add_func ("/fwupd/firmware{dfu}", fu_firmware_dfu_func); + g_test_add_func ("/fwupd/firmware{dfuse}", fu_firmware_dfuse_func); + g_test_add_func ("/fwupd/firmware{fmap}", fu_firmware_fmap_func); + g_test_add_func ("/fwupd/firmware{gtypes}", fu_firmware_new_from_gtypes_func); g_test_add_func ("/fwupd/archive{invalid}", fu_archive_invalid_func); g_test_add_func ("/fwupd/archive{cab}", fu_archive_cab_func); + g_test_add_func ("/fwupd/device", fu_device_func); + g_test_add_func ("/fwupd/device{instance-ids}", fu_device_instance_ids_func); g_test_add_func ("/fwupd/device{flags}", fu_device_flags_func); g_test_add_func ("/fwupd/device{parent}", fu_device_parent_func); + g_test_add_func ("/fwupd/device{children}", fu_device_children_func); g_test_add_func ("/fwupd/device{incorporate}", fu_device_incorporate_func); if (g_test_slow ()) g_test_add_func ("/fwupd/device{poll}", fu_device_poll_func); diff -Nru fwupd-1.4.5/libfwupdplugin/fu-smbios.c fwupd-1.5.8/libfwupdplugin/fu-smbios.c --- fwupd-1.4.5/libfwupdplugin/fu-smbios.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-smbios.c 2021-03-31 20:08:32.000000000 +0000 @@ -16,8 +16,7 @@ #include "fwupd-error.h" struct _FuSmbios { - GObject parent_instance; - gchar *smbios_ver; + FuFirmware parent_instance; guint32 structure_table_len; GPtrArray *items; }; @@ -54,34 +53,117 @@ guint64 structure_table_addr; } FuSmbiosStructureEntryPoint64; -/* little endian */ -typedef struct __attribute__((packed)) { - guint8 type; - guint8 len; - guint16 handle; -} FuSmbiosStructure; - typedef struct { guint8 type; guint16 handle; - GBytes *data; + GByteArray *buf; GPtrArray *strings; } FuSmbiosItem; -G_DEFINE_TYPE (FuSmbios, fu_smbios, G_TYPE_OBJECT) +G_DEFINE_TYPE (FuSmbios, fu_smbios, FU_TYPE_FIRMWARE) + +static void +fu_smbios_convert_dt_value (FuSmbios *self, guint8 type, guint8 offset, guint8 value) +{ + FuSmbiosItem *item = g_ptr_array_index (self->items, type); + for (guint i = item->buf->len; i < (guint) offset + 1; i++) + fu_byte_array_append_uint8 (item->buf, 0x0); + item->buf->data[offset] = value; +} + +static void +fu_smbios_convert_dt_string (FuSmbios *self, guint8 type, guint8 offset, + const gchar *path, const gchar *subpath) +{ + FuSmbiosItem *item = g_ptr_array_index (self->items, type); + gsize bufsz = 0; + g_autofree gchar *fn = g_build_filename (path, subpath, NULL); + g_autofree gchar *buf = NULL; + + /* not found */ + if (!g_file_get_contents (fn, &buf, &bufsz, NULL)) + return; + + /* add to strtab */ + g_ptr_array_add (item->strings, g_strndup (buf, bufsz)); + fu_smbios_convert_dt_value (self, type, offset, item->strings->len); +} + +static gboolean +fu_smbios_setup_from_path_dt (FuSmbios *self, const gchar *path, GError **error) +{ + g_autofree gchar *fn_battery = NULL; + + /* add all four faked structures */ + for (guint i = 0; i < FU_SMBIOS_STRUCTURE_TYPE_LAST; i++) { + FuSmbiosItem *item = g_new0 (FuSmbiosItem, 1); + item->type = i; + item->buf = g_byte_array_new (); + item->strings = g_ptr_array_new_with_free_func (g_free); + g_ptr_array_add (self->items, item); + } + + /* if it has a battery it is portable (probably a laptop) */ + fn_battery = g_build_filename (path, "battery", NULL); + if (g_file_test (fn_battery, G_FILE_TEST_EXISTS)) { + fu_smbios_convert_dt_value (self, + FU_SMBIOS_STRUCTURE_TYPE_CHASSIS, 0x05, + FU_SMBIOS_CHASSIS_KIND_PORTABLE); + } + + /* DMI:Manufacturer */ + fu_smbios_convert_dt_string (self, FU_SMBIOS_STRUCTURE_TYPE_SYSTEM, 0x04, + path, "vendor"); + + /* DMI:Family */ + fu_smbios_convert_dt_string (self, FU_SMBIOS_STRUCTURE_TYPE_SYSTEM, 0x1a, + path, "model-name"); + + /* DMI:ProductName */ + fu_smbios_convert_dt_string (self, FU_SMBIOS_STRUCTURE_TYPE_SYSTEM, 0x05, + path, "model"); + + /* DMI:BiosVersion */ + fu_smbios_convert_dt_string (self, FU_SMBIOS_STRUCTURE_TYPE_BIOS, 0x05, + path, "ibm,firmware-versions/version"); + + /* DMI:BaseboardManufacturer */ + fu_smbios_convert_dt_string (self, FU_SMBIOS_STRUCTURE_TYPE_BASEBOARD, 0x04, + path, "vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/vendor"); + + /* DMI:BaseboardProduct */ + fu_smbios_convert_dt_string (self, FU_SMBIOS_STRUCTURE_TYPE_BASEBOARD, 0x05, + path, "vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/part-number"); + + return TRUE; +} static gboolean fu_smbios_setup_from_data (FuSmbios *self, const guint8 *buf, gsize sz, GError **error) { /* go through each structure */ for (gsize i = 0; i < sz; i++) { - FuSmbiosStructure *str = (FuSmbiosStructure *) &buf[i]; FuSmbiosItem *item; + guint16 str_handle = 0; + guint8 str_len = 0; + guint8 str_type = 0; + + /* le */ + if (!fu_common_read_uint8_safe (buf, sz, i + 0x0, + &str_type, error)) + return FALSE; + if (!fu_common_read_uint8_safe (buf, sz, i + 0x1, + &str_len, error)) + return FALSE; + if (!fu_common_read_uint16_safe (buf, sz, i + 0x2, + &str_handle, G_LITTLE_ENDIAN, + error)) + return FALSE; /* invalid */ - if (str->len == 0x00) + if (str_len == 0x00) break; - if (str->len >= sz) { + if (i + str_len >= sz) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, @@ -91,14 +173,15 @@ /* create a new result */ item = g_new0 (FuSmbiosItem, 1); - item->type = str->type; - item->handle = GUINT16_FROM_LE (str->handle); - item->data = g_bytes_new (buf + i, str->len); + item->type = str_type; + item->handle = GUINT16_FROM_LE (str_handle); + item->buf = g_byte_array_sized_new (str_len); item->strings = g_ptr_array_new_with_free_func (g_free); + g_byte_array_append (item->buf, buf + i, str_len); g_ptr_array_add (self->items, item); /* jump to the end of the struct */ - i += str->len; + i += str_len; if (buf[i] == '\0' && buf[i+1] == '\0') { i++; continue; @@ -135,6 +218,18 @@ { gsize sz = 0; g_autofree gchar *buf = NULL; + g_autofree gchar *basename = NULL; + + g_return_val_if_fail (FU_IS_SMBIOS (self), FALSE); + g_return_val_if_fail (filename != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* use a heuristic */ + basename = g_path_get_basename (filename); + if (g_strcmp0 (basename, "base") == 0) + return fu_smbios_setup_from_path_dt (self, filename, error); + + /* DMI blob */ if (!g_file_get_contents (filename, &buf, &sz, error)) return FALSE; return fu_smbios_setup_from_data (self, (guint8 *) buf, sz, error); @@ -145,6 +240,7 @@ { FuSmbiosStructureEntryPoint32 *ep; guint8 csum = 0; + g_autofree gchar *version_str = NULL; /* verify size */ if (sz != sizeof(FuSmbiosStructureEntryPoint32)) { @@ -188,9 +284,13 @@ return FALSE; } self->structure_table_len = GUINT16_FROM_LE (ep->structure_table_len); - self->smbios_ver = g_strdup_printf ("%u.%u", - ep->smbios_major_ver, - ep->smbios_minor_ver); + version_str = g_strdup_printf ("%u.%u", + ep->smbios_major_ver, + ep->smbios_minor_ver); + fu_firmware_set_version (FU_FIRMWARE (self), version_str); + fu_firmware_set_version_raw (FU_FIRMWARE (self), + (((guint16) ep->smbios_major_ver) << 8) + + ep->smbios_minor_ver); return TRUE; } @@ -199,6 +299,7 @@ { FuSmbiosStructureEntryPoint64 *ep; guint8 csum = 0; + g_autofree gchar *version_str = NULL; /* verify size */ if (sz != sizeof(FuSmbiosStructureEntryPoint64)) { @@ -223,26 +324,15 @@ } ep = (FuSmbiosStructureEntryPoint64 *) buf; self->structure_table_len = GUINT32_FROM_LE (ep->structure_table_len); - self->smbios_ver = g_strdup_printf ("%u.%u", - ep->smbios_major_ver, - ep->smbios_minor_ver); + version_str = g_strdup_printf ("%u.%u", + ep->smbios_major_ver, + ep->smbios_minor_ver); + fu_firmware_set_version (FU_FIRMWARE (self), version_str); return TRUE; } -/** - * fu_smbios_setup_from_path: - * @self: A #FuSmbios - * @path: A path, e.g. `/sys/firmware/dmi/tables` - * @error: A #GError or %NULL - * - * Reads all the SMBIOS values from a specific path. - * - * Returns: %TRUE for success - * - * Since: 1.0.0 - **/ -gboolean -fu_smbios_setup_from_path (FuSmbios *self, const gchar *path, GError **error) +static gboolean +fu_smbios_setup_from_path_dmi (FuSmbios *self, const gchar *path, GError **error) { gsize sz = 0; g_autofree gchar *dmi_fn = NULL; @@ -304,6 +394,48 @@ return fu_smbios_setup_from_data (self, (guint8 *) dmi_raw, sz, error); } +static gboolean +fu_smbios_parse (FuFirmware *firmware, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error) +{ + FuSmbios *self = FU_SMBIOS (firmware); + gsize bufsz = 0; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + return fu_smbios_setup_from_data (self, buf, bufsz, error); +} + +/** + * fu_smbios_setup_from_path: + * @self: A #FuSmbios + * @path: A path, e.g. `/sys/firmware/dmi/tables` + * @error: A #GError or %NULL + * + * Reads all the SMBIOS values from a specific path. + * + * Returns: %TRUE for success + * + * Since: 1.0.0 + **/ +gboolean +fu_smbios_setup_from_path (FuSmbios *self, const gchar *path, GError **error) +{ + g_autofree gchar *basename = NULL; + + g_return_val_if_fail (FU_IS_SMBIOS (self), FALSE); + g_return_val_if_fail (path != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* use a heuristic */ + basename = g_path_get_basename (path); + if (g_strcmp0 (basename, "base") == 0) + return fu_smbios_setup_from_path_dt (self, path, error); + return fu_smbios_setup_from_path_dmi (self, path, error); +} + /** * fu_smbios_setup: * @self: A #FuSmbios @@ -319,11 +451,49 @@ fu_smbios_setup (FuSmbios *self, GError **error) { g_autofree gchar *path = NULL; + g_autofree gchar *path_dt = NULL; g_autofree gchar *sysfsfwdir = NULL; + g_return_val_if_fail (FU_IS_SMBIOS (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); + + /* DMI */ path = g_build_filename (sysfsfwdir, "dmi", "tables", NULL); - return fu_smbios_setup_from_path (self, path, error); + if (g_file_test (path, G_FILE_TEST_EXISTS)) + return fu_smbios_setup_from_path (self, path, error); + + /* DT */ + path_dt = g_build_filename (sysfsfwdir, "devicetree", "base", NULL); + if (g_file_test (path_dt, G_FILE_TEST_EXISTS)) + return fu_smbios_setup_from_path (self, path_dt, error); + + /* neither found */ + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "neither SMBIOS or DT found"); + return FALSE; + +} + +static void +fu_smbios_to_string_internal (FuFirmware *firmware, guint idt, GString *str) +{ + FuSmbios *self = FU_SMBIOS (firmware); + for (guint i = 0; i < self->items->len; i++) { + FuSmbiosItem *item = g_ptr_array_index (self->items, i); + fu_common_string_append_kx (str, idt + 0, "Type", item->type); + fu_common_string_append_kx (str, idt + 1, "Length", item->buf->len); + fu_common_string_append_kx (str, idt + 1, "Handle", item->handle); + for (guint j = 0; j < item->strings->len; j++) { + const gchar *tmp = g_ptr_array_index (item->strings, j); + g_autofree gchar *title = g_strdup_printf ("String[%02u]", j); + g_autofree gchar *value = fu_common_strsafe (tmp, 20); + fu_common_string_append_kv (str, idt + 2, title, value); + } + } } /** @@ -339,24 +509,8 @@ gchar * fu_smbios_to_string (FuSmbios *self) { - GString *str; - g_return_val_if_fail (FU_IS_SMBIOS (self), NULL); - - str = g_string_new (NULL); - g_string_append_printf (str, "SmbiosVersion: %s\n", self->smbios_ver); - for (guint i = 0; i < self->items->len; i++) { - FuSmbiosItem *item = g_ptr_array_index (self->items, i); - g_string_append_printf (str, "Type: %02x\n", item->type); - g_string_append_printf (str, " Length: %" G_GSIZE_FORMAT "\n", - g_bytes_get_size (item->data)); - g_string_append_printf (str, " Handle: 0x%04x\n", item->handle); - for (guint j = 0; j < item->strings->len; j++) { - const gchar *tmp = g_ptr_array_index (item->strings, j); - g_string_append_printf (str, " String[%02u]: %s\n", j, tmp); - } - } - return g_string_free (str, FALSE); + return fu_firmware_to_string (FU_FIRMWARE (self)); } static FuSmbiosItem * @@ -386,7 +540,10 @@ fu_smbios_get_data (FuSmbios *self, guint8 type, GError **error) { FuSmbiosItem *item; + g_return_val_if_fail (FU_IS_SMBIOS (self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + item = fu_smbios_get_item_for_type (self, type); if (item == NULL) { g_set_error (error, @@ -395,7 +552,55 @@ "no structure with type %02x", type); return NULL; } - return g_bytes_ref (item->data); + return g_bytes_new (item->buf->data, item->buf->len); +} + +/** + * fu_smbios_get_integer: + * @self: A #FuSmbios + * @type: A structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS + * @offset: A structure offset + * @error: A #GError or %NULL + * + * Reads an integer value from the SMBIOS string table of a specific structure. + * + * The @type and @offset can be referenced from the DMTF SMBIOS specification: + * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.1.1.pdf + * + * Returns: an integer, or %G_MAXUINT if invalid or not found + * + * Since: 1.5.0 + **/ +guint +fu_smbios_get_integer (FuSmbios *self, guint8 type, guint8 offset, GError **error) +{ + FuSmbiosItem *item; + + g_return_val_if_fail (FU_IS_SMBIOS (self), 0); + g_return_val_if_fail (error == NULL || *error == NULL, 0); + + /* get item */ + item = fu_smbios_get_item_for_type (self, type); + if (item == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "no structure with type %02x", type); + return G_MAXUINT; + } + + /* check offset valid */ + if (offset >= item->buf->len) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "offset bigger than size %u", + item->buf->len); + return G_MAXUINT; + } + + /* success */ + return item->buf->data[offset]; } /** @@ -418,10 +623,9 @@ fu_smbios_get_string (FuSmbios *self, guint8 type, guint8 offset, GError **error) { FuSmbiosItem *item; - const guint8 *data; - gsize sz; g_return_val_if_fail (FU_IS_SMBIOS (self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* get item */ item = fu_smbios_get_item_for_type (self, type); @@ -434,15 +638,15 @@ } /* check offset valid */ - data = g_bytes_get_data (item->data, &sz); - if (offset >= sz) { + if (offset >= item->buf->len) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "offset bigger than size %" G_GSIZE_FORMAT, sz); + "offset bigger than size %u", + item->buf->len); return NULL; } - if (data[offset] == 0x00) { + if (item->buf->data[offset] == 0x00) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, @@ -451,21 +655,21 @@ } /* check string index valid */ - if (data[offset] > item->strings->len) { + if (item->buf->data[offset] > item->strings->len) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "index larger than string table %u", - data[offset]); + item->strings->len); return NULL; } - return g_ptr_array_index (item->strings, data[offset] - 1); + return g_ptr_array_index (item->strings, item->buf->data[offset] - 1); } static void fu_smbios_item_free (FuSmbiosItem *item) { - g_bytes_unref (item->data); + g_byte_array_unref (item->buf); g_ptr_array_unref (item->strings); g_free (item); } @@ -474,7 +678,6 @@ fu_smbios_finalize (GObject *object) { FuSmbios *self = FU_SMBIOS (object); - g_free (self->smbios_ver); g_ptr_array_unref (self->items); G_OBJECT_CLASS (fu_smbios_parent_class)->finalize (object); } @@ -483,7 +686,10 @@ fu_smbios_class_init (FuSmbiosClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); object_class->finalize = fu_smbios_finalize; + klass_firmware->parse = fu_smbios_parse; + klass_firmware->to_string = fu_smbios_to_string_internal; } static void diff -Nru fwupd-1.4.5/libfwupdplugin/fu-smbios.h fwupd-1.5.8/libfwupdplugin/fu-smbios.h --- fwupd-1.4.5/libfwupdplugin/fu-smbios.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-smbios.h 2021-03-31 20:08:32.000000000 +0000 @@ -8,9 +8,11 @@ #include +#include "fu-firmware.h" + #define FU_TYPE_SMBIOS (fu_smbios_get_type ()) -G_DECLARE_FINAL_TYPE (FuSmbios, fu_smbios, FU, SMBIOS, GObject) +G_DECLARE_FINAL_TYPE (FuSmbios, fu_smbios, FU, SMBIOS, FuFirmware) FuSmbios *fu_smbios_new (void); @@ -18,6 +20,47 @@ #define FU_SMBIOS_STRUCTURE_TYPE_SYSTEM 0x01 #define FU_SMBIOS_STRUCTURE_TYPE_BASEBOARD 0x02 #define FU_SMBIOS_STRUCTURE_TYPE_CHASSIS 0x03 +#define FU_SMBIOS_STRUCTURE_TYPE_LAST 0x04 + +typedef enum { + FU_SMBIOS_CHASSIS_KIND_OTHER = 0x01, + FU_SMBIOS_CHASSIS_KIND_UNKNOWN = 0x02, + FU_SMBIOS_CHASSIS_KIND_DESKTOP = 0x03, + FU_SMBIOS_CHASSIS_KIND_LOW_PROFILE_DESKTOP = 0x04, + FU_SMBIOS_CHASSIS_KIND_PIZZA_BOX = 0x05, + FU_SMBIOS_CHASSIS_KIND_MINI_TOWER = 0x06, + FU_SMBIOS_CHASSIS_KIND_TOWER = 0x07, + FU_SMBIOS_CHASSIS_KIND_PORTABLE = 0x08, + FU_SMBIOS_CHASSIS_KIND_LAPTOP = 0x09, + FU_SMBIOS_CHASSIS_KIND_NOTEBOOK = 0x0A, + FU_SMBIOS_CHASSIS_KIND_HAND_HELD = 0x0B, + FU_SMBIOS_CHASSIS_KIND_DOCKING_STATION = 0x0C, + FU_SMBIOS_CHASSIS_KIND_ALL_IN_ONE = 0x0D, + FU_SMBIOS_CHASSIS_KIND_SUB_NOTEBOOK = 0x0E, + FU_SMBIOS_CHASSIS_KIND_SPACE_SAVING = 0x0F, + FU_SMBIOS_CHASSIS_KIND_LUNCH_BOX = 0x10, + FU_SMBIOS_CHASSIS_KIND_MAIN_SERVER = 0x11, + FU_SMBIOS_CHASSIS_KIND_EXPANSION = 0x12, + FU_SMBIOS_CHASSIS_KIND_SUBCHASSIS = 0x13, + FU_SMBIOS_CHASSIS_KIND_BUS_EXPANSION = 0x14, + FU_SMBIOS_CHASSIS_KIND_PERIPHERAL = 0x15, + FU_SMBIOS_CHASSIS_KIND_RAID = 0x16, + FU_SMBIOS_CHASSIS_KIND_RACK_MOUNT = 0x17, + FU_SMBIOS_CHASSIS_KIND_SEALED_CASE_PC = 0x18, + FU_SMBIOS_CHASSIS_KIND_MULTI_SYSTEM = 0x19, + FU_SMBIOS_CHASSIS_KIND_COMPACT_PCI = 0x1A, + FU_SMBIOS_CHASSIS_KIND_ADVANCED_TCA = 0x1B, + FU_SMBIOS_CHASSIS_KIND_BLADE = 0x1C, + FU_SMBIOS_CHASSIS_KIND_TABLET = 0x1E, + FU_SMBIOS_CHASSIS_KIND_CONVERTIBLE = 0x1F, + FU_SMBIOS_CHASSIS_KIND_DETACHABLE = 0x20, + FU_SMBIOS_CHASSIS_KIND_IOT_GATEWAY = 0x21, + FU_SMBIOS_CHASSIS_KIND_EMBEDDED_PC = 0x22, + FU_SMBIOS_CHASSIS_KIND_MINI_PC = 0x23, + FU_SMBIOS_CHASSIS_KIND_STICK_PC = 0x24, + /*< private >*/ + FU_SMBIOS_CHASSIS_KIND_LAST, +} FuSmbiosChassisKind; gchar *fu_smbios_to_string (FuSmbios *self); @@ -25,6 +68,10 @@ guint8 type, guint8 offset, GError **error); +guint fu_smbios_get_integer (FuSmbios *self, + guint8 type, + guint8 offset, + GError **error); GBytes *fu_smbios_get_data (FuSmbios *self, guint8 type, GError **error); diff -Nru fwupd-1.4.5/libfwupdplugin/fu-smbios-private.h fwupd-1.5.8/libfwupdplugin/fu-smbios-private.h --- fwupd-1.4.5/libfwupdplugin/fu-smbios-private.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-smbios-private.h 2021-03-31 20:08:32.000000000 +0000 @@ -11,10 +11,13 @@ #include "fu-smbios.h" gboolean fu_smbios_setup (FuSmbios *self, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_smbios_setup_from_path (FuSmbios *self, const gchar *path, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_smbios_setup_from_file (FuSmbios *self, const gchar *filename, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; diff -Nru fwupd-1.4.5/libfwupdplugin/fu-srec-firmware.c fwupd-1.5.8/libfwupdplugin/fu-srec-firmware.c --- fwupd-1.4.5/libfwupdplugin/fu-srec-firmware.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-srec-firmware.c 2021-03-31 20:08:32.000000000 +0000 @@ -98,6 +98,7 @@ const gchar *line = lines[ln]; gsize linesz; guint32 rec_addr32; + guint16 rec_addr16; guint8 addrsz = 0; /* bytes */ guint8 rec_count; /* words */ guint8 rec_kind; @@ -110,27 +111,27 @@ /* check starting token */ if (line[0] != 'S') { + g_autofree gchar *strsafe = fu_common_strsafe (line, 3); + if (strsafe != NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "invalid starting token, got '%s' at line %u", + strsafe, ln + 1); + return FALSE; + } g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "invalid starting token, got '%c' at line %u", - line[0], ln + 1); - return FALSE; - } - - /* check there's enough data for the smallest possible record */ - if (linesz < 10) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "record incomplete at line %u, length %u", - ln + 1, (guint) linesz); + "invalid starting token at line %u", + ln + 1); return FALSE; } /* kind, count, address, (data), checksum, linefeed */ rec_kind = line[1] - '0'; - rec_count = fu_firmware_strparse_uint8 (line + 2); + if (!fu_firmware_strparse_uint8_safe (line, linesz, 2, &rec_count, error)) + return FALSE; if (rec_count * 2 != linesz - 4) { g_set_error (error, FWUPD_ERROR, @@ -142,13 +143,24 @@ } /* checksum check */ - if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + if ((flags & FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM) == 0) { guint8 rec_csum = 0; guint8 rec_csum_expected; - for (guint8 i = 0; i < rec_count; i++) - rec_csum += fu_firmware_strparse_uint8 (line + (i * 2) + 2); + for (guint8 i = 0; i < rec_count; i++) { + guint8 csum_tmp = 0; + if (!fu_firmware_strparse_uint8_safe (line, linesz, + (i * 2) + 2, + &csum_tmp, + error)) + return FALSE; + rec_csum += csum_tmp; + } rec_csum ^= 0xff; - rec_csum_expected = fu_firmware_strparse_uint8 (line + (rec_count * 2) + 2); + if (!fu_firmware_strparse_uint8_safe (line, linesz, + (rec_count * 2) + 2, + &rec_csum_expected, + error)) + return FALSE; if (rec_csum != rec_csum_expected) { g_set_error (error, FWUPD_ERROR, @@ -205,13 +217,23 @@ /* parse address */ switch (addrsz) { case 2: - rec_addr32 = fu_firmware_strparse_uint16 (line + 4); + if (!fu_firmware_strparse_uint16_safe (line, linesz, + 4, &rec_addr16, + error)) + return FALSE; + rec_addr32 = rec_addr16; break; case 3: - rec_addr32 = fu_firmware_strparse_uint24 (line + 4); + if (!fu_firmware_strparse_uint24_safe (line, linesz, + 4, &rec_addr32, + error)) + return FALSE; break; case 4: - rec_addr32 = fu_firmware_strparse_uint32 (line + 4); + if (!fu_firmware_strparse_uint32_safe (line, linesz, + 4, &rec_addr32, + error)) + return FALSE; break; default: g_assert_not_reached (); @@ -224,8 +246,10 @@ /* data */ rcd = fu_srec_firmware_record_new (ln + 1, rec_kind, rec_addr32); if (rec_kind == 1 || rec_kind == 2 || rec_kind == 3) { - for (guint8 i = 4 + (addrsz * 2); i <= rec_count * 2; i += 2) { - guint8 tmp = fu_firmware_strparse_uint8 (line + i); + for (gsize i = 4 + (addrsz * 2); i <= rec_count * 2; i += 2) { + guint8 tmp = 0; + if (!fu_firmware_strparse_uint8_safe (line, linesz, i, &tmp, error)) + return FALSE; fu_byte_array_append_uint8 (rcd->buf, tmp); } } @@ -356,6 +380,14 @@ if (img_address == 0x0) img_address = rcd->addr; addr32_last = rcd->addr + rcd->buf->len; + if (addr32_last < rcd->addr) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "overflow from address 0x%x at line %u", + (guint) rcd->addr, rcd->ln); + return FALSE; + } } data_cnt++; } @@ -381,6 +413,7 @@ fu_srec_firmware_init (FuSrecFirmware *self) { self->records = g_ptr_array_new_with_free_func ((GFreeFunc) fu_srec_firmware_record_free); + fu_firmware_add_flag (FU_FIRMWARE (self), FU_FIRMWARE_FLAG_HAS_CHECKSUM); } static void diff -Nru fwupd-1.4.5/libfwupdplugin/fu-srec-firmware.h fwupd-1.5.8/libfwupdplugin/fu-srec-firmware.h --- fwupd-1.4.5/libfwupdplugin/fu-srec-firmware.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-srec-firmware.h 2021-03-31 20:08:32.000000000 +0000 @@ -25,6 +25,9 @@ FU_FIRMWARE_SREC_RECORD_KIND_LAST } FuFirmareSrecRecordKind; +/** + * FuSrecFirmwareRecord: (skip): + **/ typedef struct { guint ln; FuFirmareSrecRecordKind kind; diff -Nru fwupd-1.4.5/libfwupdplugin/fu-udev-device.c fwupd-1.5.8/libfwupdplugin/fu-udev-device.c --- fwupd-1.4.5/libfwupdplugin/fu-udev-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-udev-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2019 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -11,7 +11,7 @@ #include #include #ifdef HAVE_ERRNO_H -#include +#include #endif #ifdef HAVE_IOCTL_H #include @@ -39,8 +39,11 @@ GUdevDevice *udev_device; guint32 vendor; guint32 model; + guint32 subsystem_vendor; + guint32 subsystem_model; guint8 revision; gchar *subsystem; + gchar *driver; gchar *device_file; gint fd; FuUdevDeviceFlags flags; @@ -52,6 +55,7 @@ PROP_0, PROP_UDEV_DEVICE, PROP_SUBSYSTEM, + PROP_DRIVER, PROP_DEVICE_FILE, PROP_LAST }; @@ -76,8 +80,11 @@ void fu_udev_device_emit_changed (FuUdevDevice *self) { + g_autoptr(GError) error = NULL; g_return_if_fail (FU_IS_UDEV_DEVICE (self)); g_debug ("FuUdevDevice emit changed"); + if (!fu_device_rescan (FU_DEVICE (self), &error)) + g_debug ("%s", error->message); g_signal_emit (self, signals[SIGNAL_CHANGED], 0); } @@ -120,6 +127,8 @@ fu_udev_device_to_string_raw (GUdevDevice *udev_device, guint idt, GString *str) { const gchar * const *keys; + if (udev_device == NULL) + return; keys = g_udev_device_get_property_keys (udev_device); for (guint i = 0; keys[i] != NULL; i++) { fu_common_string_append_kv (str, idt, keys[i], @@ -136,24 +145,35 @@ static void fu_udev_device_to_string (FuDevice *device, guint idt, GString *str) { -#ifdef HAVE_GUDEV FuUdevDevice *self = FU_UDEV_DEVICE (device); + FuUdevDeviceClass *klass = FU_UDEV_DEVICE_GET_CLASS (self); +#ifdef HAVE_GUDEV FuUdevDevicePrivate *priv = GET_PRIVATE (self); - g_autoptr(GUdevDevice) udev_parent = NULL; - - if (priv->udev_device == NULL) - return; - - if (g_getenv ("FU_UDEV_DEVICE_DEBUG") == NULL) - return; - - fu_udev_device_to_string_raw (priv->udev_device, idt, str); - udev_parent = g_udev_device_get_parent (priv->udev_device); - if (udev_parent != NULL) { - fu_common_string_append_kv (str, idt, "Parent", NULL); - fu_udev_device_to_string_raw (udev_parent, idt + 1, str); + if (priv->udev_device != NULL) { + fu_common_string_append_kv (str, idt, "SysfsPath", + g_udev_device_get_sysfs_path (priv->udev_device)); + fu_common_string_append_kv (str, idt, "Subsystem", priv->subsystem); + if (priv->driver != NULL) + fu_common_string_append_kv (str, idt, "Driver", priv->driver); + if (priv->device_file != NULL) + fu_common_string_append_kv (str, idt, "DeviceFile", priv->device_file); + } + if (g_getenv ("FU_UDEV_DEVICE_DEBUG") != NULL) { + g_autoptr(GUdevDevice) udev_parent = NULL; + fu_udev_device_to_string_raw (priv->udev_device, idt, str); + udev_parent = g_udev_device_get_parent (priv->udev_device); + if (udev_parent != NULL) { + fu_common_string_append_kv (str, idt, "Parent", NULL); + fu_udev_device_to_string_raw (udev_parent, idt + 1, str); + } } #endif + + /* subclassed */ + if (klass->to_string != NULL) { + g_warning ("FuUdevDevice->to_string is deprecated!"); + klass->to_string (self, idt, str); + } } static void @@ -171,6 +191,20 @@ } static void +fu_udev_device_set_driver (FuUdevDevice *self, const gchar *driver) +{ + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + + /* not changed */ + if (g_strcmp0 (priv->driver, driver) == 0) + return; + + g_free (priv->driver); + priv->driver = g_strdup (driver); + g_object_notify (G_OBJECT (self), "driver"); +} + +static void fu_udev_device_set_device_file (FuUdevDevice *self, const gchar *device_file) { FuUdevDevicePrivate *priv = GET_PRIVATE (self); @@ -184,6 +218,60 @@ g_object_notify (G_OBJECT (self), "device-file"); } +#ifdef HAVE_GUDEV +static const gchar * +fu_udev_device_get_vendor_fallback (GUdevDevice *udev_device) +{ + const gchar *tmp; + tmp = g_udev_device_get_property (udev_device, "ID_VENDOR_FROM_DATABASE"); + if (tmp != NULL) + return tmp; + tmp = g_udev_device_get_property (udev_device, "ID_VENDOR"); + if (tmp != NULL) + return tmp; + return NULL; +} +#endif + +#ifdef HAVE_GUDEV +static gboolean +fu_udev_device_probe_i2c_dev (FuUdevDevice *self, GError **error) +{ + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + const gchar *name = g_udev_device_get_sysfs_attr (priv->udev_device, "name"); + if (name != NULL) { + g_autofree gchar *devid = NULL; + g_autofree gchar *name_safe = g_strdup (name); + g_strdelimit (name_safe, " /\\\"", '-'); + devid = g_strdup_printf ("I2C\\NAME_%s", name_safe); + fu_device_add_instance_id (FU_DEVICE (self), devid); + } + return TRUE; +} + +static gboolean +fu_udev_device_probe_serio (FuUdevDevice *self, GError **error) +{ + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + const gchar *tmp; + + /* firmware ID */ + tmp = g_udev_device_get_property (priv->udev_device, "SERIO_FIRMWARE_ID"); + if (tmp != NULL) { + g_autofree gchar *devid = NULL; + g_autofree gchar *id_safe = NULL; + /* this prefix is not useful */ + if (g_str_has_prefix (tmp, "PNP: ")) + tmp += 5; + id_safe = g_utf8_strup (tmp, -1); + g_strdelimit (id_safe, " /\\\"", '-'); + devid = g_strdup_printf ("SERIO\\FWID_%s", id_safe); + fu_device_add_instance_id (FU_DEVICE (self), devid); + } + return TRUE; +} +#endif + static gboolean fu_udev_device_probe (FuDevice *device, GError **error) { @@ -205,6 +293,8 @@ priv->vendor = fu_udev_device_get_sysfs_attr_as_uint32 (priv->udev_device, "vendor"); priv->model = fu_udev_device_get_sysfs_attr_as_uint32 (priv->udev_device, "device"); priv->revision = fu_udev_device_get_sysfs_attr_as_uint8 (priv->udev_device, "revision"); + priv->subsystem_vendor = fu_udev_device_get_sysfs_attr_as_uint32 (priv->udev_device, "subsystem_vendor"); + priv->subsystem_model = fu_udev_device_get_sysfs_attr_as_uint32 (priv->udev_device, "subsystem_device"); #ifdef HAVE_GUDEV /* fallback to the parent */ @@ -215,6 +305,8 @@ priv->vendor = fu_udev_device_get_sysfs_attr_as_uint32 (udev_parent, "vendor"); priv->model = fu_udev_device_get_sysfs_attr_as_uint32 (udev_parent, "device"); priv->revision = fu_udev_device_get_sysfs_attr_as_uint8 (udev_parent, "revision"); + priv->subsystem_vendor = fu_udev_device_get_sysfs_attr_as_uint32 (udev_parent, "subsystem_vendor"); + priv->subsystem_model = fu_udev_device_get_sysfs_attr_as_uint32 (udev_parent, "subsystem_device"); } /* hidraw helpfully encodes the information in a different place */ @@ -250,26 +342,6 @@ } } - /* try harder to find a vendor name the user will recognise */ - if (priv->flags & FU_UDEV_DEVICE_FLAG_VENDOR_FROM_PARENT && - udev_parent != NULL && fu_device_get_vendor (device) == NULL) { - g_autoptr(GUdevDevice) device_tmp = g_object_ref (udev_parent); - for (guint i = 0; i < 0xff; i++) { - g_autoptr(GUdevDevice) parent = NULL; - const gchar *id_vendor; - id_vendor = g_udev_device_get_property (device_tmp, - "ID_VENDOR_FROM_DATABASE"); - if (id_vendor != NULL) { - fu_device_set_vendor (device, id_vendor); - break; - } - parent = g_udev_device_get_parent (device_tmp); - if (parent == NULL) - break; - g_set_object (&device_tmp, parent); - } - } - /* set the version if the revision has been set */ if (fu_device_get_version (device) == NULL && fu_device_get_version_format (device) == FWUPD_VERSION_FORMAT_UNKNOWN) { @@ -282,9 +354,7 @@ /* set model */ if (fu_device_get_name (device) == NULL) { - tmp = g_udev_device_get_property (priv->udev_device, "FWUPD_MODEL"); - if (tmp == NULL) - tmp = g_udev_device_get_property (priv->udev_device, "ID_MODEL_FROM_DATABASE"); + tmp = g_udev_device_get_property (priv->udev_device, "ID_MODEL_FROM_DATABASE"); if (tmp == NULL) tmp = g_udev_device_get_property (priv->udev_device, "ID_MODEL"); if (tmp == NULL) @@ -295,15 +365,29 @@ /* set vendor */ if (fu_device_get_vendor (device) == NULL) { - tmp = g_udev_device_get_property (priv->udev_device, "FWUPD_VENDOR"); - if (tmp == NULL) - tmp = g_udev_device_get_property (priv->udev_device, "ID_VENDOR_FROM_DATABASE"); - if (tmp == NULL) - tmp = g_udev_device_get_property (priv->udev_device, "ID_VENDOR"); + tmp = fu_udev_device_get_vendor_fallback (priv->udev_device); if (tmp != NULL) fu_device_set_vendor (device, tmp); } + /* try harder to find a vendor name the user will recognize */ + if (priv->flags & FU_UDEV_DEVICE_FLAG_VENDOR_FROM_PARENT && + udev_parent != NULL && fu_device_get_vendor (device) == NULL) { + g_autoptr(GUdevDevice) device_tmp = g_object_ref (udev_parent); + for (guint i = 0; i < 0xff; i++) { + g_autoptr(GUdevDevice) parent = NULL; + tmp = fu_udev_device_get_vendor_fallback (device_tmp); + if (tmp != NULL) { + fu_device_set_vendor (device, tmp); + break; + } + parent = g_udev_device_get_parent (device_tmp); + if (parent == NULL) + break; + g_set_object (&device_tmp, parent); + } + } + /* set serial */ if (fu_device_get_serial (device) == NULL) { tmp = g_udev_device_get_property (priv->udev_device, "ID_SERIAL_SHORT"); @@ -326,10 +410,26 @@ if (subsystem != NULL && priv->vendor != 0x0000) { g_autofree gchar *vendor_id = NULL; vendor_id = g_strdup_printf ("%s:0x%04X", subsystem, (guint) priv->vendor); - fu_device_set_vendor_id (device, vendor_id); + fu_device_add_vendor_id (device, vendor_id); } /* add GUIDs in order of priority */ + if (priv->vendor != 0x0000 && priv->model != 0x0000 && + priv->subsystem_vendor != 0x0000 && priv->subsystem_model != 0x0000) { + g_autofree gchar *devid1 = NULL; + g_autofree gchar *devid2 = NULL; + devid1 = g_strdup_printf ("%s\\VEN_%04X&DEV_%04X&SUBSYS_%04X%04X&REV_%02X", + subsystem, + priv->vendor, priv->model, + priv->subsystem_vendor, priv->subsystem_model, + priv->revision); + fu_device_add_instance_id (device, devid1); + devid2 = g_strdup_printf ("%s\\VEN_%04X&DEV_%04X&SUBSYS_%04X%04X", + subsystem, + priv->vendor, priv->model, + priv->subsystem_vendor, priv->subsystem_model); + fu_device_add_instance_id (device, devid2); + } if (priv->vendor != 0x0000 && priv->model != 0x0000) { g_autofree gchar *devid = NULL; devid = g_strdup_printf ("%s\\VEN_%04X&DEV_%04X&REV_%02X", @@ -350,12 +450,47 @@ FU_DEVICE_INSTANCE_FLAG_ONLY_QUIRKS); } + /* add device class */ + tmp = g_udev_device_get_sysfs_attr (priv->udev_device, "class"); + if (tmp != NULL && g_str_has_prefix (tmp, "0x")) { + g_autofree gchar *class_id = g_utf8_strup (tmp + 2, -1); + g_autofree gchar *devid = NULL; + devid = g_strdup_printf ("%s\\VEN_%04X&CLASS_%s", + subsystem, + priv->vendor, + class_id); + fu_device_add_instance_id_full (device, devid, + FU_DEVICE_INSTANCE_FLAG_ONLY_QUIRKS); + } + + /* add the driver */ + if (priv->driver != NULL) { + g_autofree gchar *devid = NULL; + devid = g_strdup_printf ("%s\\DRIVER_%s", + subsystem, + priv->driver); + fu_device_add_instance_id_full (device, devid, + FU_DEVICE_INSTANCE_FLAG_ONLY_QUIRKS); + } + /* add subsystem to match in plugins */ if (subsystem != NULL) { fu_device_add_instance_id_full (device, subsystem, FU_DEVICE_INSTANCE_FLAG_ONLY_QUIRKS); } + /* i2c devices all expose a name */ + if (g_strcmp0 (g_udev_device_get_subsystem (priv->udev_device), "i2c-dev") == 0) { + if (!fu_udev_device_probe_i2c_dev (self, error)) + return FALSE; + } + + /* add firmware_id */ + if (g_strcmp0 (g_udev_device_get_subsystem (priv->udev_device), "serio") == 0) { + if (!fu_udev_device_probe_serio (self, error)) + return FALSE; + } + /* determine if we're wired internally */ parent_i2c = g_udev_device_get_parent_with_subsystem (priv->udev_device, "i2c", NULL); @@ -365,6 +500,7 @@ /* subclassed */ if (klass->probe != NULL) { + g_warning ("FuUdevDevice->probe is deprecated!"); if (!klass->probe (self, error)) return FALSE; } @@ -373,28 +509,78 @@ return TRUE; } +#ifdef HAVE_GUDEV +static gchar * +fu_udev_device_get_miscdev0 (FuUdevDevice *self) +{ + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + const gchar *fn; + g_autofree gchar *miscdir = NULL; + g_autoptr(GDir) dir = NULL; + + miscdir = g_build_filename (g_udev_device_get_sysfs_path (priv->udev_device), "misc", NULL); + dir = g_dir_open (miscdir, 0, NULL); + if (dir == NULL) + return NULL; + fn = g_dir_read_name (dir); + if (fn == NULL) + return NULL; + return g_strdup_printf ("/dev/%s", fn); +} +#endif + static void fu_udev_device_set_dev (FuUdevDevice *self, GUdevDevice *udev_device) { FuUdevDevicePrivate *priv = GET_PRIVATE (self); #ifdef HAVE_GUDEV const gchar *summary; - g_autoptr(GUdevDevice) parent = NULL; #endif g_return_if_fail (FU_IS_UDEV_DEVICE (self)); - /* set new device */ +#ifdef HAVE_GUDEV + /* the net subsystem is not a real hardware class */ + if (udev_device != NULL && + g_strcmp0 (g_udev_device_get_subsystem (udev_device), "net") == 0) { + g_autoptr(GUdevDevice) udev_device_phys = NULL; + udev_device_phys = g_udev_device_get_parent (udev_device); + g_set_object (&priv->udev_device, udev_device_phys); + fu_device_set_metadata (FU_DEVICE (self), + "ParentSubsystem", + g_udev_device_get_subsystem (udev_device)); + } else { + g_set_object (&priv->udev_device, udev_device); + } +#else g_set_object (&priv->udev_device, udev_device); +#endif + + /* set new device */ if (priv->udev_device == NULL) return; #ifdef HAVE_GUDEV fu_udev_device_set_subsystem (self, g_udev_device_get_subsystem (priv->udev_device)); + fu_udev_device_set_driver (self, g_udev_device_get_driver (priv->udev_device)); fu_udev_device_set_device_file (self, g_udev_device_get_device_file (priv->udev_device)); + /* so we can display something sensible for unclaimed devices */ + fu_device_set_backend_id (FU_DEVICE (self), g_udev_device_get_sysfs_path (priv->udev_device)); + + /* fall back to the first thing handled by misc drivers */ + if (priv->device_file == NULL) { + /* perhaps we should unconditionally fall back? or perhaps + * require FU_UDEV_DEVICE_FLAG_FALLBACK_MISC... */ + if (g_strcmp0 (priv->subsystem, "serio") == 0) + priv->device_file = fu_udev_device_get_miscdev0 (self); + if (priv->device_file != NULL) + g_debug ("falling back to misc %s", priv->device_file); + } + /* try to get one line summary */ summary = g_udev_device_get_sysfs_attr (priv->udev_device, "description"); if (summary == NULL) { + g_autoptr(GUdevDevice) parent = NULL; parent = g_udev_device_get_parent (priv->udev_device); if (parent != NULL) summary = g_udev_device_get_sysfs_attr (parent, "description"); @@ -435,6 +621,120 @@ return 0; } +#ifdef HAVE_GUDEV +static gchar * +fu_udev_device_get_bind_id (FuUdevDevice *self) +{ + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + if (g_strcmp0 (fu_udev_device_get_subsystem (self), "pci") == 0) + return g_strdup (g_udev_device_get_property (priv->udev_device, "PCI_SLOT_NAME")); + if (g_strcmp0 (fu_udev_device_get_subsystem (self), "hid") == 0) + return g_strdup (g_udev_device_get_property (priv->udev_device, "HID_PHYS")); + if (g_strcmp0 (fu_udev_device_get_subsystem (self), "usb") == 0) + return g_path_get_basename (g_udev_device_get_sysfs_path (priv->udev_device)); + return NULL; +} +#endif + +static gboolean +fu_udev_device_unbind_driver (FuDevice *device, GError **error) +{ +#ifdef HAVE_GUDEV + FuUdevDevice *self = FU_UDEV_DEVICE (device); + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + g_autofree gchar *bind_id = NULL; + g_autofree gchar *fn = NULL; + g_autoptr(GFile) file = NULL; + g_autoptr(GOutputStream) stream = NULL; + + /* is already unbound */ + fn = g_build_filename (g_udev_device_get_sysfs_path (priv->udev_device), + "driver", "unbind", NULL); + if (!g_file_test (fn, G_FILE_TEST_EXISTS)) + return TRUE; + + /* write bus ID to file */ + bind_id = fu_udev_device_get_bind_id (self); + if (bind_id == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "bind-id not set for subsystem %s", + priv->subsystem); + return FALSE; + } + file = g_file_new_for_path (fn); + stream = G_OUTPUT_STREAM (g_file_replace (file, NULL, FALSE, + G_FILE_CREATE_NONE, NULL, error)); + if (stream == NULL) + return FALSE; + return g_output_stream_write_all (stream, bind_id, strlen (bind_id), + NULL, NULL, error); +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "driver unbinding not supported"); + return FALSE; +#endif +} + +static gboolean +fu_udev_device_bind_driver (FuDevice *device, + const gchar *subsystem, + const gchar *driver, + GError **error) +{ +#ifdef HAVE_GUDEV + FuUdevDevice *self = FU_UDEV_DEVICE (device); + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + g_autofree gchar *bind_id = NULL; + g_autofree gchar *driver_safe = g_strdup (driver); + g_autofree gchar *fn = NULL; + g_autoptr(GFile) file = NULL; + g_autoptr(GOutputStream) stream = NULL; + + /* copy the logic from modprobe */ + g_strdelimit (driver_safe, "-", '_'); + + /* driver exists */ + fn = g_strdup_printf ("/sys/module/%s/drivers/%s:%s/bind", + driver_safe, subsystem, driver_safe); + if (!g_file_test (fn, G_FILE_TEST_EXISTS)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "cannot bind with %s:%s", + subsystem, driver); + return FALSE; + } + + /* write bus ID to file */ + bind_id = fu_udev_device_get_bind_id (self); + if (bind_id == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "bind-id not set for subsystem %s", + priv->subsystem); + return FALSE; + } + file = g_file_new_for_path (fn); + stream = G_OUTPUT_STREAM (g_file_replace (file, NULL, FALSE, + G_FILE_CREATE_NONE, NULL, error)); + if (stream == NULL) + return FALSE; + return g_output_stream_write_all (stream, bind_id, strlen (bind_id), + NULL, NULL, error); +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "driver binding not supported on Windows"); + return FALSE; +#endif +} + static void fu_udev_device_incorporate (FuDevice *self, FuDevice *donor) { @@ -489,6 +789,24 @@ } /** + * fu_udev_device_get_driver: + * @self: A #FuUdevDevice + * + * Gets the device driver, e.g. "psmouse". + * + * Returns: a subsystem, or NULL if unset or invalid + * + * Since: 1.5.3 + **/ +const gchar * +fu_udev_device_get_driver (FuUdevDevice *self) +{ + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), NULL); + return priv->driver; +} + +/** * fu_udev_device_get_device_file: * @self: A #FuUdevDevice * @@ -529,6 +847,29 @@ } /** + * fu_udev_device_get_number: + * @self: A #FuUdevDevice + * + * Gets the device number, if any. + * + * Returns: integer, 0 if the data is unavailable, or %G_MAXUINT64 if the + * feature is not available + * + * Since: 1.5.0 + **/ +guint64 +fu_udev_device_get_number (FuUdevDevice *self) +{ +#ifdef HAVE_GUDEV + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), 0); + if (priv->udev_device != NULL) + return fu_common_strtoull (g_udev_device_get_number (priv->udev_device)); +#endif + return G_MAXUINT64; +} + +/** * fu_udev_device_get_vendor: * @self: A #FuUdevDevice * @@ -565,6 +906,42 @@ } /** + * fu_udev_device_get_subsystem_vendor: + * @self: A #FuUdevDevice + * + * Gets the device subsystem vendor code. + * + * Returns: a vendor code, or 0 if unset or invalid + * + * Since: 1.5.0 + **/ +guint32 +fu_udev_device_get_subsystem_vendor (FuUdevDevice *self) +{ + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), 0x0000); + return priv->subsystem_vendor; +} + +/** + * fu_udev_device_get_subsystem_model: + * @self: A #FuUdevDevice + * + * Gets the device subsystem model code. + * + * Returns: a vendor code, or 0 if unset or invalid + * + * Since: 1.5.0 + **/ +guint32 +fu_udev_device_get_subsystem_model (FuUdevDevice *self) +{ + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), 0x0000); + return priv->subsystem_model; +} + +/** * fu_udev_device_get_revision: * @self: A #FuUdevDevice * @@ -636,6 +1013,7 @@ g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), FALSE); g_return_val_if_fail (subsystems != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* nothing to do */ if (priv->udev_device == NULL) @@ -677,6 +1055,7 @@ } else if (g_strcmp0 (subsystem, "usb") == 0 || g_strcmp0 (subsystem, "mmc") == 0 || g_strcmp0 (subsystem, "i2c") == 0 || + g_strcmp0 (subsystem, "platform") == 0 || g_strcmp0 (subsystem, "scsi") == 0) { tmp = g_udev_device_get_property (udev_device, "DEVPATH"); if (tmp == NULL) { @@ -730,6 +1109,85 @@ } /** + * fu_udev_device_set_logical_id: + * @self: A #FuUdevDevice + * @subsystem: A subsystem string, e.g. `pci,usb` + * @error: A #GError, or %NULL + * + * Sets the logical ID from the device subsystem. Plugins should choose the + * subsystem that most relevant in the udev tree, for instance choosing 'hid' + * over 'usb' for a mouse device. + * + * Returns: %TRUE if the logical device was set. + * + * Since: 1.5.8 + **/ +gboolean +fu_udev_device_set_logical_id (FuUdevDevice *self, const gchar *subsystem, GError **error) +{ +#ifdef HAVE_GUDEV + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + const gchar *tmp; + g_autofree gchar *logical_id = NULL; + g_autoptr(GUdevDevice) udev_device = NULL; + + g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), FALSE); + g_return_val_if_fail (subsystem != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* nothing to do */ + if (priv->udev_device == NULL) + return TRUE; + + /* find correct device matching subsystem */ + if (g_strcmp0 (priv->subsystem, subsystem) == 0) { + udev_device = g_object_ref (priv->udev_device); + } else { + udev_device = g_udev_device_get_parent_with_subsystem (priv->udev_device, + subsystem, NULL); + } + if (udev_device == NULL) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "failed to find device with subsystem %s", + subsystem); + return FALSE; + } + + /* query each subsystem */ + if (g_strcmp0 (subsystem, "hid") == 0) { + tmp = g_udev_device_get_property (udev_device, "HID_UNIQ"); + if (tmp == NULL) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "failed to find HID_UNIQ"); + return FALSE; + } + logical_id = g_strdup_printf ("HID_UNIQ=%s", tmp); + } else { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "cannot handle subsystem %s", + subsystem); + return FALSE; + } + + /* success */ + fu_device_set_logical_id (FU_DEVICE (self), logical_id); + return TRUE; +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as is unavailable"); + return FALSE; +#endif +} + +/** * fu_udev_device_get_fd: * @self: A #FuUdevDevice * @@ -806,6 +1264,15 @@ FuUdevDevicePrivate *priv = GET_PRIVATE (self); g_return_if_fail (FU_IS_UDEV_DEVICE (self)); priv->flags = flags; + +#ifdef HAVE_GUDEV + /* overwrite */ + if (flags & FU_UDEV_DEVICE_FLAG_USE_CONFIG) { + g_free (priv->device_file); + priv->device_file = g_build_filename (g_udev_device_get_sysfs_path (priv->udev_device), + "config", NULL); + } +#endif } static gboolean @@ -826,6 +1293,10 @@ } else { flags = O_RDONLY; } +#ifdef O_NONBLOCK + if (priv->flags & FU_UDEV_DEVICE_FLAG_OPEN_NONBLOCK) + flags |= O_NONBLOCK; +#endif priv->fd = g_open (priv->device_file, flags, 0); if (priv->fd < 0) { g_set_error (error, @@ -840,6 +1311,7 @@ /* subclassed */ if (klass->open != NULL) { + g_warning ("FuUdevDevice->open is deprecated!"); if (!klass->open (self, error)) return FALSE; } @@ -849,6 +1321,40 @@ } static gboolean +fu_udev_device_rescan (FuDevice *device, GError **error) +{ +#ifdef HAVE_GUDEV + FuUdevDevice *self = FU_UDEV_DEVICE (device); + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + const gchar *sysfs_path; + g_autoptr(GUdevClient) udev_client = g_udev_client_new (NULL); + g_autoptr(GUdevDevice) udev_device = NULL; + + /* never set */ + if (priv->udev_device == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "rescan with no previous device"); + return FALSE; + } + sysfs_path = g_udev_device_get_sysfs_path (priv->udev_device); + udev_device = g_udev_client_query_by_sysfs_path (udev_client, sysfs_path); + if (udev_device == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "rescan could not find device %s", + sysfs_path); + return FALSE; + } + fu_udev_device_set_dev (self, udev_device); + fu_device_probe_invalidate (device); +#endif + return fu_device_probe (device, error); +} + +static gboolean fu_udev_device_close (FuDevice *device, GError **error) { FuUdevDevice *self = FU_UDEV_DEVICE (device); @@ -857,6 +1363,7 @@ /* subclassed */ if (klass->close != NULL) { + g_warning ("FuUdevDevice->close is deprecated!"); if (!klass->close (self, error)) return FALSE; } @@ -900,13 +1407,25 @@ g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), FALSE); g_return_val_if_fail (request != 0x0, FALSE); g_return_val_if_fail (buf != NULL, FALSE); - g_return_val_if_fail (priv->fd > 0, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* not open! */ + if (priv->fd == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "%s [%s] has not been opened", + fu_device_get_id (FU_DEVICE (self)), + fu_device_get_name (FU_DEVICE (self))); + return FALSE; + } rc_tmp = ioctl (priv->fd, request, buf); if (rc != NULL) *rc = rc_tmp; if (rc_tmp < 0) { - if (rc_tmp == -EPERM) { +#ifdef HAVE_ERRNO_H + if (errno == EPERM) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_PERMISSION_DENIED, @@ -916,8 +1435,14 @@ g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, - "ioctl not supported: %s", + "ioctl error: %s", strerror (errno)); +#else + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified ioctl error"); +#endif return FALSE; } return TRUE; @@ -952,9 +1477,19 @@ FuUdevDevicePrivate *priv = GET_PRIVATE (self); g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), FALSE); - g_return_val_if_fail (port != 0x0, FALSE); g_return_val_if_fail (buf != NULL, FALSE); - g_return_val_if_fail (priv->fd > 0, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* not open! */ + if (priv->fd == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "%s [%s] has not been opened", + fu_device_get_id (FU_DEVICE (self)), + fu_device_get_name (FU_DEVICE (self))); + return FALSE; + } #ifdef HAVE_PWRITE if (pread (priv->fd, buf, bufsz, port) != (gssize) bufsz) { @@ -998,8 +1533,18 @@ FuUdevDevicePrivate *priv = GET_PRIVATE (self); g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), FALSE); - g_return_val_if_fail (port != 0x0, FALSE); - g_return_val_if_fail (priv->fd > 0, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* not open! */ + if (priv->fd == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "%s [%s] has not been opened", + fu_device_get_id (FU_DEVICE (self)), + fu_device_get_name (FU_DEVICE (self))); + return FALSE; + } #ifdef HAVE_PWRITE if (pwrite (priv->fd, buf, bufsz, port) != (gssize) bufsz) { @@ -1086,8 +1631,9 @@ FuUdevDevicePrivate *priv = GET_PRIVATE (self); const gchar *result; - g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), FALSE); - g_return_val_if_fail (attr != NULL, FALSE); + g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), NULL); + g_return_val_if_fail (attr != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); /* nothing to do */ if (priv->udev_device == NULL) { @@ -1104,17 +1650,17 @@ G_IO_ERROR_NOT_FOUND, "attribute %s returned no data", attr); - return FALSE; + return NULL; } return result; -#endif +#else g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, "not supported"); return NULL; - +#endif } /** @@ -1163,6 +1709,7 @@ g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), FALSE); g_return_val_if_fail (attribute != NULL, FALSE); g_return_val_if_fail (val != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); path = g_build_filename (fu_udev_device_get_sysfs_path (self), attribute, NULL); @@ -1244,6 +1791,9 @@ case PROP_SUBSYSTEM: g_value_set_string (value, priv->subsystem); break; + case PROP_DRIVER: + g_value_set_string (value, priv->driver); + break; case PROP_DEVICE_FILE: g_value_set_string (value, priv->device_file); break; @@ -1265,6 +1815,9 @@ case PROP_SUBSYSTEM: fu_udev_device_set_subsystem (self, g_value_get_string (value)); break; + case PROP_DRIVER: + fu_udev_device_set_driver (self, g_value_get_string (value)); + break; case PROP_DEVICE_FILE: fu_udev_device_set_device_file (self, g_value_get_string (value)); break; @@ -1281,6 +1834,7 @@ FuUdevDevicePrivate *priv = GET_PRIVATE (self); g_free (priv->subsystem); + g_free (priv->driver); g_free (priv->device_file); if (priv->udev_device != NULL) g_object_unref (priv->udev_device); @@ -1309,10 +1863,13 @@ object_class->get_property = fu_udev_device_get_property; object_class->set_property = fu_udev_device_set_property; device_class->probe = fu_udev_device_probe; + device_class->rescan = fu_udev_device_rescan; device_class->incorporate = fu_udev_device_incorporate; device_class->open = fu_udev_device_open; device_class->close = fu_udev_device_close; device_class->to_string = fu_udev_device_to_string; + device_class->bind_driver = fu_udev_device_bind_driver; + device_class->unbind_driver = fu_udev_device_unbind_driver; signals[SIGNAL_CHANGED] = g_signal_new ("changed", @@ -1333,6 +1890,12 @@ G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_SUBSYSTEM, pspec); + pspec = g_param_spec_string ("driver", NULL, NULL, + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_DRIVER, pspec); + pspec = g_param_spec_string ("device-file", NULL, NULL, NULL, G_PARAM_READWRITE | diff -Nru fwupd-1.4.5/libfwupdplugin/fu-udev-device.h fwupd-1.5.8/libfwupdplugin/fu-udev-device.h --- fwupd-1.4.5/libfwupdplugin/fu-udev-device.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-udev-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2019 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -29,7 +29,10 @@ GError **error); gboolean (*close) (FuUdevDevice *device, GError **error); - gpointer __reserved[29]; + void (*to_string) (FuUdevDevice *self, + guint indent, + GString *str); + gpointer __reserved[28]; }; /** @@ -38,6 +41,8 @@ * @FU_UDEV_DEVICE_FLAG_OPEN_READ: Open the device read-only * @FU_UDEV_DEVICE_FLAG_OPEN_WRITE: Open the device write-only * @FU_UDEV_DEVICE_FLAG_VENDOR_FROM_PARENT: Get the vendor ID fallback from the parent + * @FU_UDEV_DEVICE_FLAG_USE_CONFIG: Read and write from the device config + * @FU_UDEV_DEVICE_FLAG_OPEN_NONBLOCK: Open nonblocking, e.g. O_NONBLOCK * * Flags used when opening the device using fu_device_open(). **/ @@ -46,6 +51,8 @@ FU_UDEV_DEVICE_FLAG_OPEN_READ = 1 << 0, FU_UDEV_DEVICE_FLAG_OPEN_WRITE = 1 << 1, FU_UDEV_DEVICE_FLAG_VENDOR_FROM_PARENT = 1 << 2, + FU_UDEV_DEVICE_FLAG_USE_CONFIG = 1 << 3, + FU_UDEV_DEVICE_FLAG_OPEN_NONBLOCK = 1 << 4, /*< private >*/ FU_UDEV_DEVICE_FLAG_LAST } FuUdevDeviceFlags; @@ -55,14 +62,23 @@ const gchar *fu_udev_device_get_device_file (FuUdevDevice *self); const gchar *fu_udev_device_get_sysfs_path (FuUdevDevice *self); const gchar *fu_udev_device_get_subsystem (FuUdevDevice *self); +const gchar *fu_udev_device_get_driver (FuUdevDevice *self); guint32 fu_udev_device_get_vendor (FuUdevDevice *self); guint32 fu_udev_device_get_model (FuUdevDevice *self); +guint32 fu_udev_device_get_subsystem_vendor (FuUdevDevice *self); +guint32 fu_udev_device_get_subsystem_model (FuUdevDevice *self); guint8 fu_udev_device_get_revision (FuUdevDevice *self); +guint64 fu_udev_device_get_number (FuUdevDevice *self); guint fu_udev_device_get_slot_depth (FuUdevDevice *self, const gchar *subsystem); gboolean fu_udev_device_set_physical_id (FuUdevDevice *self, const gchar *subsystems, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fu_udev_device_set_logical_id (FuUdevDevice *self, + const gchar *subsystem, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; void fu_udev_device_set_readonly (FuUdevDevice *self, gboolean readonly) G_GNUC_DEPRECATED_FOR(fu_udev_device_set_flags); @@ -76,25 +92,30 @@ gulong request, guint8 *buf, gint *rc, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_udev_device_pwrite (FuUdevDevice *self, goffset port, guint8 data, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_udev_device_pwrite_full (FuUdevDevice *self, goffset port, const guint8 *buf, gsize bufsz, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_udev_device_pread (FuUdevDevice *self, goffset port, guint8 *data, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_udev_device_pread_full (FuUdevDevice *self, goffset port, guint8 *buf, gsize bufsz, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; const gchar *fu_udev_device_get_sysfs_attr (FuUdevDevice *self, const gchar *attr, GError **error); @@ -103,5 +124,6 @@ gboolean fu_udev_device_write_sysfs (FuUdevDevice *self, const gchar *attribute, const gchar *val, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; const gchar *fu_udev_device_get_devtype (FuUdevDevice *self); diff -Nru fwupd-1.4.5/libfwupdplugin/fu-udev-device-private.h fwupd-1.5.8/libfwupdplugin/fu-udev-device-private.h --- fwupd-1.4.5/libfwupdplugin/fu-udev-device-private.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-udev-device-private.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/libfwupdplugin/fu-usb-device.c fwupd-1.5.8/libfwupdplugin/fu-usb-device.c --- fwupd-1.4.5/libfwupdplugin/fu-usb-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-usb-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -83,6 +83,7 @@ static void fu_usb_device_init (FuUsbDevice *device) { +#ifdef HAVE_GUSB fu_device_retry_add_recovery (FU_DEVICE (device), G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_NO_DEVICE, @@ -91,6 +92,7 @@ G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_PERMISSION_DENIED, NULL); +#endif } /** @@ -111,6 +113,7 @@ return priv->usb_device_locker != NULL; } +#ifdef HAVE_GUSB static gboolean fu_usb_device_query_hub (FuUsbDevice *self, GError **error) { @@ -153,6 +156,7 @@ } return TRUE; } +#endif static gboolean fu_usb_device_open (FuDevice *device, GError **error) @@ -160,8 +164,9 @@ FuUsbDevice *self = FU_USB_DEVICE (device); FuUsbDevicePrivate *priv = GET_PRIVATE (self); FuUsbDeviceClass *klass = FU_USB_DEVICE_GET_CLASS (device); - guint idx; g_autoptr(FuDeviceLocker) locker = NULL; +#ifdef HAVE_GUSB + guint idx; g_return_val_if_fail (FU_IS_USB_DEVICE (self), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); @@ -258,9 +263,11 @@ if (!fu_usb_device_query_hub (self, error)) return FALSE; } +#endif /* subclassed */ if (klass->open != NULL) { + g_warning ("FuUsbDevice->open is deprecated!"); if (!klass->open (self, error)) return FALSE; } @@ -286,6 +293,7 @@ /* subclassed */ if (klass->close != NULL) { + g_warning ("FuUsbDevice->close is deprecated!"); if (!klass->close (self, error)) return FALSE; } @@ -299,6 +307,7 @@ { FuUsbDevice *self = FU_USB_DEVICE (device); FuUsbDeviceClass *klass = FU_USB_DEVICE_GET_CLASS (device); +#ifdef HAVE_GUSB FuUsbDevicePrivate *priv = GET_PRIVATE (self); guint16 release; g_autofree gchar *devid0 = NULL; @@ -309,7 +318,7 @@ /* set vendor ID */ vendor_id = g_strdup_printf ("USB:0x%04X", g_usb_device_get_vid (priv->usb_device)); - fu_device_set_vendor_id (device, vendor_id); + fu_device_add_vendor_id (device, vendor_id); /* set the version if the release has been set */ release = g_usb_device_get_release (priv->usb_device); @@ -361,9 +370,11 @@ fu_device_add_instance_id_full (device, intid3, FU_DEVICE_INSTANCE_FLAG_ONLY_QUIRKS); } +#endif /* subclassed */ if (klass->probe != NULL) { + g_warning ("FuUsbDevice->probe is deprecated!"); if (!klass->probe (self, error)) return FALSE; } @@ -385,11 +396,15 @@ guint16 fu_usb_device_get_vid (FuUsbDevice *self) { +#ifdef HAVE_GUSB FuUsbDevicePrivate *priv = GET_PRIVATE (self); g_return_val_if_fail (FU_IS_USB_DEVICE (self), 0x0000); if (priv->usb_device == NULL) return 0x0; return g_usb_device_get_vid (priv->usb_device); +#else + return 0x0; +#endif } /** @@ -405,11 +420,15 @@ guint16 fu_usb_device_get_pid (FuUsbDevice *self) { +#ifdef HAVE_GUSB FuUsbDevicePrivate *priv = GET_PRIVATE (self); g_return_val_if_fail (FU_IS_USB_DEVICE (self), 0x0000); if (priv->usb_device == NULL) return 0x0; return g_usb_device_get_pid (priv->usb_device); +#else + return 0x0; +#endif } /** @@ -425,11 +444,15 @@ const gchar * fu_usb_device_get_platform_id (FuUsbDevice *self) { +#ifdef HAVE_GUSB FuUsbDevicePrivate *priv = GET_PRIVATE (self); g_return_val_if_fail (FU_IS_USB_DEVICE (self), NULL); if (priv->usb_device == NULL) return NULL; return g_usb_device_get_platform_id (priv->usb_device); +#else + return NULL; +#endif } /** @@ -482,9 +505,11 @@ return; } +#ifdef HAVE_GUSB /* set device ID automatically */ fu_device_set_physical_id (FU_DEVICE (device), g_usb_device_get_platform_id (usb_device)); +#endif } /** @@ -501,11 +526,14 @@ GUdevDevice * fu_usb_device_find_udev_device (FuUsbDevice *device, GError **error) { -#ifdef HAVE_GUDEV +#if defined(HAVE_GUDEV) && defined(HAVE_GUSB) FuUsbDevicePrivate *priv = GET_PRIVATE (device); g_autoptr(GList) devices = NULL; g_autoptr(GUdevClient) gudev_client = g_udev_client_new (NULL); + g_return_val_if_fail (FU_IS_USB_DEVICE (device), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + /* find all tty devices */ devices = g_udev_client_query_by_subsystem (gudev_client, "usb"); for (GList *l = devices; l != NULL; l = l->next) { @@ -570,6 +598,40 @@ fu_usb_device_get_dev (FU_USB_DEVICE (donor))); } +static gboolean +fu_udev_device_bind_driver (FuDevice *device, + const gchar *subsystem, + const gchar *driver, + GError **error) +{ + FuUsbDevice *self = FU_USB_DEVICE (device); + g_autoptr(GUdevDevice) dev = NULL; + g_autoptr(FuUdevDevice) udev_device = NULL; + + /* use udev for this */ + dev = fu_usb_device_find_udev_device (self, error); + if (dev == NULL) + return FALSE; + udev_device = fu_udev_device_new (dev); + return fu_device_bind_driver (FU_DEVICE (udev_device), + subsystem, driver, error); +} + +static gboolean +fu_udev_device_unbind_driver (FuDevice *device, GError **error) +{ + FuUsbDevice *self = FU_USB_DEVICE (device); + g_autoptr(GUdevDevice) dev = NULL; + g_autoptr(FuUdevDevice) udev_device = NULL; + + /* use udev for this */ + dev = fu_usb_device_find_udev_device (self, error); + if (dev == NULL) + return FALSE; + udev_device = fu_udev_device_new (dev); + return fu_device_unbind_driver (FU_DEVICE (udev_device), error); +} + /** * fu_usb_device_new: * @usb_device: A #GUsbDevice @@ -602,9 +664,15 @@ device_class->close = fu_usb_device_close; device_class->probe = fu_usb_device_probe; device_class->incorporate = fu_usb_device_incorporate; + device_class->bind_driver = fu_udev_device_bind_driver; + device_class->unbind_driver = fu_udev_device_unbind_driver; pspec = g_param_spec_object ("usb-device", NULL, NULL, +#ifdef HAVE_GUSB G_USB_TYPE_DEVICE, +#else + G_TYPE_OBJECT, +#endif G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_NAME); diff -Nru fwupd-1.4.5/libfwupdplugin/fu-usb-device.h fwupd-1.5.8/libfwupdplugin/fu-usb-device.h --- fwupd-1.4.5/libfwupdplugin/fu-usb-device.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-usb-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -7,7 +7,13 @@ #pragma once #include +#ifdef HAVE_GUSB #include +#else +typedef GObject GUsbContext; +typedef GObject GUsbDevice; +#define G_USB_CHECK_VERSION(a,c,b) 0 +#endif #include "fu-plugin.h" #include "fu-udev-device.h" @@ -36,4 +42,5 @@ GUsbDevice *usb_device); gboolean fu_usb_device_is_open (FuUsbDevice *device); GUdevDevice *fu_usb_device_find_udev_device (FuUsbDevice *device, - GError **error); + GError **error) + G_GNUC_WARN_UNUSED_RESULT; diff -Nru fwupd-1.4.5/libfwupdplugin/fu-volume.c fwupd-1.5.8/libfwupdplugin/fu-volume.c --- fwupd-1.4.5/libfwupdplugin/fu-volume.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-volume.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,432 @@ +/* + * Copyright (C) 2018 Richard Hughes + * Copyright (C) 2019 Mario Limonciello + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuVolume" + +#include "config.h" + +#include + +#include "fwupd-error.h" + +#include "fu-volume-private.h" + +/** + * SECTION:fu-volume + * @title: FuVolume + * @short_description: Volume abstraction that uses UDisks + */ + +struct _FuVolume { + GObject parent_instance; + GDBusProxy *proxy_blk; + GDBusProxy *proxy_fs; + gchar *mount_path; /* only when mounted ourselves */ +}; + +enum { + PROP_0, + PROP_MOUNT_PATH, + PROP_PROXY_BLOCK, + PROP_PROXY_FILESYSTEM, + PROP_LAST +}; + +G_DEFINE_TYPE (FuVolume, fu_volume, G_TYPE_OBJECT) + +static void +fu_volume_finalize (GObject *obj) +{ + FuVolume *self = FU_VOLUME (obj); + g_free (self->mount_path); + if (self->proxy_blk != NULL) + g_object_unref (self->proxy_blk); + if (self->proxy_fs != NULL) + g_object_unref (self->proxy_fs); + G_OBJECT_CLASS (fu_volume_parent_class)->finalize (obj); +} + +static void +fu_volume_get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + FuVolume *self = FU_VOLUME (object); + switch (prop_id) { + case PROP_MOUNT_PATH: + g_value_set_string (value, self->mount_path); + break; + case PROP_PROXY_BLOCK: + g_value_set_object (value, self->proxy_blk); + break; + case PROP_PROXY_FILESYSTEM: + g_value_set_object (value, self->proxy_fs); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +fu_volume_set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + FuVolume *self = FU_VOLUME (object); + switch (prop_id) { + case PROP_MOUNT_PATH: + self->mount_path = g_value_dup_string (value); + break; + case PROP_PROXY_BLOCK: + self->proxy_blk = g_value_dup_object (value); + break; + case PROP_PROXY_FILESYSTEM: + self->proxy_fs = g_value_dup_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +fu_volume_class_init (FuVolumeClass *klass) +{ + GParamSpec *pspec; + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = fu_volume_finalize; + object_class->get_property = fu_volume_get_property; + object_class->set_property = fu_volume_set_property; + + pspec = g_param_spec_object ("proxy-block", NULL, NULL, G_TYPE_DBUS_PROXY, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_PROXY_BLOCK, pspec); + + pspec = g_param_spec_object ("proxy-filesystem", NULL, NULL, G_TYPE_DBUS_PROXY, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_PROXY_FILESYSTEM, pspec); + + pspec = g_param_spec_string ("mount-path", NULL, NULL, NULL, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_MOUNT_PATH, pspec); +} + +static void +fu_volume_init (FuVolume *self) +{ +} + +/** + * fu_volume_get_id: + * @self: a @FuVolume + * + * Gets the D-Bus path of the mount point. + * + * Returns: string ID, or %NULL + * + * Since: 1.4.6 + **/ +const gchar * +fu_volume_get_id (FuVolume *self) +{ + g_return_val_if_fail (FU_IS_VOLUME (self), NULL); + if (self->proxy_fs != NULL) + return g_dbus_proxy_get_object_path (self->proxy_fs); + if (self->proxy_blk != NULL) + return g_dbus_proxy_get_object_path (self->proxy_blk); + return NULL; +} + +/** + * fu_volume_get_mount_point: + * @self: a @FuVolume + * + * Gets the location of the volume mount point. + * + * Returns: UNIX path, or %NULL + * + * Since: 1.4.6 + **/ +gchar * +fu_volume_get_mount_point (FuVolume *self) +{ + g_autofree const gchar **mountpoints = NULL; + g_autoptr(GVariant) val = NULL; + + g_return_val_if_fail (FU_IS_VOLUME (self), NULL); + + /* we mounted it */ + if (self->mount_path != NULL) + return g_strdup (self->mount_path); + + /* something else mounted it */ + if (self->proxy_fs == NULL) + return NULL; + val = g_dbus_proxy_get_cached_property (self->proxy_fs, "MountPoints"); + if (val == NULL) + return NULL; + mountpoints = g_variant_get_bytestring_array (val, NULL); + return g_strdup (mountpoints[0]); +} + +/** + * fu_volume_check_free_space: + * @self: a @FuVolume + * @required: size in bytes + * @error: A #GError, or %NULL + * + * Checks the volume for required space. + * + * Returns: %TRUE for success + * + * Since: 1.4.6 + **/ +gboolean +fu_volume_check_free_space (FuVolume *self, guint64 required, GError **error) +{ + guint64 fs_free; + g_autofree gchar *path = NULL; + g_autoptr(GFile) file = NULL; + g_autoptr(GFileInfo) info = NULL; + + g_return_val_if_fail (FU_IS_VOLUME (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* skip the checks for unmounted disks */ + path = fu_volume_get_mount_point (self); + if (path == NULL) + return TRUE; + + file = g_file_new_for_path (path); + info = g_file_query_filesystem_info (file, + G_FILE_ATTRIBUTE_FILESYSTEM_FREE, + NULL, error); + if (info == NULL) + return FALSE; + fs_free = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE); + if (fs_free < required) { + g_autofree gchar *str_free = g_format_size (fs_free); + g_autofree gchar *str_reqd = g_format_size (required); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "%s does not have sufficient space, required %s, got %s", + path, str_reqd, str_free); + return FALSE; + } + return TRUE; +} + +/** + * fu_volume_is_mounted: + * @self: a @FuVolume + * + * Checks if the VOLUME is already mounted. + * + * Returns: %TRUE for success + * + * Since: 1.4.6 + **/ +gboolean +fu_volume_is_mounted (FuVolume *self) +{ + g_autofree gchar *mount_point = NULL; + g_return_val_if_fail (FU_IS_VOLUME (self), FALSE); + mount_point = fu_volume_get_mount_point (self); + return mount_point != NULL; +} + +/** + * fu_volume_is_encrypted: + * @self: a @FuVolume + * + * Checks if the VOLUME is currently encrypted. + * + * Returns: %TRUE for success + * + * Since: 1.5.1 + **/ +gboolean +fu_volume_is_encrypted (FuVolume *self) +{ + g_autoptr(GVariant) val = NULL; + + g_return_val_if_fail (FU_IS_VOLUME (self), FALSE); + + if (self->proxy_blk == NULL) + return FALSE; + val = g_dbus_proxy_get_cached_property (self->proxy_blk, "CryptoBackingDevice"); + if (val == NULL) + return FALSE; + if (g_strcmp0 (g_variant_get_string (val, NULL), "/") == 0) + return FALSE; + return TRUE; +} + +/** + * fu_volume_mount: + * @self: a @FuVolume + * @error: A #GError, or %NULL + * + * Mounts the VOLUME ready for use. + * + * Returns: %TRUE for success + * + * Since: 1.4.6 + **/ +gboolean +fu_volume_mount (FuVolume *self, GError **error) +{ + GVariantBuilder builder; + g_autoptr(GVariant) val = NULL; + + g_return_val_if_fail (FU_IS_VOLUME (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* device from the self tests */ + if (self->proxy_fs == NULL) + return TRUE; + + g_debug ("mounting %s", fu_volume_get_id (self)); + g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); + val = g_dbus_proxy_call_sync (self->proxy_fs, + "Mount", g_variant_new ("(a{sv})", &builder), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (val == NULL) + return FALSE; + g_variant_get (val, "(s)", &self->mount_path); + return TRUE; +} + +/** + * fu_volume_is_internal: + * @self: a @FuVolume + * + * Guesses if the drive is internal to the system + * + * Returns: %TRUE for success + * + * Since: 1.5.2 + **/ +gboolean +fu_volume_is_internal (FuVolume *self) +{ + g_autoptr(GVariant) val_system = NULL; + g_return_val_if_fail (FU_IS_VOLUME (self), FALSE); + + val_system = g_dbus_proxy_get_cached_property (self->proxy_blk, "HintSystem"); + if (val_system == NULL) + return FALSE; + + return g_variant_get_boolean (val_system); +} + +/** + * fu_volume_get_id_type: + * @self: a @FuVolume + * + * Return the IdType of the volume + * + * Returns: string for type or NULL + * + * Since: 1.5.2 + **/ +gchar * +fu_volume_get_id_type (FuVolume *self) +{ + g_autoptr(GVariant) val = NULL; + g_return_val_if_fail (FU_IS_VOLUME (self), NULL); + + val = g_dbus_proxy_get_cached_property (self->proxy_blk, "IdType"); + if (val == NULL) + return NULL; + + return g_strdup (g_variant_get_string (val, NULL)); +} + + +/** + * fu_volume_unmount: + * @self: a @FuVolume + * @error: A #GError, or %NULL + * + * Unmounts the volume after use. + * + * Returns: %TRUE for success + * + * Since: 1.4.6 + **/ +gboolean +fu_volume_unmount (FuVolume *self, GError **error) +{ + GVariantBuilder builder; + g_autoptr(GVariant) val = NULL; + + g_return_val_if_fail (FU_IS_VOLUME (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* device from the self tests */ + if (self->proxy_fs == NULL) + return TRUE; + + g_debug ("unmounting %s", fu_volume_get_id (self)); + g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); + val = g_dbus_proxy_call_sync (self->proxy_fs, + "Unmount", + g_variant_new ("(a{sv})", &builder), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (val == NULL) + return FALSE; + g_free (self->mount_path); + self->mount_path = NULL; + return TRUE; +} + +/** + * fu_volume_locker: + * @self: a @FuVolume + * @error: A #GError, or %NULL + * + * Locks the volume, mounting it and unmounting it as required. If the volume is + * already mounted then it is is _not_ unmounted when the locker is closed. + * + * Returns: (transfer full): a #FuDeviceLocker for success, or %NULL + * + * Since: 1.4.6 + **/ +FuDeviceLocker * +fu_volume_locker (FuVolume *self, GError **error) +{ + g_return_val_if_fail (FU_IS_VOLUME (self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* already open, so NOP */ + if (fu_volume_is_mounted (self)) + return g_object_new (FU_TYPE_DEVICE_LOCKER, NULL); + return fu_device_locker_new_full (self, + (FuDeviceLockerFunc) fu_volume_mount, + (FuDeviceLockerFunc) fu_volume_unmount, + error); +} + +/* private */ +FuVolume * +fu_volume_new_from_mount_path (const gchar *mount_path) +{ + g_autoptr(FuVolume) self = g_object_new (FU_TYPE_VOLUME, NULL); + g_return_val_if_fail (mount_path != NULL, NULL); + self->mount_path = g_strdup (mount_path); + return g_steal_pointer (&self); +} diff -Nru fwupd-1.4.5/libfwupdplugin/fu-volume.h fwupd-1.5.8/libfwupdplugin/fu-volume.h --- fwupd-1.4.5/libfwupdplugin/fu-volume.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-volume.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2018 Richard Hughes + * Copyright (C) 2019 Mario Limonciello + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#include "fu-device-locker.h" + +#define FU_TYPE_VOLUME (fu_volume_get_type ()) + +G_DECLARE_FINAL_TYPE (FuVolume, fu_volume, FU, VOLUME, GObject) + +#define FU_VOLUME_KIND_ESP "c12a7328-f81f-11d2-ba4b-00a0c93ec93b" +#define FU_VOLUME_KIND_BDP "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" + +const gchar *fu_volume_get_id (FuVolume *self); +gboolean fu_volume_check_free_space (FuVolume *self, + guint64 required, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fu_volume_is_mounted (FuVolume *self); +gboolean fu_volume_is_encrypted (FuVolume *self); +gchar *fu_volume_get_mount_point (FuVolume *self); +gboolean fu_volume_mount (FuVolume *self, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fu_volume_unmount (FuVolume *self, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +FuDeviceLocker *fu_volume_locker (FuVolume *self, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fu_volume_is_internal (FuVolume *self); +gchar *fu_volume_get_id_type (FuVolume *self); diff -Nru fwupd-1.4.5/libfwupdplugin/fu-volume-private.h fwupd-1.5.8/libfwupdplugin/fu-volume-private.h --- fwupd-1.4.5/libfwupdplugin/fu-volume-private.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fu-volume-private.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2018 Richard Hughes + * Copyright (C) 2019 Mario Limonciello + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#include "fu-volume.h" + +FuVolume *fu_volume_new_from_mount_path (const gchar *mount_path); diff -Nru fwupd-1.4.5/libfwupdplugin/fwupdplugin.h fwupd-1.5.8/libfwupdplugin/fwupdplugin.h --- fwupd-1.4.5/libfwupdplugin/fwupdplugin.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fwupdplugin.h 2021-03-31 20:08:32.000000000 +0000 @@ -14,6 +14,7 @@ #define __FWUPDPLUGIN_H_INSIDE__ #include +#include #include #include #include @@ -23,20 +24,26 @@ #include #include #include +#include #include #include #include +#include #include #include #include #include #include #include +#include #include #include +#include +#include #include #include #include +#include #ifndef FWUPD_DISABLE_DEPRECATED #include diff -Nru fwupd-1.4.5/libfwupdplugin/fwupdplugin.map fwupd-1.5.8/libfwupdplugin/fwupdplugin.map --- fwupd-1.4.5/libfwupdplugin/fwupdplugin.map 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/fwupdplugin.map 2021-03-31 20:08:32.000000000 +0000 @@ -277,6 +277,7 @@ fu_chunk_array_new; fu_chunk_array_new_from_bytes; fu_chunk_new; + fu_chunk_to_string; fu_common_find_program_in_path; fu_common_strstrip; fu_common_strtoull; @@ -591,3 +592,203 @@ fu_udev_device_write_sysfs; local: *; } LIBFWUPDPLUGIN_1.4.1; + +LIBFWUPDPLUGIN_1.4.6 { + global: + fu_common_get_esp_default; + fu_common_get_esp_for_path; + fu_common_get_volumes_by_kind; + fu_common_is_live_media; + fu_volume_check_free_space; + fu_volume_get_id; + fu_volume_get_mount_point; + fu_volume_get_type; + fu_volume_is_mounted; + fu_volume_locker; + fu_volume_mount; + fu_volume_unmount; + local: *; +} LIBFWUPDPLUGIN_1.4.5; + +LIBFWUPDPLUGIN_1.4.7 { + global: + fu_efivar_get_names; + local: *; +} LIBFWUPDPLUGIN_1.4.6; + +LIBFWUPDPLUGIN_1.5.0 { + global: + fu_byte_array_set_size; + fu_common_cpuid; + fu_common_crc16; + fu_common_crc32; + fu_common_crc32_full; + fu_common_crc8; + fu_common_filename_glob; + fu_common_is_cpu_intel; + fu_device_bind_driver; + fu_device_dump_firmware; + fu_device_report_metadata_post; + fu_device_report_metadata_pre; + fu_device_sleep_with_progress; + fu_device_unbind_driver; + fu_efivar_get_data_bytes; + fu_efivar_secure_boot_enabled_full; + fu_efivar_set_data_bytes; + fu_firmware_add_flag; + fu_firmware_build; + fu_firmware_flag_from_string; + fu_firmware_flag_to_string; + fu_firmware_has_flag; + fu_firmware_image_build; + fu_firmware_image_get_bytes; + fu_firmware_image_get_filename; + fu_firmware_image_get_offset; + fu_firmware_image_parse; + fu_firmware_image_set_filename; + fu_firmware_image_set_offset; + fu_firmware_remove_image; + fu_firmware_remove_image_by_id; + fu_firmware_remove_image_by_idx; + fu_fmap_firmware_get_type; + fu_fmap_firmware_new; + fu_plugin_runner_add_security_attrs; + fu_plugin_runner_device_added; + fu_plugin_security_changed; + fu_security_attrs_append; + fu_security_attrs_calculate_hsi; + fu_security_attrs_depsolve; + fu_security_attrs_get_all; + fu_security_attrs_get_type; + fu_security_attrs_new; + fu_security_attrs_remove_all; + fu_security_attrs_to_variant; + fu_smbios_get_integer; + fu_udev_device_get_number; + fu_udev_device_get_subsystem_model; + fu_udev_device_get_subsystem_vendor; + local: *; +} LIBFWUPDPLUGIN_1.4.7; + +LIBFWUPDPLUGIN_1.5.1 { + global: + fu_common_get_volume_by_device; + fu_common_get_volume_by_devnum; + fu_device_add_possible_plugin; + fu_efivar_space_used; + fu_volume_is_encrypted; + local: *; +} LIBFWUPDPLUGIN_1.5.0; + +LIBFWUPDPLUGIN_1.5.2 { + global: + fu_hid_device_add_flag; + fu_volume_get_id_type; + fu_volume_is_internal; + local: *; +} LIBFWUPDPLUGIN_1.5.1; + +LIBFWUPDPLUGIN_1.5.3 { + global: + fu_udev_device_get_driver; + local: *; +} LIBFWUPDPLUGIN_1.5.2; + +LIBFWUPDPLUGIN_1.5.4 { + global: + fu_common_bytes_new_offset; + local: *; +} LIBFWUPDPLUGIN_1.5.3; + +LIBFWUPDPLUGIN_1.5.5 { + global: + fu_common_get_cpu_vendor; + fu_common_strsafe; + fu_device_add_internal_flag; + fu_device_has_internal_flag; + fu_device_internal_flag_from_string; + fu_device_internal_flag_to_string; + fu_device_remove_internal_flag; + fu_device_retry_full; + fu_efi_signature_get_kind; + fu_efi_signature_get_owner; + fu_efi_signature_get_type; + fu_efi_signature_kind_to_string; + fu_efi_signature_list_get_type; + fu_efi_signature_list_new; + fu_efivar_get_monitor; + fu_firmware_get_image_by_checksum; + fu_firmware_image_get_checksum; + local: *; +} LIBFWUPDPLUGIN_1.5.4; + +LIBFWUPDPLUGIN_1.5.6 { + global: + fu_chunk_array_mutable_new; + fu_chunk_bytes_new; + fu_chunk_get_address; + fu_chunk_get_bytes; + fu_chunk_get_data; + fu_chunk_get_data_out; + fu_chunk_get_data_sz; + fu_chunk_get_idx; + fu_chunk_get_page; + fu_chunk_get_type; + fu_chunk_set_address; + fu_chunk_set_bytes; + fu_chunk_set_idx; + fu_chunk_set_page; + fu_common_get_memory_size; + fu_common_strjoin_array; + fu_common_uri_get_scheme; + fu_dfuse_firmware_get_type; + fu_dfuse_firmware_new; + fu_firmware_image_add_chunk; + fu_firmware_image_get_chunks; + fu_firmware_new_from_gtypes; + fu_firmware_strparse_uint16_safe; + fu_firmware_strparse_uint24_safe; + fu_firmware_strparse_uint32_safe; + fu_firmware_strparse_uint4_safe; + fu_firmware_strparse_uint8_safe; + fu_hwids_add_smbios_override; + fu_hwids_get_keys; + fu_memdup_safe; + fu_plugin_get_devices; + fu_plugin_runner_backend_device_added; + fu_plugin_runner_backend_device_changed; + local: *; +} LIBFWUPDPLUGIN_1.5.5; + +LIBFWUPDPLUGIN_1.5.7 { + global: + fu_bluez_device_get_type; + fu_bluez_device_read; + fu_bluez_device_read_string; + fu_bluez_device_write; + fu_firmware_get_version_raw; + fu_firmware_set_version_raw; + local: *; +} LIBFWUPDPLUGIN_1.5.6; + +LIBFWUPDPLUGIN_1.5.8 { + global: + fu_bluez_device_notify_start; + fu_bluez_device_notify_stop; + fu_byte_array_append_uint64; + fu_common_read_uint64; + fu_common_read_uint64_safe; + fu_common_write_uint16_safe; + fu_common_write_uint32_safe; + fu_common_write_uint64; + fu_common_write_uint64_safe; + fu_common_write_uint8_safe; + fu_device_get_backend_id; + fu_device_get_battery_level; + fu_device_set_backend_id; + fu_device_set_battery_level; + fu_plugin_add_possible_quirk_key; + fu_quirks_add_possible_key; + fu_udev_device_set_logical_id; + local: *; +} LIBFWUPDPLUGIN_1.5.7; diff -Nru fwupd-1.4.5/libfwupdplugin/meson.build fwupd-1.5.8/libfwupdplugin/meson.build --- fwupd-1.4.5/libfwupdplugin/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,24 +1,31 @@ fwupdplugin_src = [ 'fu-archive.c', + 'fu-bluez-device.c', 'fu-cabinet.c', - 'fu-chunk.c', - 'fu-common.c', + 'fu-chunk.c', # fuzzing + 'fu-common.c', # fuzzing 'fu-common-cab.c', 'fu-common-guid.c', - 'fu-common-version.c', - 'fu-device-locker.c', - 'fu-device.c', - 'fu-dfu-firmware.c', - 'fu-firmware.c', - 'fu-firmware-common.c', - 'fu-firmware-image.c', + 'fu-common-version.c', # fuzzing + 'fu-device-locker.c', # fuzzing + 'fu-device.c', # fuzzing + 'fu-dfu-firmware.c', # fuzzing + 'fu-volume.c', # fuzzing + 'fu-firmware.c', # fuzzing + 'fu-firmware-common.c', # fuzzing + 'fu-firmware-image.c', # fuzzing + 'fu-dfuse-firmware.c', # fuzzing + 'fu-fmap-firmware.c', # fuzzing 'fu-hwids.c', - 'fu-ihex-firmware.c', - 'fu-io-channel.c', + 'fu-ihex-firmware.c', # fuzzing + 'fu-io-channel.c', # fuzzing 'fu-plugin.c', - 'fu-quirks.c', + 'fu-quirks.c', # fuzzing + 'fu-security-attrs.c', 'fu-smbios.c', - 'fu-srec-firmware.c', + 'fu-srec-firmware.c', # fuzzing + 'fu-efi-signature.c', + 'fu-efi-signature-list.c', 'fu-efivar.c', 'fu-udev-device.c', 'fu-usb-device.c', @@ -27,26 +34,34 @@ fwupdplugin_headers = [ 'fu-archive.h', + 'fu-bluez-device.h', 'fu-cabinet.h', 'fu-chunk.h', 'fu-common.h', 'fu-common-cab.h', 'fu-common-guid.h', 'fu-common-version.h', + 'fu-deprecated.h', 'fu-device.h', 'fu-device-metadata.h', 'fu-device-locker.h', 'fu-dfu-firmware.h', + 'fu-volume.h', 'fu-firmware.h', 'fu-firmware-common.h', 'fu-firmware-image.h', + 'fu-fmap-firmware.h', + 'fu-dfuse-firmware.h', 'fu-hwids.h', 'fu-ihex-firmware.h', 'fu-io-channel.h', 'fu-plugin.h', 'fu-quirks.h', + 'fu-security-attrs.h', 'fu-smbios.h', 'fu-srec-firmware.h', + 'fu-efi-signature.h', + 'fu-efi-signature-list.h', 'fu-efivar.h', 'fu-udev-device.h', 'fu-usb-device.h', @@ -73,6 +88,7 @@ fu_hash, 'fu-device-private.h', 'fu-plugin-private.h', + 'fu-security-attrs-private.h', 'fu-smbios-private.h', 'fu-usb-device-private.h', ] @@ -81,9 +97,12 @@ libxmlb, libjcat, giounix, - gusb, ] +if get_option('gusb') + introspection_deps += gusb +endif + if get_option('gudev') fwupdplugin_headers_private += 'fu-udev-device-private.h' introspection_deps += gudev @@ -92,7 +111,6 @@ library_deps = [ introspection_deps, gmodule, - libarchive, libjsonglib, libgcab, valgrind, @@ -100,9 +118,13 @@ platform_deps, ] +if get_option('libarchive') + library_deps += libarchive +endif + fwupdplugin_mapfile = 'fwupdplugin.map' vflag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), fwupdplugin_mapfile) -fwupdplugin = shared_library( +fwupdplugin = library( 'fwupdplugin', sources : [ fwupdplugin_src, @@ -136,7 +158,6 @@ 'json-glib-1.0', 'libarchive', 'libgcab-1.0', - 'libsoup-2.4', 'xmlb', 'jcat', ], @@ -147,8 +168,13 @@ description : 'library for plugins to use to interact with fwupd daemon', ) -if get_option('introspection') +if get_option('introspection') and get_option('gusb') gir_dep = declare_dependency(sources: fwupd_gir) + if gusb.type_name() == 'internal' + libgusb_girtarget = subproject('gusb').get_variable('libgusb_girtarget')[0] + else + libgusb_girtarget = 'GUsb-1.0' + endif fwupdplugin_gir = gnome.generate_gir(fwupd, sources : [ fwupdplugin_src, @@ -173,7 +199,7 @@ includes : [ 'Gio-2.0', 'GObject-2.0', - 'GUsb-1.0', + libgusb_girtarget, fwupd_gir[0], ], install : true @@ -200,6 +226,7 @@ 'LIBFWUPDPLUGIN', '@INPUT@', '@OUTPUT@', + '--override', 'fu_chunk_get_type', '1.5.6', ], ) diff -Nru fwupd-1.4.5/libfwupdplugin/README.md fwupd-1.5.8/libfwupdplugin/README.md --- fwupd-1.4.5/libfwupdplugin/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/libfwupdplugin/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,12 @@ +Planned API/ABI changes for next release +======================================== + + * Remove fu_common_is_cpu_intel() + * Remove fu_firmware_strparse_uintXX() + * Remove fu_plugin_get_usb_context() and fu_plugin_set_usb_context() + * Remove fu_plugin_runner_usb_device_added(), fu_plugin_runner_udev_device_added() + and fu_plugin_runner_udev_device_changed() + * Remove FuHidDevice->open() and FuHidDevice->close() + * Remove FuUsbDevice->probe(), FuUsbDevice->open() and FuUsbDevice->close() + * Remove FuUdevDevice->to_string(), FuUdevDevice->probe(), FuUdevDevice->open() and FuUdevDevice->close() + * Remove fu_device_get_protocol() and fu_device_set_protocol() diff -Nru fwupd-1.4.5/meson.build fwupd-1.5.8/meson.build --- fwupd-1.4.5/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ project('fwupd', 'c', - version : '1.4.5', + version : '1.5.8', license : 'LGPL-2.1+', meson_version : '>=0.47.0', default_options : ['warning_level=2', 'c_std=c99'], @@ -73,7 +73,6 @@ '-Wformat-signedness', '-Wignored-qualifiers', '-Wimplicit-function-declaration', - '-Wincompatible-pointer-types-discards-qualifiers', '-Winit-self', '-Wlogical-op', '-Wmaybe-uninitialized', @@ -87,12 +86,10 @@ '-Wno-cast-function-type', '-Wno-address-of-packed-member', # incompatible with g_autoptr() '-Wno-unknown-pragmas', - '-Wno-deprecated-declarations', '-Wno-missing-field-initializers', '-Wno-strict-aliasing', '-Wno-suggest-attribute=format', '-Wno-unused-parameter', - '-Wnull-dereference', '-Wold-style-definition', '-Woverride-init', '-Wpointer-arith', @@ -114,6 +111,12 @@ cc = meson.get_compiler('c') add_project_arguments(cc.get_supported_arguments(warning_flags), language : 'c') +# use honggfuzz for parallel persistent fuzzing +honggfuzz = find_program('honggfuzz', required: false) +if cc.has_function('HF_ITER') + conf.set('HAVE_HF_ITER', '1') +endif + if not meson.is_cross_build() add_project_arguments('-fstack-protector-strong', language : 'c') endif @@ -125,17 +128,20 @@ '-Wl,-z,relro', '-Wl,-z,defs', '-Wl,-z,now', + '-Wl,-z,ibt,-z,shstk', ] foreach arg: test_link_args if cc.has_link_argument(arg) global_link_args += arg endif endforeach -add_global_link_arguments( +add_project_link_arguments( global_link_args, language: 'c' ) +add_project_arguments('-DFWUPD_COMPILATION', language : 'c') + # Needed for realpath(), syscall(), cfmakeraw(), etc. add_project_arguments('-D_DEFAULT_SOURCE', language : 'c') @@ -171,10 +177,14 @@ sysconfdir = get_option('sysconfdir') localstatedir = get_option('localstatedir') datadir = get_option('datadir') + installed_test_bindir = get_option('libexecdir') + installed_test_datadir = get_option('datadir') else datadir = join_paths(prefix, get_option('datadir')) sysconfdir = join_paths(prefix, get_option('sysconfdir')) localstatedir = join_paths(prefix, get_option('localstatedir')) + installed_test_bindir = join_paths(libexecdir, 'installed-tests', meson.project_name()) + installed_test_datadir = join_paths(datadir, 'installed-tests', meson.project_name()) endif mandir = join_paths(prefix, get_option('mandir')) localedir = join_paths(prefix, get_option('localedir')) @@ -196,21 +206,41 @@ else gudev = dependency('', required : false) endif +if get_option('bluez') + conf.set('HAVE_BLUEZ', '1') +endif libxmlb = dependency('xmlb', version : '>= 0.1.13', fallback : ['libxmlb', 'libxmlb_dep']) -gusb = dependency('gusb', version : '>= 0.2.9', fallback : ['gusb', 'gusb_dep']) +if get_option('gusb') + gusb = dependency('gusb', version : '>= 0.3.4', fallback : ['gusb', 'gusb_dep']) + conf.set('HAVE_GUSB', '1') +endif sqlite = dependency('sqlite3') -libarchive = dependency('libarchive') +if get_option('libarchive') + libarchive = dependency('libarchive') + conf.set('HAVE_LIBARCHIVE', '1') +endif endif libjcat = dependency('jcat', version : '>= 0.1.0', fallback : ['libjcat', 'libjcat_dep']) libjsonglib = dependency('json-glib-1.0', version : '>= 1.1.1') valgrind = dependency('valgrind', required: false) -soup = dependency('libsoup-2.4', version : '>= 2.51.92') -if build_daemon - polkit = dependency('polkit-gobject-1', version : '>= 0.103') - if polkit.version().version_compare('>= 0.114') - conf.set('HAVE_POLKIT_0_114', '1') +if get_option('curl') + libcurl = dependency('libcurl', version : '>= 7.56.0') + conf.set('HAVE_LIBCURL', '1') + if libcurl.version().version_compare('>= 7.62.0') + conf.set('HAVE_LIBCURL_7_62_0', '1') endif +endif +if build_daemon + if get_option('polkit') + polkit = dependency('polkit-gobject-1', version : '>= 0.103') + conf.set('HAVE_POLKIT', '1') + if polkit.version().version_compare('>= 0.114') + conf.set('HAVE_POLKIT_0_114', '1') + endif conf.set_quoted ('POLKIT_ACTIONDIR', polkit.get_pkgconfig_variable('actiondir')) + else + warning('Polkit is disabled, the daemon will allow ALL client actions') + endif udevdir = get_option('udevdir') if udevdir == '' udev = dependency('udev') @@ -219,12 +249,20 @@ endif libm = cc.find_library('m', required: false) libgcab = dependency('libgcab-1.0', version : '>= 1.0', fallback : ['gcab', 'gcab_dep']) -gcab = find_program('gcab', required : true) +gcab = find_program('gcab', required : get_option('tests')) bashcomp = dependency('bash-completion', required: false) python3 = find_program('python3') -tpm2tss = dependency('tss2-esys', version : '>= 2.0', required: false) -if tpm2tss.found() - conf.set('HAVE_TSS2', '1') + +if get_option('gnutls') + gnutls = dependency('gnutls', version : '>= 3.6.0') + conf.set('HAVE_GNUTLS', '1') +else + if get_option('plugin_uefi_pk') + error('plugin_uefi_pk needs -Dgnutls=true to work') + endif + if get_option('plugin_synaptics_rmi') + error('plugin_synaptics_rmi needs -Dgnutls=true to work') + endif endif platform_deps = [] @@ -238,35 +276,61 @@ conf.set('HAVE_VALGRIND', '1') endif -if build_standalone and get_option('plugin_redfish') - efivar = dependency('efivar') -endif - if build_standalone and get_option('plugin_altos') libelf = dependency('libelf') endif +host_cpu = host_machine.cpu_family() + if cc.has_header('sys/utsname.h') conf.set('HAVE_UTSNAME_H', '1') endif if cc.has_header('sys/ioctl.h') conf.set('HAVE_IOCTL_H', '1') endif -if cc.has_header('sys/errno.h') +if cc.has_header('errno.h') conf.set('HAVE_ERRNO_H', '1') endif +if cc.has_header('sys/socket.h') + conf.set('HAVE_SOCKET_H', '1') +endif +if cc.has_header('linux/ethtool.h') + conf.set('HAVE_ETHTOOL_H', '1') +endif +if cc.has_header('linux/hidraw.h') + conf.set('HAVE_HIDRAW_H', '1') +endif +if cc.has_header('sys/mman.h') + conf.set('HAVE_MMAN_H', '1') +endif if cc.has_header('poll.h') conf.set('HAVE_POLL_H', '1') endif if cc.has_header('fnmatch.h') conf.set('HAVE_FNMATCH_H', '1') endif +if cc.has_header('cpuid.h') and cc.has_header_symbol('cpuid.h', '__get_cpuid_count') and (host_cpu == 'x86' or host_cpu == 'x86_64') + conf.set('HAVE_CPUID_H', '1') +else + if get_option('plugin_msr') + error('cpuid.h is required for -Dplugin_msr=true') + endif +endif if cc.has_function('getuid') conf.set('HAVE_GETUID', '1') endif if cc.has_function('realpath') conf.set('HAVE_REALPATH', '1') endif +if cc.has_function('memmem') + conf.set('HAVE_MEMMEM', '1') +endif +if cc.has_function('sigaction') + conf.set('HAVE_SIGACTION', '1') +endif +if cc.has_function('memfd_create') + conf.set('HAVE_MEMFD_CREATE', '1') +endif if cc.has_header_symbol('locale.h', 'LC_MESSAGES') conf.set('HAVE_LC_MESSAGES', '1') endif @@ -274,16 +338,17 @@ conf.set('HAVE_PWRITE', '1') endif -if build_standalone and get_option('plugin_tpm') and not tpm2tss.found() - error('tss2-esys is required for -Dplugin_tpm=true') +if build_standalone and get_option('plugin_tpm') + tpm2tss = dependency('tss2-esys', version : '>= 2.0') + conf.set('HAVE_TSS2', '1') +else + tpm2tss = dependency('', required: false) endif -if build_standalone and get_option('plugin_uefi') +if build_standalone and get_option('plugin_uefi_capsule') cairo = dependency('cairo') fontconfig = cc.find_library('fontconfig') freetype = cc.find_library('freetype') - efivar = dependency('efivar', version : '>= 33') - conf.set_quoted('EFIVAR_LIBRARY_VERSION', efivar.version()) efiboot = dependency('efiboot') objcopy = find_program ('objcopy') readelf = find_program ('readelf') @@ -292,17 +357,16 @@ efi_app_location = join_paths(libexecdir, 'fwupd', 'efi') conf.set_quoted ('EFI_APP_LOCATION', efi_app_location) - efi_arch = host_machine.cpu_family() - if efi_arch == 'x86' + if host_cpu == 'x86' EFI_MACHINE_TYPE_NAME = 'ia32' gnu_efi_arch = 'ia32' - elif efi_arch == 'x86_64' + elif host_cpu == 'x86_64' EFI_MACHINE_TYPE_NAME = 'x64' gnu_efi_arch = 'x86_64' - elif efi_arch == 'arm' + elif host_cpu == 'arm' EFI_MACHINE_TYPE_NAME = 'arm' gnu_efi_arch = 'arm' - elif efi_arch == 'aarch64' + elif host_cpu == 'aarch64' EFI_MACHINE_TYPE_NAME = 'aa64' gnu_efi_arch = 'aarch64' else @@ -312,16 +376,15 @@ conf.set_quoted('EFI_MACHINE_TYPE_NAME', EFI_MACHINE_TYPE_NAME) r = run_command([python3, 'po/test-deps']) if r.returncode() != 0 - error(r.stderr()) + error(r.stdout()) endif endif if build_standalone and get_option('plugin_dell') libsmbios_c = dependency('libsmbios_c', version : '>= 2.4.0') - efivar = dependency('efivar') conf.set('HAVE_DELL', '1') - if not get_option('plugin_uefi') - error('plugin_dell also needs plugin_uefi to work') + if not get_option('plugin_uefi_capsule') + error('plugin_dell also needs plugin_uefi_capsule to work') endif endif @@ -332,16 +395,16 @@ add_project_arguments('-DQMI_REQUIRED_VERSION="1.23.1"', language : 'c') endif +if get_option('soup_session_compat') + conf.set('SOUP_SESSION_COMPAT', '1') +endif + if build_standalone and get_option('plugin_nvme') if not cc.has_header('linux/nvme_ioctl.h') error('NVMe support requires kernel >= 4.4') endif endif -if build_standalone and get_option('plugin_synaptics') - conf.set('HAVE_SYNAPTICS', '1') -endif - if build_standalone and get_option('plugin_thunderbolt') umockdev = dependency('umockdev-1.0', required: false) conf.set('HAVE_THUNDERBOLT', '1') @@ -353,6 +416,7 @@ if build_standalone and get_option('systemd') systemd = dependency('systemd', version : '>= 211') + libsystemd = dependency('libsystemd') conf.set('HAVE_SYSTEMD' , '1') conf.set('HAVE_LOGIND' , '1') systemd_root_prefix = get_option('systemd_root_prefix') @@ -360,11 +424,19 @@ systemdunitdir = systemd.get_pkgconfig_variable('systemdsystemunitdir') systemdsystempresetdir = systemd.get_pkgconfig_variable('systemdsystempresetdir') systemd_shutdown_dir = systemd.get_pkgconfig_variable('systemdshutdowndir') + systemd_modules_load_dir = systemd.get_pkgconfig_variable('modulesloaddir') else systemdunitdir = systemd.get_pkgconfig_variable('systemdsystemunitdir', define_variable: ['rootprefix', systemd_root_prefix]) systemdsystempresetdir = systemd.get_pkgconfig_variable('systemdsystempresetdir', define_variable: ['rootprefix', systemd_root_prefix]) - systemd_shutdown_dir = systemd.get_pkgconfig_variable('systemdshutdowndir', define_variable: ['rootprefix', systemd_root_prefix]) + systemd_root_prefix_varname = 'root_prefix' + if systemd.version().version_compare('< 246') + systemd_root_prefix_varname = 'rootprefix' + endif + systemd_shutdown_dir = systemd.get_pkgconfig_variable('systemdshutdowndir', define_variable: [systemd_root_prefix_varname, systemd_root_prefix]) + systemd_modules_load_dir = systemd.get_pkgconfig_variable('modulesloaddir', define_variable: [systemd_root_prefix_varname, systemd_root_prefix]) endif +else + libsystemd = dependency('', required: false) endif if build_standalone and get_option('elogind') @@ -376,10 +448,15 @@ conf.set('HAVE_CONSOLEKIT' , '1') endif +if get_option('supported_build') + conf.set('SUPPORTED_BUILD', '1') +endif + gnome = import('gnome') i18n = import('i18n') conf.set_quoted('FWUPD_BINDIR', bindir) +conf.set_quoted('FWUPD_LIBDIR', libdir) conf.set_quoted('FWUPD_LIBEXECDIR', libexecdir) conf.set_quoted('FWUPD_DATADIR', datadir) conf.set_quoted('FWUPD_LOCALSTATEDIR', localstatedir) @@ -395,6 +472,11 @@ conf.set_quoted('FWUPD_PLUGINDIR', plugin_dir) endif +# sanity check, otherwise there is not point building +if host_machine.system() == 'windows' and not get_option('gusb') + error('-Dgusb=true is required for Windows build') +endif + conf.set_quoted('GETTEXT_PACKAGE', meson.project_name()) conf.set_quoted('PACKAGE_NAME', meson.project_name()) conf.set_quoted('VERSION', meson.project_version()) @@ -415,10 +497,16 @@ plugin_deps += gio plugin_deps += giounix plugin_deps += gmodule + plugin_deps += gudev + plugin_deps += libjsonglib +endif + +if get_option('gusb') plugin_deps += gusb - plugin_deps += soup +endif + +if get_option('libarchive') plugin_deps += libarchive - plugin_deps += gudev endif root_incdir = include_directories('.') @@ -428,7 +516,7 @@ subdir('docs') endif subdir('libfwupd') -if build_daemon +if build_daemon and get_option('polkit') subdir('policy') endif if build_standalone @@ -453,3 +541,17 @@ join_paths(meson.source_root(), 'contrib', 'setup-win32.nsi'), ]) endif + +codespell = find_program('codespell', required : false) +if codespell.found() +run_target('codespell', + command: [ + codespell, + meson.source_root(), + '--write-changes', + '--builtin', 'en-GB_to_en-US', + '--skip', '*.po,*.csv,*.svg,*.p7c,subprojects,.git,pcrs,build*', + '--ignore-words-list', 'conexant,Conexant,gir,GIR,hsi,HSI,cancelled,Cancelled', + ] +) +endif diff -Nru fwupd-1.4.5/meson_options.txt fwupd-1.5.8/meson_options.txt --- fwupd-1.4.5/meson_options.txt 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/meson_options.txt 2021-03-31 20:08:32.000000000 +0000 @@ -6,29 +6,48 @@ option('introspection', type : 'boolean', value : true, description : 'generate GObject Introspection data') option('lvfs', type : 'boolean', value : true, description : 'enable LVFS remotes') option('man', type : 'boolean', value : true, description : 'enable man pages') +option('libarchive', type : 'boolean', value : true, description : 'enable libarchive support') option('gudev', type : 'boolean', value : true, description : 'enable GUdev support') +option('gusb', type : 'boolean', value : true, description : 'enable GUsb support') +option('bluez', type : 'boolean', value : false, description : 'enable BlueZ support') +option('polkit', type: 'boolean', value : true, description : 'enable PolKit support in daemon') +option('gnutls', type: 'boolean', value : true, description : 'enable GnuTLS support') option('plugin_altos', type : 'boolean', value : true, description : 'enable altos support') option('plugin_amt', type : 'boolean', value : true, description : 'enable Intel AMT support') option('plugin_dell', type : 'boolean', value : true, description : 'enable Dell-specific support') option('plugin_dummy', type : 'boolean', value : false, description : 'enable the dummy device') option('plugin_emmc', type : 'boolean', value : true, description : 'enable eMMC support') -option('plugin_synaptics', type: 'boolean', value: true, description : 'enable Synaptics MST hub support') +option('plugin_synaptics_mst', type: 'boolean', value: true, description : 'enable Synaptics MST hub support') +option('plugin_synaptics_rmi', type: 'boolean', value: true, description : 'enable Synaptics RMI support') +option('plugin_tpm', type : 'boolean', value : true, description : 'enable TPM support') option('plugin_thunderbolt', type : 'boolean', value : true, description : 'enable Thunderbolt support') option('plugin_redfish', type : 'boolean', value : true, description : 'enable Redfish support') -option('plugin_tpm', type : 'boolean', value : true, description : 'enable TPM support') -option('plugin_uefi', type : 'boolean', value : true, description : 'enable UEFI support') +option('plugin_uefi_capsule', type : 'boolean', value : true, description : 'enable UEFI capsule support') +option('plugin_uefi_pk', type : 'boolean', value : true, description : 'enable UEFI PK support') option('plugin_nvme', type : 'boolean', value : true, description : 'enable NVMe support') option('plugin_modem_manager', type : 'boolean', value : false, description : 'enable ModemManager support') +option('plugin_msr', type : 'boolean', value : true, description : 'enable MSR support') option('plugin_flashrom', type : 'boolean', value : false, description : 'enable libflashrom support') -option('plugin_coreboot', type : 'boolean', value : true, description : 'enable coreboot support') +option('plugin_platform_integrity', type : 'boolean', value : false, description : 'enable platform integrity support') +option('qubes', type : 'boolean', value : false, description : 'build packages for Qubes OS') +option('supported_build', type : 'boolean', value : false, description: 'distribution package with upstream support') option('systemd', type : 'boolean', value : true, description : 'enable systemd support') option('systemd_root_prefix', type: 'string', value: '', description: 'Directory to base systemd’s installation directories on') option('elogind', type : 'boolean', value : false, description : 'enable elogind support') option('tests', type : 'boolean', value : true, description : 'enable tests') +option('soup_session_compat', type : 'boolean', value : true, description : 'enable SoupSession runtime compatibility support') +option('curl', type : 'boolean', value : true, description : 'enable libcurl support') option('udevdir', type: 'string', value: '', description: 'Directory for udev rules') option('efi-cc', type : 'string', value : 'gcc', description : 'the compiler to use for EFI modules') option('efi-ld', type : 'string', value : 'ld', description : 'the linker to use for EFI modules') +option('efi-objcopy', type : 'string', value : 'objcopy', description : 'the objcopy utility to use for EFI modules') option('efi-libdir', type : 'string', description : 'path to the EFI lib directory') option('efi-ldsdir', type : 'string', description : 'path to the EFI lds directory') option('efi-includedir', type : 'string', value : '/usr/include/efi', description : 'path to the EFI header directory') -option('efi_os_dir', type: 'string', description : 'the name of OS directory in ESP') +option('efi_os_dir', type: 'string', description : 'the hardcoded name of OS directory in ESP, e.g. fedora') +option('efi_sbat_fwupd_generation', type : 'integer', value : 1, description : 'SBAT fwupd generation') +option('efi_sbat_distro_id', type : 'string', value : '', description : 'SBAT distribution ID, e.g. fedora') +option('efi_sbat_distro_summary', type : 'string', value : '', description : 'SBAT distribution summary, e.g. Fedora') +option('efi_sbat_distro_pkgname', type : 'string', value : '', description : 'SBAT distribution package name, e.g. fwupd') +option('efi_sbat_distro_version', type : 'string', value : '', description : 'SBAT distribution version, e.g. fwupd-1.5.6.fc33') +option('efi_sbat_distro_url', type : 'string', value : '', description : 'SBAT distribution URL, e.g. https://src.fedoraproject.org/rpms/fwupd') diff -Nru fwupd-1.4.5/.pc/0001-Tweak-the-SBAT-output-for-a-vendor-string.patch/plugins/uefi-capsule/efi/generate_sbat.py fwupd-1.5.8/.pc/0001-Tweak-the-SBAT-output-for-a-vendor-string.patch/plugins/uefi-capsule/efi/generate_sbat.py --- fwupd-1.4.5/.pc/0001-Tweak-the-SBAT-output-for-a-vendor-string.patch/plugins/uefi-capsule/efi/generate_sbat.py 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/.pc/0001-Tweak-the-SBAT-output-for-a-vendor-string.patch/plugins/uefi-capsule/efi/generate_sbat.py 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,151 @@ +#!/usr/bin/python3 +# +# Copyright (C) 2021 Javier Martinez Canillas +# Copyright (C) 2021 Richard Hughes +# +# SPDX-License-Identifier: LGPL-2.1+ +# +# pylint: disable=missing-docstring, invalid-name + +import subprocess +import sys +import argparse +import tempfile + + +def _generate_sbat(args): + """ append SBAT metadata """ + FWUPD_SUMMARY = "Firmware update daemon" + FWUPD_URL = "https://github.com/fwupd/fwupd" + + subprocess.run( + [args.cc, "-x", "c", "-c", "-o", args.outfile, "/dev/null"], check=True + ) + + # not specified + if not args.sbat_distro_id: + return + + with tempfile.NamedTemporaryFile() as sfd: + + # spec + sfd.write( + "{0},{1},{2},{0},{1},{3}\n".format( + "sbat", + args.sbat_version, + "UEFI shim", + "https://github.com/rhboot/shim/blob/main/SBAT.md", + ).encode() + ) + + # fwupd + sfd.write( + "{0},{1},{2},{0},{3},{4}\n".format( + args.project_name, + args.sbat_generation, + "Firmware update daemon", + args.project_version, + FWUPD_URL, + ).encode() + ) + + # distro specifics, falling back to the project defaults + sfd.write( + "{0}-{1},{2},{3},{4},{5},{6}\n".format( + args.project_name, + args.sbat_distro_id, + args.sbat_distro_generation or args.sbat_generation, + args.sbat_distro_summary or FWUPD_SUMMARY, + args.sbat_distro_pkgname, + args.sbat_distro_version or args.project_version, + args.sbat_distro_url or FWUPD_URL, + ).encode() + ) + + # all written + sfd.seek(0) + + # add a section to the object; use `objdump -s -j .sbat` to verify + argv = [ + args.objcopy, + "--add-section", + ".sbat={}".format(sfd.name), + "--set-section-flags", + ".sbat=contents,alloc,load,readonly,data", + args.outfile, + ] + subprocess.run(argv, check=True) + + +if __name__ == "__main__": + + parser = argparse.ArgumentParser() + parser.add_argument( + "--cc", + default="gcc", + help="Compiler to use for generating sbat object", + ) + parser.add_argument( + "--objcopy", + default="objcopy", + help="Binary file to use for objcopy", + ) + parser.add_argument( + "--project-name", + help="SBAT project name", + ) + parser.add_argument( + "--project-version", + help="SBAT project version", + ) + parser.add_argument( + "--sbat-version", + default=1, + type=int, + help="SBAT version", + ) + parser.add_argument( + "--sbat-generation", + default=1, + type=int, + help="SBAT generation", + ) + parser.add_argument( + "--sbat-distro-id", + default=None, + help="SBAT distribution ID" + ) + parser.add_argument( + "--sbat-distro-generation", + default=None, + type=int, + help="SBAT distribution generation", + ) + parser.add_argument( + "--sbat-distro-summary", + default=None, + help="SBAT distribution summary", + ) + parser.add_argument( + "--sbat-distro-pkgname", + default=None, + help="SBAT distribution package name", + ) + parser.add_argument( + "--sbat-distro-version", + default=None, + help="SBAT distribution version", + ) + parser.add_argument( + "--sbat-distro-url", + default=None, + help="SBAT distribution URL", + ) + parser.add_argument( + "outfile", + help="Output file", + ) + _args = parser.parse_args() + _generate_sbat(_args) + + sys.exit(0) diff -Nru fwupd-1.4.5/.pc/applied-patches fwupd-1.5.8/.pc/applied-patches --- fwupd-1.4.5/.pc/applied-patches 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/.pc/applied-patches 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +0001-Tweak-the-SBAT-output-for-a-vendor-string.patch diff -Nru fwupd-1.4.5/.pc/.quilt_patches fwupd-1.5.8/.pc/.quilt_patches --- fwupd-1.4.5/.pc/.quilt_patches 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/.pc/.quilt_patches 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +debian/patches diff -Nru fwupd-1.4.5/.pc/.quilt_series fwupd-1.5.8/.pc/.quilt_series --- fwupd-1.4.5/.pc/.quilt_series 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/.pc/.quilt_series 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +series diff -Nru fwupd-1.4.5/.pc/.version fwupd-1.5.8/.pc/.version --- fwupd-1.4.5/.pc/.version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/.pc/.version 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +2 diff -Nru fwupd-1.4.5/plugins/acpi-dmar/fu-acpi-dmar.c fwupd-1.5.8/plugins/acpi-dmar/fu-acpi-dmar.c --- fwupd-1.4.5/plugins/acpi-dmar/fu-acpi-dmar.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/acpi-dmar/fu-acpi-dmar.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" +#include "fu-acpi-dmar.h" + +struct _FuAcpiDmar { + GObject parent_instance; + gboolean opt_in; +}; + +G_DEFINE_TYPE (FuAcpiDmar, fu_acpi_dmar, G_TYPE_OBJECT) + +#define DMAR_DMA_CTRL_PLATFORM_OPT_IN_FLAG 0x4 + +FuAcpiDmar * +fu_acpi_dmar_new (GBytes *blob, GError **error) +{ + FuAcpiDmar *self = g_object_new (FU_TYPE_ACPI_DMAR, NULL); + gchar creator_id[5] = { '\0' }; + gchar oem_table_id[9] = { '\0' }; + gchar signature[5] = { '\0' }; + gsize bufsz = 0; + guint8 flags = 0; + const guint8 *buf = g_bytes_get_data (blob, &bufsz); + + /* parse table */ + if (!fu_memcpy_safe ((guint8 *) signature, sizeof(signature), 0x0, /* dst */ + buf, bufsz, 0x00, /* src */ + sizeof(signature) - 1, error)) + return NULL; + if (strcmp (signature, "DMAR") != 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "Not a DMAR table, got %s", + signature); + return NULL; + } + if (!fu_memcpy_safe ((guint8 *) oem_table_id, sizeof(oem_table_id), 0x0,/* dst */ + buf, bufsz, 0x10, /* src */ + sizeof(oem_table_id) - 1, error)) + return NULL; + g_debug ("OemTableId: %s", oem_table_id); + if (!fu_memcpy_safe ((guint8 *) creator_id, sizeof(creator_id), 0x0, /* dst */ + buf, bufsz, 0x1c, /* src */ + sizeof(creator_id) - 1, error)) + return NULL; + g_debug ("CreatorId: %s", creator_id); + if (!fu_memcpy_safe (&flags, sizeof(flags), 0x0, /* dst */ + buf, bufsz, 0x25, /* src */ + sizeof(flags), error)) + return NULL; + g_debug ("Flags: 0x%02x", flags); + self->opt_in = (flags & DMAR_DMA_CTRL_PLATFORM_OPT_IN_FLAG) > 0; + return self; +} + +gboolean +fu_acpi_dmar_get_opt_in (FuAcpiDmar *self) +{ + g_return_val_if_fail (FU_IS_ACPI_DMAR (self), FALSE); + return self->opt_in; +} + +static void +fu_acpi_dmar_class_init (FuAcpiDmarClass *klass) +{ +} + +static void +fu_acpi_dmar_init (FuAcpiDmar *self) +{ +} diff -Nru fwupd-1.4.5/plugins/acpi-dmar/fu-acpi-dmar.h fwupd-1.5.8/plugins/acpi-dmar/fu-acpi-dmar.h --- fwupd-1.4.5/plugins/acpi-dmar/fu-acpi-dmar.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/acpi-dmar/fu-acpi-dmar.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#define FU_TYPE_ACPI_DMAR (fu_acpi_dmar_get_type ()) +G_DECLARE_FINAL_TYPE (FuAcpiDmar, fu_acpi_dmar, FU, ACPI_DMAR, GObject) + +FuAcpiDmar *fu_acpi_dmar_new (GBytes *blob, + GError **error); +gboolean fu_acpi_dmar_get_opt_in (FuAcpiDmar *self); diff -Nru fwupd-1.4.5/plugins/acpi-dmar/fu-plugin-acpi-dmar.c fwupd-1.5.8/plugins/acpi-dmar/fu-plugin-acpi-dmar.c --- fwupd-1.4.5/plugins/acpi-dmar/fu-plugin-acpi-dmar.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/acpi-dmar/fu-plugin-acpi-dmar.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" +#include "fu-acpi-dmar.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + g_autofree gchar *fn = NULL; + g_autofree gchar *path = NULL; + g_autoptr(FuAcpiDmar) dmar = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GBytes) blob = NULL; + g_autoptr(GError) error_local = NULL; + + /* only Intel */ + if (fu_common_get_cpu_vendor () != FU_CPU_VENDOR_INTEL) + return; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_ACPI_DMAR); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL); + fu_security_attrs_append (attrs, attr); + + /* load DMAR table */ + path = fu_common_get_path (FU_PATH_KIND_ACPI_TABLES); + fn = g_build_filename (path, "DMAR", NULL); + blob = fu_common_get_contents_bytes (fn, &error_local); + if (blob == NULL) { + g_debug ("failed to load %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); + return; + } + dmar = fu_acpi_dmar_new (blob, &error_local); + if (dmar == NULL) { + g_warning ("failed to parse %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); + return; + } + if (!fu_acpi_dmar_get_opt_in (dmar)) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); + return; + } + + /* success */ + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); +} diff -Nru fwupd-1.4.5/plugins/acpi-dmar/fu-self-test.c fwupd-1.5.8/plugins/acpi-dmar/fu-self-test.c --- fwupd-1.4.5/plugins/acpi-dmar/fu-self-test.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/acpi-dmar/fu-self-test.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" + +#include "fu-acpi-dmar.h" + +static void +fu_acpi_dmar_opt_in_func (void) +{ + const gchar *ci = g_getenv ("CI_NETWORK"); + g_autoptr(FuAcpiDmar) dmar = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GBytes) blob = NULL; + g_autofree gchar *fn = NULL; + + fn = g_test_build_filename (G_TEST_DIST, "tests", "DMAR", NULL); + if (!g_file_test (fn, G_FILE_TEST_EXISTS) && ci == NULL) { + g_test_skip ("Missing DMAR"); + return; + } + blob = fu_common_get_contents_bytes (fn, &error); + g_assert_no_error (error); + g_assert_nonnull (blob); + dmar = fu_acpi_dmar_new (blob, &error); + g_assert_no_error (error); + g_assert_nonnull (dmar); + g_assert_true (fu_acpi_dmar_get_opt_in (dmar)); +} + +static void +fu_acpi_dmar_opt_out_func (void) +{ + const gchar *ci = g_getenv ("CI_NETWORK"); + g_autoptr(FuAcpiDmar) dmar = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GBytes) blob = NULL; + g_autofree gchar *fn = NULL; + + fn = g_test_build_filename (G_TEST_DIST, "tests", "DMAR-OPTOUT", NULL); + if (!g_file_test (fn, G_FILE_TEST_EXISTS) && ci == NULL) { + g_test_skip ("Missing DMAR-OPTOUT"); + return; + } + blob = fu_common_get_contents_bytes (fn, &error); + g_assert_no_error (error); + g_assert_nonnull (blob); + dmar = fu_acpi_dmar_new (blob, &error); + g_assert_no_error (error); + g_assert_nonnull (dmar); + g_assert_false (fu_acpi_dmar_get_opt_in (dmar)); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + /* only critical and error are fatal */ + g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); + g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); + + /* tests go here */ + g_test_add_func ("/acpi-dmar/opt-in", fu_acpi_dmar_opt_in_func); + g_test_add_func ("/acpi-dmar/opt-out", fu_acpi_dmar_opt_out_func); + + return g_test_run (); +} diff -Nru fwupd-1.4.5/plugins/acpi-dmar/meson.build fwupd-1.5.8/plugins/acpi-dmar/meson.build --- fwupd-1.4.5/plugins/acpi-dmar/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/acpi-dmar/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,55 @@ +if host_machine.system() == 'linux' +cargs = ['-DG_LOG_DOMAIN="FuPluginAcpiDmar"'] + +shared_module('fu_plugin_acpi_dmar', + fu_hash, + sources : [ + 'fu-plugin-acpi-dmar.c', + 'fu-acpi-dmar.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) + +if get_option('tests') + testdatadirs = environment() + testdatadirs.set('G_TEST_SRCDIR', meson.current_source_dir()) + testdatadirs.set('G_TEST_BUILDDIR', meson.current_build_dir()) + e = executable( + 'acpi-dmar-self-test', + fu_hash, + sources : [ + 'fu-self-test.c', + 'fu-acpi-dmar.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + dependencies : [ + plugin_deps, + ], + link_with : [ + fwupd, + fwupdplugin, + ], + install : true, + install_dir : installed_test_bindir, + ) + test('acpi-dmar-self-test', e, env : testdatadirs) # added to installed-tests +endif +endif diff -Nru fwupd-1.4.5/plugins/acpi-dmar/README.md fwupd-1.5.8/plugins/acpi-dmar/README.md --- fwupd-1.4.5/plugins/acpi-dmar/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/acpi-dmar/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,12 @@ +DMA Protection +============== + +Introduction +------------ + +This plugin checks if DMA remapping for Thunderbolt devices is available. The +result will be stored in an security attribute for HSI. + +External interface access +------------------------- +This plugin requires read access to `/sys/firmware/acpi/tables`. diff -Nru fwupd-1.4.5/plugins/acpi-facp/fu-acpi-facp.c fwupd-1.5.8/plugins/acpi-facp/fu-acpi-facp.c --- fwupd-1.4.5/plugins/acpi-facp/fu-acpi-facp.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/acpi-facp/fu-acpi-facp.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" +#include "fu-acpi-facp.h" + +struct _FuAcpiFacp { + GObject parent_instance; + gboolean get_s2i; +}; + +G_DEFINE_TYPE (FuAcpiFacp, fu_acpi_facp, G_TYPE_OBJECT) + +#define LOW_POWER_S0_IDLE_CAPABLE (1 << 21) + +FuAcpiFacp * +fu_acpi_facp_new (GBytes *blob, GError **error) +{ + FuAcpiFacp *self = g_object_new (FU_TYPE_ACPI_FACP, NULL); + gsize bufsz = 0; + guint32 flags = 0; + const guint8 *buf = g_bytes_get_data (blob, &bufsz); + + /* parse table */ + if (!fu_common_read_uint32_safe (buf, bufsz, 0x70, &flags, G_LITTLE_ENDIAN, error)) + return NULL; + g_debug ("Flags: 0x%04x", flags); + self->get_s2i = (flags & LOW_POWER_S0_IDLE_CAPABLE) > 0; + return self; +} + +gboolean +fu_acpi_facp_get_s2i (FuAcpiFacp *self) +{ + g_return_val_if_fail (FU_IS_ACPI_FACP (self), FALSE); + return self->get_s2i; +} + +static void +fu_acpi_facp_class_init (FuAcpiFacpClass *klass) +{ +} + +static void +fu_acpi_facp_init (FuAcpiFacp *self) +{ +} diff -Nru fwupd-1.4.5/plugins/acpi-facp/fu-acpi-facp.h fwupd-1.5.8/plugins/acpi-facp/fu-acpi-facp.h --- fwupd-1.4.5/plugins/acpi-facp/fu-acpi-facp.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/acpi-facp/fu-acpi-facp.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#define FU_TYPE_ACPI_FACP (fu_acpi_facp_get_type ()) +G_DECLARE_FINAL_TYPE (FuAcpiFacp, fu_acpi_facp, FU, ACPI_FACP, GObject) + +FuAcpiFacp *fu_acpi_facp_new (GBytes *blob, + GError **error); +gboolean fu_acpi_facp_get_s2i (FuAcpiFacp *self); diff -Nru fwupd-1.4.5/plugins/acpi-facp/fu-plugin-acpi-facp.c fwupd-1.5.8/plugins/acpi-facp/fu-plugin-acpi-facp.c --- fwupd-1.4.5/plugins/acpi-facp/fu-plugin-acpi-facp.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/acpi-facp/fu-plugin-acpi-facp.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" +#include "fu-acpi-facp.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + g_autofree gchar *fn = NULL; + g_autofree gchar *path = NULL; + g_autoptr(FuAcpiFacp) facp = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GBytes) blob = NULL; + g_autoptr(GError) error_local = NULL; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_IDLE); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL); + fu_security_attrs_append (attrs, attr); + + /* load FACP table */ + path = fu_common_get_path (FU_PATH_KIND_ACPI_TABLES); + fn = g_build_filename (path, "FACP", NULL); + blob = fu_common_get_contents_bytes (fn, &error_local); + if (blob == NULL) { + g_warning ("failed to load %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); + return; + } + facp = fu_acpi_facp_new (blob, &error_local); + if (facp == NULL) { + g_warning ("failed to parse %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); + return; + } + if (!fu_acpi_facp_get_s2i (facp)) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); + return; + } + + /* success */ + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); +} diff -Nru fwupd-1.4.5/plugins/acpi-facp/fu-self-test.c fwupd-1.5.8/plugins/acpi-facp/fu-self-test.c --- fwupd-1.4.5/plugins/acpi-facp/fu-self-test.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/acpi-facp/fu-self-test.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" + +#include "fu-acpi-facp.h" + +static void +fu_acpi_facp_s2i_disabled_func (void) +{ + const gchar *ci = g_getenv ("CI_NETWORK"); + g_autofree gchar *fn = NULL; + g_autoptr(FuAcpiFacp) facp = NULL; + g_autoptr(GBytes) blob = NULL; + g_autoptr(GError) error = NULL; + + fn = g_test_build_filename (G_TEST_DIST, "tests", "FACP", NULL); + if (!g_file_test (fn, G_FILE_TEST_EXISTS) && ci == NULL) { + g_test_skip ("Missing FACP"); + return; + } + blob = fu_common_get_contents_bytes (fn, &error); + g_assert_no_error (error); + g_assert_nonnull (blob); + facp = fu_acpi_facp_new (blob, &error); + g_assert_no_error (error); + g_assert_nonnull (facp); + g_assert_false (fu_acpi_facp_get_s2i (facp)); +} + +static void +fu_acpi_facp_s2i_enabled_func (void) +{ + const gchar *ci = g_getenv ("CI_NETWORK"); + g_autofree gchar *fn = NULL; + g_autoptr(FuAcpiFacp) facp = NULL; + g_autoptr(GBytes) blob = NULL; + g_autoptr(GError) error = NULL; + + fn = g_test_build_filename (G_TEST_DIST, "tests", "FACP-S2I", NULL); + if (!g_file_test (fn, G_FILE_TEST_EXISTS) && ci == NULL) { + g_test_skip ("Missing FACP-S2I"); + return; + } + blob = fu_common_get_contents_bytes (fn, &error); + g_assert_no_error (error); + g_assert_nonnull (blob); + facp = fu_acpi_facp_new (blob, &error); + g_assert_no_error (error); + g_assert_nonnull (facp); + g_assert_true (fu_acpi_facp_get_s2i (facp)); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + /* only critical and error are fatal */ + g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); + g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); + + /* tests go here */ + g_test_add_func ("/acpi-facp/s2i{disabled}", fu_acpi_facp_s2i_disabled_func); + g_test_add_func ("/acpi-facp/s2i{enabled}", fu_acpi_facp_s2i_enabled_func); + return g_test_run (); +} diff -Nru fwupd-1.4.5/plugins/acpi-facp/meson.build fwupd-1.5.8/plugins/acpi-facp/meson.build --- fwupd-1.4.5/plugins/acpi-facp/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/acpi-facp/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,55 @@ +if host_machine.system() == 'linux' +cargs = ['-DG_LOG_DOMAIN="FuPluginAcpiFacp"'] + +shared_module('fu_plugin_acpi_facp', + fu_hash, + sources : [ + 'fu-plugin-acpi-facp.c', + 'fu-acpi-facp.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) + +if get_option('tests') + testdatadirs = environment() + testdatadirs.set('G_TEST_SRCDIR', meson.current_source_dir()) + testdatadirs.set('G_TEST_BUILDDIR', meson.current_build_dir()) + e = executable( + 'acpi-facp-self-test', + fu_hash, + sources : [ + 'fu-self-test.c', + 'fu-acpi-facp.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + dependencies : [ + plugin_deps, + ], + link_with : [ + fwupd, + fwupdplugin, + ], + install : true, + install_dir : installed_test_bindir, + ) + test('acpi-facp-self-test', e, env : testdatadirs) # added to installed-tests +endif +endif diff -Nru fwupd-1.4.5/plugins/acpi-facp/README.md fwupd-1.5.8/plugins/acpi-facp/README.md --- fwupd-1.4.5/plugins/acpi-facp/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/acpi-facp/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,12 @@ +ACPI FACP +========= + +Introduction +------------ + +This plugin checks if S2I sleep is available. The result will be stored in an +security attribute for HSI. + +External interface access +------------------------- +This plugin requires read access to `/sys/firmware/acpi/tables`. diff -Nru fwupd-1.4.5/plugins/altos/altos.quirk fwupd-1.5.8/plugins/altos/altos.quirk --- fwupd-1.4.5/plugins/altos/altos.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/altos/altos.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,11 +1,11 @@ # ChaosKey -[DeviceInstanceId=USB\VID_1D50&PID_60C6] +[USB\VID_1D50&PID_60C6] Plugin = altos Flags = ~is-bootloader -Name = Altos ChaosKey +Name = Altus-Metrum ChaosKey CounterpartGuid = USB\VID_FFFE&PID_000A -[DeviceInstanceId=USB\VID_FFFE&PID_000A] +[USB\VID_FFFE&PID_000A] Plugin = altos Flags = is-bootloader Name = Altos [bootloader] diff -Nru fwupd-1.4.5/plugins/altos/fu-altos-device.c fwupd-1.5.8/plugins/altos/fu-altos-device.c --- fwupd-1.4.5/plugins/altos/fu-altos-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/altos/fu-altos-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2017 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -381,13 +381,12 @@ return TRUE; } -static FuFirmware * -fu_altos_device_read_firmware (FuDevice *device, GError **error) +static GBytes * +fu_altos_device_dump_firmware (FuDevice *device, GError **error) { FuAltosDevice *self = FU_ALTOS_DEVICE (device); guint flash_len; g_autoptr(FuDeviceLocker) locker = NULL; - g_autoptr(GBytes) fw = NULL; g_autoptr(GString) buf = g_string_new (NULL); /* check kind */ @@ -441,8 +440,7 @@ } /* success */ - fw = g_bytes_new (buf->str, buf->len); - return fu_firmware_new_from_bytes (fw); + return g_bytes_new (buf->str, buf->len); } static gboolean @@ -558,10 +556,11 @@ fu_altos_device_init (FuAltosDevice *self) { fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_internal_flag (FU_DEVICE (self), FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_TRIPLET); fu_device_set_vendor (FU_DEVICE (self), "altusmetrum.org"); fu_device_set_summary (FU_DEVICE (self), "A USB hardware random number generator"); - fu_device_set_protocol (FU_DEVICE (self), "org.altusmetrum.altos"); + fu_device_add_protocol (FU_DEVICE (self), "org.altusmetrum.altos"); /* requires manual step */ if (!fu_device_has_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) @@ -577,6 +576,6 @@ klass_device->probe = fu_altos_device_probe; klass_device->prepare_firmware = fu_altos_device_prepare_firmware; klass_device->write_firmware = fu_altos_device_write_firmware; - klass_device->read_firmware = fu_altos_device_read_firmware; + klass_device->dump_firmware = fu_altos_device_dump_firmware; object_class->finalize = fu_altos_device_finalize; } diff -Nru fwupd-1.4.5/plugins/altos/fu-altos-device.h fwupd-1.5.8/plugins/altos/fu-altos-device.h --- fwupd-1.4.5/plugins/altos/fu-altos-device.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/altos/fu-altos-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2017 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/altos/fu-altos-firmware.c fwupd-1.5.8/plugins/altos/fu-altos-firmware.c --- fwupd-1.4.5/plugins/altos/fu-altos-firmware.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/altos/fu-altos-firmware.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2019 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/altos/fu-altos-firmware.h fwupd-1.5.8/plugins/altos/fu-altos-firmware.h --- fwupd-1.4.5/plugins/altos/fu-altos-firmware.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/altos/fu-altos-firmware.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2019 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/altos/fu-plugin-altos.c fwupd-1.5.8/plugins/altos/fu-plugin-altos.c --- fwupd-1.4.5/plugins/altos/fu-plugin-altos.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/altos/fu-plugin-altos.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2017 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -7,7 +7,6 @@ #include "config.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #include "fu-altos-device.h" #include "fu-altos-firmware.h" @@ -17,5 +16,5 @@ { fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_set_device_gtype (plugin, FU_TYPE_ALTOS_DEVICE); - fu_plugin_add_firmware_gtype (plugin, "altos", FU_TYPE_ALTOS_FIRMWARE); + fu_plugin_add_firmware_gtype (plugin, NULL, FU_TYPE_ALTOS_FIRMWARE); } diff -Nru fwupd-1.4.5/plugins/altos/meson.build fwupd-1.5.8/plugins/altos/meson.build --- fwupd-1.4.5/plugins/altos/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/altos/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,7 @@ +if get_option('plugin_altos') +if not get_option('gudev') or not get_option('gusb') + error('gudev and gusb is required for plugin_altos') +endif cargs = ['-DG_LOG_DOMAIN="FuPluginAltos"'] install_data(['altos.quirk'], @@ -28,3 +32,4 @@ plugin_deps, ], ) +endif diff -Nru fwupd-1.4.5/plugins/altos/README.md fwupd-1.5.8/plugins/altos/README.md --- fwupd-1.4.5/plugins/altos/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/altos/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -34,6 +34,16 @@ * `USB\VID_1D50&PID_60C6` * `USB\VID_1D50` +Update Behavior +--------------- + +The device usually presents in runtime mode, but on detach re-enumerates with a +different USB PID in a bootloader mode. On attach the device again re-enumerates +back to the runtime mode. + +For this reason the `REPLUG_MATCH_GUID` internal device flag is used so that +the bootloader and runtime modes are treated as the same device. + Vendor ID Security ------------------ @@ -67,3 +77,7 @@ Command: `v\n` The device will reboot into application mode. This is typically performed after flashing firmware completes successfully. + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff -Nru fwupd-1.4.5/plugins/amt/fu-plugin-amt.c fwupd-1.5.8/plugins/amt/fu-plugin-amt.c --- fwupd-1.4.5/plugins/amt/fu-plugin-amt.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/amt/fu-plugin-amt.c 2021-03-31 20:08:32.000000000 +0000 @@ -15,7 +15,6 @@ #include #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" typedef struct { uuid_le guid; diff -Nru fwupd-1.4.5/plugins/amt/meson.build fwupd-1.5.8/plugins/amt/meson.build --- fwupd-1.4.5/plugins/amt/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/amt/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,4 @@ +if get_option('plugin_amt') cargs = ['-DG_LOG_DOMAIN="FuPluginAmt"'] shared_module('fu_plugin_amt', @@ -21,3 +22,4 @@ plugin_deps, ], ) +endif diff -Nru fwupd-1.4.5/plugins/amt/README.md fwupd-1.5.8/plugins/amt/README.md --- fwupd-1.4.5/plugins/amt/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/amt/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -25,3 +25,7 @@ ------------------ The device is not upgradable and thus requires no vendor ID set. + +External interface access +------------------------- +This plugin requires read only access to `/dev/mei0`. diff -Nru fwupd-1.4.5/plugins/ata/ata.conf fwupd-1.5.8/plugins/ata/ata.conf --- fwupd-1.4.5/plugins/ata/ata.conf 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/ata/ata.conf 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -[ata] - -# ask the user to report the missing OUI in the daemon logs -UnknownOuiReport=true diff -Nru fwupd-1.4.5/plugins/ata/ata.quirk fwupd-1.5.8/plugins/ata/ata.quirk --- fwupd-1.4.5/plugins/ata/ata.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/ata/ata.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,68 +1,99 @@ # match all devices with this udev subsystem -[DeviceInstanceId=BLOCK] +[BLOCK] Plugin = ata -[DeviceInstanceId=OUI\000039] +[OUI\000039] Vendor = Toshiba VendorId = ATA:0x1179 -[DeviceInstanceId=OUI\0000f0] +[OUI\0000f0] Vendor = Samsung VendorId = ATA:0x144D -[DeviceInstanceId=OUI\0004cf] +[OUI\000120] +Vendor = Corsair +VendorId = ATA:0x1987 + +[OUI\0004cf] Vendor = Seagate VendorId = ATA:0x1BB1 -[DeviceInstanceId=OUI\000c50] +[OUI\00080d] +Vendor = Toshiba +VendorId = ATA:0x1179 + +[OUI\000c50] Vendor = Seagate VendorId = ATA:0x1BB1 -[DeviceInstanceId=OUI\000cca] +[OUI\000cca] Vendor = Western Digital VendorId = ATA:0x101C -[DeviceInstanceId=OUI\0014ee] +[OUI\0014ee] Vendor = Western Digital VendorId = ATA:0x101C -[DeviceInstanceId=OUI\001517] +[OUI\001517] Vendor = Intel VendorId = ATA:0x8086 -[DeviceInstanceId=OUI\001b44] +[OUI\001b44] Vendor = Western Digital VendorId = ATA:0x101C -[DeviceInstanceId=OUI\002303] +[OUI\002303] Vendor = LITE-ON VendorId = ATA:0x14A4 -[DeviceInstanceId=OUI\002538] +[OUI\0024e9] Vendor = Samsung VendorId = ATA:0x144D -[DeviceInstanceId=OUI\0026b7] +[OUI\002538] +Vendor = Samsung +VendorId = ATA:0x144D + +[OUI\0026b7] Vendor = Kingston VendorId = ATA:0x2646 -[DeviceInstanceId=OUI\00a075] +[OUI\00a075] Vendor = Micron VendorId = ATA:0x1344 -[DeviceInstanceId=OUI\550380] +[OUI\030302] +Vendor = SK hynix +VendorId = ATA:0x1C5C + +[OUI\550380] Vendor = Kingston VendorId = ATA:0x2646 -[DeviceInstanceId=OUI\5cd2e4] +[OUI\5cd2e4] Vendor = Intel VendorId = ATA:0x8086 -[DeviceInstanceId=OUI\707c18] +[OUI\707c18] Vendor = ADATA VendorId = ATA:0x1CC1 -[DeviceInstanceId=OUI\001b44] +[OUI\7c3548] +Vendor = Transcend +VendorId = ATA:0x8564 + +[OUI\001b44] Vendor = SanDisk VendorId = ATA:0x15B7 +[OUI\96a060] +Vendor = Western Digital +VendorId = ATA:0x101C + +[OUI\f8db4c] +Vendor = PNY +VendorId = ATA:0x196E + +[OUI\e83a97] +Vendor = Toshiba +VendorId = ATA:0x1179 diff -Nru fwupd-1.4.5/plugins/ata/fu-ata-device.c fwupd-1.5.8/plugins/ata/fu-ata-device.c --- fwupd-1.4.5/plugins/ata/fu-ata-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/ata/fu-ata-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -72,7 +72,6 @@ guint16 transfer_blocks; guint8 transfer_mode; guint32 oui; - gboolean unknown_oui_report; }; G_DEFINE_TYPE (FuAtaDevice, fu_ata_device, FU_TYPE_UDEV_DEVICE) @@ -89,12 +88,6 @@ return self->transfer_blocks; } -void -fu_ata_device_set_unknown_oui_report (FuAtaDevice *self, gboolean enabled) -{ - self->unknown_oui_report = enabled; -} - static gchar * fu_ata_device_get_string (const guint16 *buf, guint start, guint end) { @@ -164,7 +157,8 @@ /* do not add the FuUdevDevice instance IDs as generic firmware * should not be used on these OEM-specific devices */ - fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NO_AUTO_INSTANCE_IDS); + fu_device_add_internal_flag (FU_DEVICE (self), + FU_DEVICE_INTERNAL_FLAG_NO_AUTO_INSTANCE_IDS); /* add instance ID *and* GUID as using no-auto-instance-ids */ guid_id = g_strdup_printf ("STORAGE-DELL-%s", component_id); @@ -179,7 +173,7 @@ /* owned by Dell */ fu_device_set_vendor (FU_DEVICE (self), "Dell"); - fu_device_set_vendor_id (FU_DEVICE (self), "ATA:0x1028"); + fu_device_add_vendor_id (FU_DEVICE (self), "ATA:0x1028"); } static void @@ -303,7 +297,7 @@ /* devices without a vendor ID will not be UPGRADABLE */ if (vendor_id != NULL) - fu_device_set_vendor_id (FU_DEVICE (self), vendor_id); + fu_device_add_vendor_id (FU_DEVICE (self), vendor_id); /* remove leading junk */ while (name[0] == ' ' || name[0] == '_' || name[0] == '-') @@ -394,28 +388,17 @@ fu_device_add_instance_id_full (device, tmp, FU_DEVICE_INSTANCE_FLAG_ONLY_QUIRKS); has_oui_quirk = fu_device_get_vendor (FU_DEVICE (self)) != NULL; } + if (self->oui > 0x0) { + g_autofree gchar *vendor_id = NULL; + vendor_id = g_strdup_printf ("OUI:%06x", self->oui); + fu_device_add_vendor_id (device, vendor_id); + } /* if not already set using the vendor block or a OUI quirk */ name = fu_ata_device_get_string (id, 27, 46); if (name != NULL && !has_oui_quirk) fu_ata_device_parse_vendor_name (self, name); - /* ask user to report data */ - if (self->oui != 0x0 && !has_oui_quirk && self->unknown_oui_report) { - const gchar *url = "https://github.com/fwupd/fwupd/wiki/ATA-Disk:-OUI-Quirk-Required"; - g_printerr ("\nOUI quirk required, please see %s!\n", url); - g_printerr ("---\n"); - g_printerr ("[DeviceInstanceId=OUI\\%06x]\n", self->oui); - if (fu_device_get_vendor_id (FU_DEVICE (self)) != NULL) { - g_printerr ("Vendor = %s\n", fu_device_get_vendor (FU_DEVICE (self))); - g_printerr ("VendorId = %s\n", fu_device_get_vendor_id (FU_DEVICE (self))); - } else { - g_printerr ("Vendor = FIXME\n"); - g_printerr ("VendorId = ATA:UNKNOWN\n"); - } - g_printerr ("---\n"); - } - /* 8 byte additional product identifier == SKU? */ sku = fu_ata_device_get_string (id, 170, 173); if (sku != NULL) @@ -445,10 +428,14 @@ } static gboolean -fu_ata_device_probe (FuUdevDevice *device, GError **error) +fu_ata_device_probe (FuDevice *device, GError **error) { FuAtaDevice *self = FU_ATA_DEVICE (device); - GUdevDevice *udev_device = fu_udev_device_get_dev (device); + GUdevDevice *udev_device = fu_udev_device_get_dev (FU_UDEV_DEVICE (device)); + + /* FuUdevDevice->probe */ + if (!FU_DEVICE_CLASS (fu_ata_device_parent_class)->probe (device, error)) + return FALSE; /* check is valid */ if (g_strcmp0 (g_udev_device_get_devtype (udev_device), "disk") != 0) { @@ -469,15 +456,15 @@ } /* set the physical ID */ - if (!fu_udev_device_set_physical_id (device, "scsi", error)) + if (!fu_udev_device_set_physical_id (FU_UDEV_DEVICE (device), "scsi", error)) return FALSE; /* look at the PCI and USB depth to work out if in an external enclosure */ - self->pci_depth = fu_udev_device_get_slot_depth (device, "pci"); - self->usb_depth = fu_udev_device_get_slot_depth (device, "usb"); + self->pci_depth = fu_udev_device_get_slot_depth (FU_UDEV_DEVICE (device), "pci"); + self->usb_depth = fu_udev_device_get_slot_depth (FU_UDEV_DEVICE (device), "usb"); if (self->pci_depth <= 2 && self->usb_depth <= 2) { - fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL); - fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_INTERNAL); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE); } return TRUE; @@ -548,10 +535,11 @@ SG_IO, (guint8 *) &io_hdr, NULL, error)) return FALSE; - g_debug ("ATA_%u status=0x%x, host_status=0x%x, driver_status=0x%x", - io_hdr.cmd_len, io_hdr.status, io_hdr.host_status, io_hdr.driver_status); - if (g_getenv ("FWUPD_ATA_VERBOSE") != NULL) + if (g_getenv ("FWUPD_ATA_VERBOSE") != NULL) { + g_debug ("ATA_%u status=0x%x, host_status=0x%x, driver_status=0x%x", + io_hdr.cmd_len, io_hdr.status, io_hdr.host_status, io_hdr.driver_status); fu_common_dump_raw (G_LOG_DOMAIN, "SB", sb, sizeof(sb)); + } /* error check */ if (io_hdr.status && io_hdr.status != SG_CHECK_CONDITION) { @@ -584,8 +572,12 @@ tf->lbah = sb[8 + 11]; tf->dev = sb[8 + 12]; tf->status = sb[8 + 13]; - g_debug ("ATA_%u stat=%02x err=%02x nsect=%02x lbal=%02x lbam=%02x lbah=%02x dev=%02x", - io_hdr.cmd_len, tf->status, tf->error, tf->nsect, tf->lbal, tf->lbam, tf->lbah, tf->dev); + if (g_getenv ("FWUPD_ATA_VERBOSE") != NULL) { + g_debug ("ATA_%u stat=%02x err=%02x nsect=%02x lbal=%02x " + "lbam=%02x lbah=%02x dev=%02x", + io_hdr.cmd_len, tf->status, tf->error, tf->nsect, tf->lbal, + tf->lbam, tf->lbah, tf->dev); + } /* io error */ if (tf->status & (ATA_STAT_ERR | ATA_STAT_DRQ)) { @@ -614,7 +606,7 @@ tf.nsect = 1; /* 512 bytes */ if (!fu_ata_device_command (self, &tf, SG_DXFER_FROM_DEV, 1000, id, sizeof(id), error)) { - g_prefix_error (error, "failed to IDENTIFY"); + g_prefix_error (error, "failed to IDENTIFY: "); return FALSE; } if (g_getenv ("FWUPD_ATA_VERBOSE") != NULL) @@ -688,7 +680,7 @@ if (!fu_ata_device_command (self, &tf, SG_DXFER_TO_DEV, 120 * 1000, /* a long time! */ (guint8 *) data, data_sz, error)) { - g_prefix_error (error, "failed to write firmware @0x%0x", + g_prefix_error (error, "failed to write firmware @0x%0x: ", (guint) addr); return FALSE; } @@ -764,10 +756,10 @@ for (guint i = 0; i < chunks->len; i++) { FuChunk *chk = g_ptr_array_index (chunks, i); if (!fu_ata_device_fw_download (self, - chk->idx, - chk->address, - chk->data, - chk->data_sz, + fu_chunk_get_idx (chk), + fu_chunk_get_address (chk), + fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk), error)) { g_prefix_error (error, "failed to write chunk %u: ", i); return FALSE; @@ -834,7 +826,7 @@ fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_set_summary (FU_DEVICE (self), "ATA Drive"); fu_device_add_icon (FU_DEVICE (self), "drive-harddisk"); - fu_device_set_protocol (FU_DEVICE (self), "org.t13.ata"); + fu_device_add_protocol (FU_DEVICE (self), "org.t13.ata"); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_PLAIN); fu_udev_device_set_flags (FU_UDEV_DEVICE (self), FU_UDEV_DEVICE_FLAG_OPEN_READ); } @@ -850,14 +842,13 @@ { GObjectClass *object_class = G_OBJECT_CLASS (klass); FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - FuUdevDeviceClass *klass_udev_device = FU_UDEV_DEVICE_CLASS (klass); object_class->finalize = fu_ata_device_finalize; klass_device->to_string = fu_ata_device_to_string; klass_device->set_quirk_kv = fu_ata_device_set_quirk_kv; klass_device->setup = fu_ata_device_setup; klass_device->activate = fu_ata_device_activate; klass_device->write_firmware = fu_ata_device_write_firmware; - klass_udev_device->probe = fu_ata_device_probe; + klass_device->probe = fu_ata_device_probe; } FuAtaDevice * diff -Nru fwupd-1.4.5/plugins/ata/fu-ata-device.h fwupd-1.5.8/plugins/ata/fu-ata-device.h --- fwupd-1.4.5/plugins/ata/fu-ata-device.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/ata/fu-ata-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -18,5 +18,3 @@ /* for self tests */ guint8 fu_ata_device_get_transfer_mode (FuAtaDevice *self); guint16 fu_ata_device_get_transfer_blocks (FuAtaDevice *self); -void fu_ata_device_set_unknown_oui_report (FuAtaDevice *self, - gboolean enabled); diff -Nru fwupd-1.4.5/plugins/ata/fu-plugin-ata.c fwupd-1.5.8/plugins/ata/fu-plugin-ata.c --- fwupd-1.4.5/plugins/ata/fu-plugin-ata.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/ata/fu-plugin-ata.c 2021-03-31 20:08:32.000000000 +0000 @@ -7,7 +7,6 @@ #include "config.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #include "fu-ata-device.h" @@ -18,11 +17,3 @@ fu_plugin_add_udev_subsystem (plugin, "block"); fu_plugin_set_device_gtype (plugin, FU_TYPE_ATA_DEVICE); } - -gboolean -fu_plugin_device_created (FuPlugin *plugin, FuDevice *dev, GError **error) -{ - gboolean tmp = fu_plugin_get_config_value_boolean (plugin, "UnknownOuiReport"); - fu_ata_device_set_unknown_oui_report (FU_ATA_DEVICE (dev), tmp); - return TRUE; -} diff -Nru fwupd-1.4.5/plugins/ata/fu-self-test.c fwupd-1.5.8/plugins/ata/fu-self-test.c --- fwupd-1.4.5/plugins/ata/fu-self-test.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/ata/fu-self-test.c 2021-03-31 20:08:32.000000000 +0000 @@ -16,12 +16,17 @@ { gboolean ret; gsize sz; + const gchar *ci = g_getenv ("CI_NETWORK"); g_autofree gchar *data = NULL; g_autofree gchar *path = NULL; g_autoptr(FuAtaDevice) dev = NULL; g_autoptr(GError) error = NULL; - path = g_build_filename (TESTDATADIR, "StarDrive-SBFM61.2.bin", NULL); + path = g_test_build_filename (G_TEST_DIST, "tests", "StarDrive-SBFM61.2.bin", NULL); + if (!g_file_test (path, G_FILE_TEST_EXISTS) && ci == NULL) { + g_test_skip ("Missing StarDrive-SBFM61.2.bin"); + return; + } ret = g_file_get_contents (path, &data, &sz, &error); g_assert_no_error (error); g_assert (ret); @@ -40,20 +45,24 @@ { gboolean ret; gsize sz; + const gchar *ci = g_getenv ("CI_NETWORK"); g_autofree gchar *data = NULL; g_autofree gchar *path = NULL; g_autofree gchar *str = NULL; g_autoptr(FuAtaDevice) dev = NULL; g_autoptr(GError) error = NULL; - path = g_build_filename (TESTDATADIR, "Samsung SSD 860 EVO 500GB.bin", NULL); + path = g_test_build_filename (G_TEST_DIST, "tests", "Samsung SSD 860 EVO 500GB.bin", NULL); + if (!g_file_test (path, G_FILE_TEST_EXISTS) && ci == NULL) { + g_test_skip ("Missing Samsung SSD 860 EVO 500GB.bin"); + return; + } ret = g_file_get_contents (path, &data, &sz, &error); g_assert_no_error (error); g_assert (ret); dev = fu_ata_device_new_from_blob ((guint8 *)data, sz, &error); g_assert_no_error (error); g_assert_nonnull (dev); - fu_ata_device_set_unknown_oui_report (dev, FALSE); fu_device_convert_instance_ids (FU_DEVICE (dev)); str = fu_device_to_string (FU_DEVICE (dev)); g_debug ("%s", str); diff -Nru fwupd-1.4.5/plugins/ata/meson.build fwupd-1.5.8/plugins/ata/meson.build --- fwupd-1.4.5/plugins/ata/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/ata/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,4 @@ +if get_option('gudev') cargs = ['-DG_LOG_DOMAIN="FuPluginAta"'] install_data([ @@ -6,10 +7,6 @@ install_dir: join_paths(datadir, 'fwupd', 'quirks.d') ) -install_data(['ata.conf'], - install_dir: join_paths(sysconfdir, 'fwupd') -) - shared_module('fu_plugin_ata', fu_hash, sources : [ @@ -37,8 +34,9 @@ ) if get_option('tests') - testdatadir = join_paths(meson.current_source_dir(), 'tests') - cargs += '-DTESTDATADIR="' + testdatadir + '"' + testdatadirs = environment() + testdatadirs.set('G_TEST_SRCDIR', meson.current_source_dir()) + testdatadirs.set('G_TEST_BUILDDIR', meson.current_build_dir()) e = executable( 'ata-self-test', fu_hash, @@ -58,7 +56,9 @@ fwupd, fwupdplugin, ], - c_args : cargs + install : true, + install_dir : installed_test_bindir, ) - test('ata-self-test', e) + test('ata-self-test', e, env : testdatadirs) # added to installed-tests +endif endif diff -Nru fwupd-1.4.5/plugins/ata/README.md fwupd-1.5.8/plugins/ata/README.md --- fwupd-1.4.5/plugins/ata/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/ata/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -34,6 +34,14 @@ See https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-ide-devices for more details. +Update Behavior +--------------- + +The firmware is deployed when the device is in normal runtime mode, but it is +only activated when the system is in the final shutdown stages. This is done to +minimize the chance of data loss if the switch to the new firmware is not done +correctly. + Vendor ID Security ------------------ @@ -47,3 +55,7 @@ |------------------------|-------------------------------------------|-----------------------| | `AtaTransferBlocks` | Blocks to transfer, or `0xffff` for max | 1.2.4 | | `AtaTransferMode` | The transfer mode, `0x3`, `0x7` or `0xe` | 1.2.4 | + +External interface access +------------------------- +This plugin requires the `SG_IO` ioctl interface. Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/ata/tests/Samsung SSD 860 EVO 500GB.bin and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/ata/tests/Samsung SSD 860 EVO 500GB.bin differ Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/ata/tests/StarDrive-SBFM61.2.bin and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/ata/tests/StarDrive-SBFM61.2.bin differ diff -Nru fwupd-1.4.5/plugins/bcm57xx/bcm57xx.quirk fwupd-1.5.8/plugins/bcm57xx/bcm57xx.quirk --- fwupd-1.4.5/plugins/bcm57xx/bcm57xx.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/bcm57xx/bcm57xx.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,9 @@ +# Broadcom BCM5719 +[PCI\VEN_14E4&DEV_1657] +Plugin = bcm57xx + +# Dell PCI card +[PCI\VEN_14E4&DEV_1657&SUBSYS_14E41904] +FirmwareSize = 0x80000 +[PCI\VEN_14E4&DEV_1657&SUBSYS_94E41904] +FirmwareSize = 0x80000 diff -Nru fwupd-1.4.5/plugins/bcm57xx/fu-bcm57xx-common.c fwupd-1.5.8/plugins/bcm57xx/fu-bcm57xx-common.c --- fwupd-1.4.5/plugins/bcm57xx/fu-bcm57xx-common.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/bcm57xx/fu-bcm57xx-common.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2018 Evan Lojewski + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: GPL-2+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" + +#include "fu-bcm57xx-common.h" + +guint32 +fu_bcm57xx_nvram_crc (const guint8 *buf, gsize bufsz) +{ + return fu_common_crc32 (buf, bufsz); +} + +gboolean +fu_bcm57xx_verify_crc (GBytes *fw, GError **error) +{ + guint32 crc_actual; + guint32 crc_file = 0; + gsize bufsz = 0x0; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + + /* expected */ + if (!fu_common_read_uint32_safe (buf, bufsz, bufsz - sizeof(guint32), + &crc_file, G_LITTLE_ENDIAN, error)) + return FALSE; + + /* reality */ + crc_actual = fu_bcm57xx_nvram_crc (buf, bufsz - sizeof(guint32)); + if (crc_actual != crc_file) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid CRC, expected 0x%08x got: 0x%08x", + (guint) crc_file, (guint) crc_actual); + return FALSE; + } + + /* success */ + return TRUE; +} + +gboolean +fu_bcm57xx_verify_magic (GBytes *fw, gsize offset, GError **error) +{ + guint32 magic = 0; + gsize bufsz = 0x0; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + + /* hardcoded value */ + if (!fu_common_read_uint32_safe (buf, bufsz, offset, &magic, G_BIG_ENDIAN, error)) + return FALSE; + if (magic != BCM_NVRAM_MAGIC) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid magic, got: 0x%x", + (guint) magic); + return FALSE; + } + + /* success */ + return TRUE; +} + +void +fu_bcm57xx_veritem_free (Bcm57xxVeritem *veritem) +{ + g_free (veritem->branch); + g_free (veritem->version); + g_free (veritem); +} + +Bcm57xxVeritem * +fu_bcm57xx_veritem_new (const guint8 *buf, gsize bufsz) +{ + g_autofree gchar *tmp = NULL; + g_autoptr(Bcm57xxVeritem) veritem = g_new0 (Bcm57xxVeritem, 1); + struct { + const gchar *prefix; + const gchar *branch; + FwupdVersionFormat verfmt; + } data[] = { + { "5719-v", BCM_FW_BRANCH_UNKNOWN, FWUPD_VERSION_FORMAT_PAIR }, + { "stage1-", BCM_FW_BRANCH_OSS_FIRMWARE, FWUPD_VERSION_FORMAT_TRIPLET }, + { NULL, NULL, 0 } + }; + + /* do not assume this is NUL terminated */ + tmp = g_strndup ((const gchar *) buf, bufsz); + if (tmp == NULL || tmp[0] == '\0') + return NULL; + + /* use prefix to define object */ + for (guint i = 0; data[i].prefix != NULL; i++) { + if (g_str_has_prefix (tmp, data[i].prefix)) { + veritem->version = g_strdup (tmp + strlen (data[i].prefix)); + veritem->branch = g_strdup (data[i].branch); + veritem->verfmt = data[i].verfmt; + return g_steal_pointer (&veritem); + } + } + veritem->verfmt = FWUPD_VERSION_FORMAT_UNKNOWN; + veritem->version = g_strdup (tmp); + return g_steal_pointer (&veritem); +} diff -Nru fwupd-1.4.5/plugins/bcm57xx/fu-bcm57xx-common.h fwupd-1.5.8/plugins/bcm57xx/fu-bcm57xx-common.h --- fwupd-1.4.5/plugins/bcm57xx/fu-bcm57xx-common.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/bcm57xx/fu-bcm57xx-common.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include +#include + +#define BCM_VENDOR_BROADCOM 0x14E4 + +#define BCM_FW_BRANCH_UNKNOWN NULL +#define BCM_FW_BRANCH_OSS_FIRMWARE "oss-firmware" + +#define BCM_FIRMWARE_SIZE 0x40000 /* x2 for Dell */ +#define BCM_PHYS_ADDR_DEFAULT 0x08003800 + +#define BCM_NVRAM_MAGIC 0x669955AA + +/* offsets into NVMRAM */ +#define BCM_NVRAM_HEADER_BASE 0x00 +#define BCM_NVRAM_DIRECTORY_BASE 0x14 +#define BCM_NVRAM_INFO_BASE 0x74 +#define BCM_NVRAM_VPD_BASE 0x100 +#define BCM_NVRAM_INFO2_BASE 0x200 +#define BCM_NVRAM_STAGE1_BASE 0x28c + +#define BCM_NVRAM_HEADER_MAGIC 0x00 +#define BCM_NVRAM_HEADER_PHYS_ADDR 0x04 +#define BCM_NVRAM_HEADER_SIZE_WRDS 0x08 +#define BCM_NVRAM_HEADER_OFFSET 0x0C +#define BCM_NVRAM_HEADER_CRC 0x10 +#define BCM_NVRAM_HEADER_SZ 0x14 + +#define BCM_NVRAM_INFO_MAC_ADDR0 0x00 +#define BCM_NVRAM_INFO_VENDOR 0x2E +#define BCM_NVRAM_INFO_DEVICE 0x2C +#define BCM_NVRAM_INFO_SZ 0x8C + +#define BCM_NVRAM_DIRECTORY_ADDR 0x00 +#define BCM_NVRAM_DIRECTORY_SIZE_WRDS 0x04 +#define BCM_NVRAM_DIRECTORY_OFFSET 0x08 +#define BCM_NVRAM_DIRECTORY_SZ 0x0c + +#define BCM_NVRAM_VPD_SZ 0x100 + +#define BCM_NVRAM_INFO2_SZ 0x8c + +#define BCM_NVRAM_STAGE1_VERADDR 0x08 +#define BCM_NVRAM_STAGE1_VERSION 0x0C + +typedef struct { + gchar *branch; + gchar *version; + FwupdVersionFormat verfmt; +} Bcm57xxVeritem; + +guint32 fu_bcm57xx_nvram_crc (const guint8 *buf, + gsize bufsz); +gboolean fu_bcm57xx_verify_crc (GBytes *fw, + GError **error); +gboolean fu_bcm57xx_verify_magic (GBytes *fw, + gsize offset, + GError **error); + +/* parses stage1 version */ +void fu_bcm57xx_veritem_free (Bcm57xxVeritem *veritem); +Bcm57xxVeritem *fu_bcm57xx_veritem_new (const guint8 *buf, + gsize bufsz); +G_DEFINE_AUTOPTR_CLEANUP_FUNC(Bcm57xxVeritem, fu_bcm57xx_veritem_free) diff -Nru fwupd-1.4.5/plugins/bcm57xx/fu-bcm57xx-device.c fwupd-1.5.8/plugins/bcm57xx/fu-bcm57xx-device.c --- fwupd-1.4.5/plugins/bcm57xx/fu-bcm57xx-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/bcm57xx/fu-bcm57xx-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,650 @@ +/* + * Copyright (C) 2018 Evan Lojewski + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: GPL-2+ + */ + +#include "config.h" + +#ifdef HAVE_ERRNO_H +#include +#endif +#include +#include +#ifdef HAVE_ETHTOOL_H +#include +#include +#include +#endif +#ifdef HAVE_IOCTL_H +#include +#endif +#ifdef HAVE_SOCKET_H +#include +#endif + +#include "fu-chunk.h" +#include "fu-common.h" + +#include "fu-bcm57xx-common.h" +#include "fu-bcm57xx-device.h" +#include "fu-bcm57xx-recovery-device.h" +#include "fu-bcm57xx-firmware.h" +#include "fu-bcm57xx-dict-image.h" + +#define FU_BCM57XX_BLOCK_SZ 0x4000 /* 16kb */ + +struct _FuBcm57xxDevice { + FuUdevDevice parent_instance; + FuBcm57xxRecoveryDevice *recovery; + gchar *ethtool_iface; + int ethtool_fd; +}; + +G_DEFINE_TYPE (FuBcm57xxDevice, fu_bcm57xx_device, FU_TYPE_UDEV_DEVICE) + +static void +fu_bcm57xx_device_to_string (FuDevice *device, guint idt, GString *str) +{ + FuBcm57xxDevice *self = FU_BCM57XX_DEVICE (device); + FU_DEVICE_CLASS (fu_bcm57xx_device_parent_class)->to_string (device, idt, str); + fu_common_string_append_kv (str, idt, "EthtoolIface", self->ethtool_iface); +} + +static gboolean +fu_bcm57xx_device_probe (FuDevice *device, GError **error) +{ + FuBcm57xxDevice *self = FU_BCM57XX_DEVICE (device); + g_autofree gchar *fn = NULL; + g_autoptr(GPtrArray) ifaces = NULL; + + /* FuUdevDevice->probe */ + if (!FU_DEVICE_CLASS (fu_bcm57xx_device_parent_class)->probe (device, error)) + return FALSE; + + /* only enumerate number 0 */ + if (fu_udev_device_get_number (FU_UDEV_DEVICE (device)) != 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "only device 0 supported on multi-device card"); + return FALSE; + } + + /* we need this even for non-recovery to reset APE */ + fu_device_set_quirks (FU_DEVICE (self->recovery), + fu_device_get_quirks (FU_DEVICE (self))); + fu_device_incorporate (FU_DEVICE (self->recovery), FU_DEVICE (self)); + if (!fu_device_probe (FU_DEVICE (self->recovery), error)) + return FALSE; + + /* only if has an interface */ + fn = g_build_filename (fu_udev_device_get_sysfs_path (FU_UDEV_DEVICE (device)), "net", NULL); + if (!g_file_test (fn, G_FILE_TEST_EXISTS)) { + g_debug ("waiting for net devices to appear"); + g_usleep (50 * 1000); + } + ifaces = fu_common_filename_glob (fn, "en*", NULL); + if (ifaces == NULL || ifaces->len == 0) { + fu_device_add_child (FU_DEVICE (self), FU_DEVICE (self->recovery)); + } else { + self->ethtool_iface = g_path_get_basename (g_ptr_array_index (ifaces, 0)); + } + + /* success */ + return fu_udev_device_set_physical_id (FU_UDEV_DEVICE (device), "pci", error); +} + +static gboolean +fu_bcm57xx_device_nvram_write (FuBcm57xxDevice *self, + guint32 address, + const guint8 *buf, + gsize bufsz, + GError **error) +{ +#ifdef HAVE_ETHTOOL_H + gsize eepromsz; + gint rc = -1; + struct ifreq ifr = { 0 }; + g_autofree struct ethtool_eeprom *eeprom = NULL; + + /* failed to load tg3 */ + if (self->ethtool_iface == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as ethtool interface disabled"); + return FALSE; + } + + /* sanity check */ + if (address + bufsz > fu_device_get_firmware_size_max (FU_DEVICE (self))) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "tried to read outside of EEPROM size [0x%x]", + (guint) fu_device_get_firmware_size_max (FU_DEVICE (self))); + return FALSE; + } + + /* write EEPROM (NVRAM) data */ + eepromsz = sizeof(struct ethtool_eeprom) + bufsz; + eeprom = (struct ethtool_eeprom *) g_malloc0 (eepromsz); + eeprom->cmd = ETHTOOL_SEEPROM; + eeprom->magic = BCM_NVRAM_MAGIC; + eeprom->len = bufsz; + eeprom->offset = address; + memcpy (eeprom->data, buf, eeprom->len); + strncpy (ifr.ifr_name, self->ethtool_iface, IFNAMSIZ - 1); + ifr.ifr_data = (char *) eeprom; +#ifdef HAVE_IOCTL_H + rc = ioctl (self->ethtool_fd, SIOCETHTOOL, &ifr); +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as not found"); + return FALSE; +#endif + if (rc < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "cannot write eeprom [%i]", rc); + return FALSE; + } + + /* success */ + return TRUE; +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as not found"); + return FALSE; +#endif +} + +static gboolean +fu_bcm57xx_device_nvram_read (FuBcm57xxDevice *self, + guint32 address, + guint8 *buf, + gsize bufsz, + GError **error) +{ +#ifdef HAVE_ETHTOOL_H + gsize eepromsz; + gint rc = -1; + struct ifreq ifr = { 0 }; + g_autofree struct ethtool_eeprom *eeprom = NULL; + + /* failed to load tg3 */ + if (self->ethtool_iface == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as ethtool interface disabled"); + return FALSE; + } + + /* sanity check */ + if (address + bufsz > fu_device_get_firmware_size_max (FU_DEVICE (self))) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "tried to read outside of EEPROM size [0x%x]", + (guint) fu_device_get_firmware_size_max (FU_DEVICE (self))); + return FALSE; + } + + /* read EEPROM (NVRAM) data */ + eepromsz = sizeof(struct ethtool_eeprom) + bufsz; + eeprom = (struct ethtool_eeprom *) g_malloc0 (eepromsz); + eeprom->cmd = ETHTOOL_GEEPROM; + eeprom->len = bufsz; + eeprom->offset = address; + strncpy (ifr.ifr_name, self->ethtool_iface, IFNAMSIZ - 1); + ifr.ifr_data = (char *) eeprom; +#ifdef HAVE_IOCTL_H + rc = ioctl (self->ethtool_fd, SIOCETHTOOL, &ifr); +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as not found"); + return FALSE; +#endif + if (rc < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "cannot read eeprom [%i]", rc); + return FALSE; + } + + /* copy back data */ + if (!fu_memcpy_safe (buf, bufsz, 0x0, /* dst */ + (guint8 *) eeprom, eepromsz, /* src */ + G_STRUCT_OFFSET(struct ethtool_eeprom, data), + bufsz, error)) + return FALSE; + + /* success */ + return TRUE; +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as not found"); + return FALSE; +#endif +} + +static gboolean +fu_bcm57xx_device_nvram_check (FuBcm57xxDevice *self, GError **error) +{ +#ifdef HAVE_ETHTOOL_H + gint rc = -1; + struct ethtool_drvinfo drvinfo = { 0 }; + struct ifreq ifr = { 0 }; + + /* failed to load tg3 */ + if (self->ethtool_iface == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as ethtool interface disabled"); + return FALSE; + } + + /* get driver info */ + drvinfo.cmd = ETHTOOL_GDRVINFO; + strncpy (ifr.ifr_name, self->ethtool_iface, IFNAMSIZ - 1); + ifr.ifr_data = (char *) &drvinfo; +#ifdef HAVE_IOCTL_H + rc = ioctl (self->ethtool_fd, SIOCETHTOOL, &ifr); +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as not found"); + return FALSE; +#endif + if (rc < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "cannot get driver information [%i]", rc); + return FALSE; + } + g_debug ("FW version %s", drvinfo.fw_version); + + /* sanity check */ + if (drvinfo.eedump_len != fu_device_get_firmware_size_max (FU_DEVICE (self))) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "EEPROM size invalid, got 0x%x, expected 0x%x", + drvinfo.eedump_len, + (guint) fu_device_get_firmware_size_max (FU_DEVICE (self))); + return FALSE; + } + + /* success */ + return TRUE; +#else + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported as not found"); + return FALSE; +#endif +} + +static gboolean +fu_bcm57xx_device_activate (FuDevice *device, GError **error) +{ + FuBcm57xxDevice *self = FU_BCM57XX_DEVICE (device); + g_autoptr(FuDeviceLocker) locker1 = NULL; + g_autoptr(FuDeviceLocker) locker2 = NULL; + + /* the only way to do this is using the mmap method */ + locker2 = fu_device_locker_new_full (FU_DEVICE (self->recovery), + (FuDeviceLockerFunc) fu_device_detach, + (FuDeviceLockerFunc) fu_device_attach, + error); + if (locker2 == NULL) + return FALSE; + + /* open */ + locker1 = fu_device_locker_new (FU_DEVICE (self->recovery), error); + if (locker1 == NULL) + return FALSE; + + /* activate, causing APE reset, then close, then attach */ + if (!fu_device_activate (FU_DEVICE (self->recovery), error)) + return FALSE; + + /* ensure we attach before we close */ + if (!fu_device_locker_close (locker2, error)) + return FALSE; + + /* wait for the device to restart before calling reload() */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_BUSY); + fu_device_sleep_with_progress (device, 5); /* seconds */ + return TRUE; +} + +static GBytes * +fu_bcm57xx_device_dump_firmware (FuDevice *device, GError **error) +{ + FuBcm57xxDevice *self = FU_BCM57XX_DEVICE (device); + const gsize bufsz = fu_device_get_firmware_size_max (FU_DEVICE (self)); + g_autofree guint8 *buf = g_malloc0 (bufsz); + g_autoptr(GPtrArray) chunks = NULL; + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_READ); + chunks = fu_chunk_array_mutable_new (buf, bufsz, 0x0, 0x0, FU_BCM57XX_BLOCK_SZ); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + if (!fu_bcm57xx_device_nvram_read (self, fu_chunk_get_address (chk), + fu_chunk_get_data_out (chk), + fu_chunk_get_data_sz (chk), + error)) + return NULL; + fu_device_set_progress_full (device, i, chunks->len - 1); + } + + /* read from hardware */ + return g_bytes_new_take (g_steal_pointer (&buf), bufsz); +} + +static FuFirmware * +fu_bcm57xx_device_read_firmware (FuDevice *device, GError **error) +{ + g_autoptr(FuFirmware) firmware = fu_bcm57xx_firmware_new (); + g_autoptr(GBytes) fw = NULL; + + /* read from hardware */ + fw = fu_bcm57xx_device_dump_firmware (device, error); + if (fw == NULL) + return NULL; + if (!fu_firmware_parse (firmware, fw, FWUPD_INSTALL_FLAG_NONE, error)) + return NULL; + + /* remove images that will contain user-data */ + if (!fu_firmware_remove_image_by_id (firmware, "info", error)) + return NULL; + if (!fu_firmware_remove_image_by_id (firmware, "info2", error)) + return NULL; + if (!fu_firmware_remove_image_by_id (firmware, "vpd", error)) + return NULL; + return g_steal_pointer (&firmware); +} + +static FuFirmware * +fu_bcm57xx_device_prepare_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + guint dict_cnt = 0; + g_autoptr(GBytes) fw_old = NULL; + g_autoptr(FuFirmware) firmware = fu_bcm57xx_firmware_new (); + g_autoptr(FuFirmware) firmware_tmp = fu_bcm57xx_firmware_new (); + g_autoptr(FuFirmwareImage) img_ape = NULL; + g_autoptr(FuFirmwareImage) img_stage1 = NULL; + g_autoptr(FuFirmwareImage) img_stage2 = NULL; + g_autoptr(GPtrArray) images = NULL; + + /* try to parse NVRAM, stage1 or APE */ + if (!fu_firmware_parse (firmware_tmp, fw, flags, error)) { + g_prefix_error (error, "failed to parse new firmware: "); + return NULL; + } + + /* for full NVRAM image, verify if correct device */ + if ((flags & FWUPD_INSTALL_FLAG_IGNORE_VID_PID) == 0) { + guint16 vid = fu_bcm57xx_firmware_get_vendor (FU_BCM57XX_FIRMWARE (firmware_tmp)); + guint16 did = fu_bcm57xx_firmware_get_model (FU_BCM57XX_FIRMWARE (firmware_tmp)); + if (vid != 0x0 && did != 0x0 && + (fu_udev_device_get_vendor (FU_UDEV_DEVICE (device)) != vid || + fu_udev_device_get_model (FU_UDEV_DEVICE (device)) != did)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "PCI vendor or model incorrect, " + "got: %04X:%04X expected %04X:%04X", + vid, did, + fu_udev_device_get_vendor (FU_UDEV_DEVICE (device)), + fu_udev_device_get_model (FU_UDEV_DEVICE (device))); + return NULL; + } + } + + /* get the existing firmware from the device */ + fw_old = fu_bcm57xx_device_dump_firmware (device, error); + if (fw_old == NULL) + return NULL; + if (!fu_firmware_parse (firmware, fw_old, flags, error)) { + g_prefix_error (error, "failed to parse existing firmware: "); + return NULL; + } + if (g_getenv ("FWUPD_BCM57XX_VERBOSE") != NULL) { + g_autofree gchar *str = fu_firmware_to_string (firmware); + g_debug ("existing device firmware: %s", str); + } + + /* merge in all the provided images into the existing firmware */ + img_stage1 = fu_firmware_get_image_by_id (firmware_tmp, "stage1", NULL); + if (img_stage1 != NULL) + fu_firmware_add_image (firmware, img_stage1); + img_stage2 = fu_firmware_get_image_by_id (firmware_tmp, "stage2", NULL); + if (img_stage2 != NULL) + fu_firmware_add_image (firmware, img_stage2); + img_ape = fu_firmware_get_image_by_id (firmware_tmp, "ape", NULL); + if (img_ape != NULL) + fu_firmware_add_image (firmware, img_ape); + + /* the src and dst dictionaries may be in different order */ + images = fu_firmware_get_images (firmware); + for (guint i = 0; i < images->len; i++) { + FuFirmwareImage *img = g_ptr_array_index (images, i); + if (FU_IS_BCM57XX_DICT_IMAGE (img)) { + fu_firmware_image_set_idx (img, 0x80 + dict_cnt); + dict_cnt++; + } + } + if (g_getenv ("FWUPD_BCM57XX_VERBOSE") != NULL) { + g_autofree gchar *str = fu_firmware_to_string (firmware); + g_debug ("proposed device firmware: %s", str); + } + + /* success */ + return g_steal_pointer (&firmware); +} + +static gboolean +fu_bcm57xx_device_write_firmware (FuDevice *device, + FuFirmware *firmware, + FwupdInstallFlags flags, + GError **error) +{ + FuBcm57xxDevice *self = FU_BCM57XX_DEVICE (device); + g_autoptr(GBytes) blob = NULL; + g_autoptr(GBytes) blob_verify = NULL; + g_autoptr(GPtrArray) chunks = NULL; + + /* build the images into one linear blob of the correct size */ + fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); + blob = fu_firmware_write (firmware, error); + if (blob == NULL) + return FALSE; + + /* hit hardware */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + chunks = fu_chunk_array_new_from_bytes (blob, 0x0, 0x0, FU_BCM57XX_BLOCK_SZ); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + if (!fu_bcm57xx_device_nvram_write (self, fu_chunk_get_address (chk), + fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk), + error)) + return FALSE; + fu_device_set_progress_full (device, i, chunks->len - 1); + } + + /* verify */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_VERIFY); + blob_verify = fu_bcm57xx_device_dump_firmware (device, error); + if (blob_verify == NULL) + return FALSE; + if (!fu_common_bytes_compare (blob, blob_verify, error)) + return FALSE; + + /* reset APE */ + return fu_device_activate (device, error); +} + +static gboolean +fu_bcm57xx_device_setup (FuDevice *device, GError **error) +{ + FuBcm57xxDevice *self = FU_BCM57XX_DEVICE (device); + guint32 fwversion = 0; + + /* device is in recovery mode */ + if (self->ethtool_iface == NULL) { + g_autoptr(FuDeviceLocker) locker = NULL; + g_debug ("device in recovery mode, use alternate device"); + locker = fu_device_locker_new (FU_DEVICE (self->recovery), error); + if (locker == NULL) + return FALSE; + return fu_device_setup (FU_DEVICE (self->recovery), error); + } + + /* check the EEPROM size */ + if (!fu_bcm57xx_device_nvram_check (self, error)) + return FALSE; + + /* get NVRAM version */ + if (!fu_bcm57xx_device_nvram_read (self, BCM_NVRAM_STAGE1_BASE + BCM_NVRAM_STAGE1_VERSION, + (guint8 *) &fwversion, sizeof(guint32), error)) + return FALSE; + if (fwversion != 0x0) { + g_autofree gchar *fwversion_str = NULL; + + /* this is only set on the OSS firmware */ + fwversion_str = fu_common_version_from_uint32 (GUINT32_FROM_BE(fwversion), + FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_set_version_format (device, FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_set_version (device, fwversion_str); + fu_device_set_version_raw (device, fwversion); + fu_device_set_branch (device, BCM_FW_BRANCH_OSS_FIRMWARE); + } else { + guint8 bufver[16] = { 0x0 }; + guint32 veraddr = 0; + g_autoptr(Bcm57xxVeritem) veritem = NULL; + + /* fall back to the string, e.g. '5719-v1.43' */ + if (!fu_bcm57xx_device_nvram_read (self, + BCM_NVRAM_STAGE1_BASE + BCM_NVRAM_STAGE1_VERADDR, + (guint8 *) &veraddr, sizeof(guint32), error)) + return FALSE; + veraddr = GUINT32_FROM_BE(veraddr); + if (veraddr > BCM_PHYS_ADDR_DEFAULT) + veraddr -= BCM_PHYS_ADDR_DEFAULT; + if (!fu_bcm57xx_device_nvram_read (self, + BCM_NVRAM_STAGE1_BASE + veraddr, + bufver, sizeof(bufver), error)) + return FALSE; + veritem = fu_bcm57xx_veritem_new (bufver, sizeof(bufver)); + if (veritem != NULL) { + fu_device_set_version_format (device, veritem->verfmt); + fu_device_set_version (device, veritem->version); + fu_device_set_branch (device, veritem->branch); + } + } + + /* success */ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NEEDS_REBOOT); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_BACKUP_BEFORE_INSTALL); + return TRUE; +} + +static gboolean +fu_bcm57xx_device_open (FuDevice *device, GError **error) +{ +#ifdef HAVE_SOCKET_H + FuBcm57xxDevice *self = FU_BCM57XX_DEVICE (device); + self->ethtool_fd = socket (AF_INET, SOCK_DGRAM, 0); + if (self->ethtool_fd < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "failed to open socket: %s", +#ifdef HAVE_ERRNO_H + strerror (errno)); +#else + "unspecified error"); +#endif + return FALSE; + } + return TRUE; +#else + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "socket() not supported as sys/socket.h not available"); + return FALSE; +#endif +} + +static gboolean +fu_bcm57xx_device_close (FuDevice *device, GError **error) +{ + FuBcm57xxDevice *self = FU_BCM57XX_DEVICE (device); + return g_close (self->ethtool_fd, error); +} + +static void +fu_bcm57xx_device_init (FuBcm57xxDevice *self) +{ + fu_device_add_protocol (FU_DEVICE (self), "com.broadcom.bcm57xx"); + fu_device_add_icon (FU_DEVICE (self), "network-wired"); + + /* other values are set from a quirk */ + fu_device_set_firmware_size (FU_DEVICE (self), BCM_FIRMWARE_SIZE); + + /* used for recovery in case of ethtool failure and for APE reset */ + self->recovery = fu_bcm57xx_recovery_device_new (); +} + +static void +fu_bcm57xx_device_finalize (GObject *object) +{ + FuBcm57xxDevice *self= FU_BCM57XX_DEVICE (object); + g_free (self->ethtool_iface); + G_OBJECT_CLASS (fu_bcm57xx_device_parent_class)->finalize (object); +} + +static void +fu_bcm57xx_device_class_init (FuBcm57xxDeviceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + object_class->finalize = fu_bcm57xx_device_finalize; + klass_device->prepare_firmware = fu_bcm57xx_device_prepare_firmware; + klass_device->setup = fu_bcm57xx_device_setup; + klass_device->reload = fu_bcm57xx_device_setup; + klass_device->open = fu_bcm57xx_device_open; + klass_device->close = fu_bcm57xx_device_close; + klass_device->activate = fu_bcm57xx_device_activate; + klass_device->write_firmware = fu_bcm57xx_device_write_firmware; + klass_device->read_firmware = fu_bcm57xx_device_read_firmware; + klass_device->dump_firmware = fu_bcm57xx_device_dump_firmware; + klass_device->probe = fu_bcm57xx_device_probe; + klass_device->to_string = fu_bcm57xx_device_to_string; +} diff -Nru fwupd-1.4.5/plugins/bcm57xx/fu-bcm57xx-device.h fwupd-1.5.8/plugins/bcm57xx/fu-bcm57xx-device.h --- fwupd-1.4.5/plugins/bcm57xx/fu-bcm57xx-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/bcm57xx/fu-bcm57xx-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,12 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +#define FU_TYPE_BCM57XX_DEVICE (fu_bcm57xx_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuBcm57xxDevice, fu_bcm57xx_device, FU, BCM57XX_DEVICE, FuUdevDevice) diff -Nru fwupd-1.4.5/plugins/bcm57xx/fu-bcm57xx-dict-image.c fwupd-1.5.8/plugins/bcm57xx/fu-bcm57xx-dict-image.c --- fwupd-1.4.5/plugins/bcm57xx/fu-bcm57xx-dict-image.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/bcm57xx/fu-bcm57xx-dict-image.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-common.h" + +#include "fu-bcm57xx-common.h" +#include "fu-bcm57xx-dict-image.h" + +struct _FuBcm57xxDictImage { + FuFirmwareImage parent_instance; + guint8 target; + guint8 kind; +}; + +G_DEFINE_TYPE (FuBcm57xxDictImage, fu_bcm57xx_dict_image, FU_TYPE_FIRMWARE_IMAGE) + +static void +fu_bcm57xx_dict_image_to_string (FuFirmwareImage *image, guint idt, GString *str) +{ + FuBcm57xxDictImage *self = FU_BCM57XX_DICT_IMAGE (image); + if (self->target != 0xff) + fu_common_string_append_kx (str, idt, "Target", self->target); + if (self->kind != 0xff) + fu_common_string_append_kx (str, idt, "Kind", self->kind); +} + +static gboolean +fu_bcm57xx_dict_image_parse (FuFirmwareImage *image, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(GBytes) fw_nocrc = NULL; + if ((flags & FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM) == 0) { + if (!fu_bcm57xx_verify_crc (fw, error)) + return FALSE; + } + fw_nocrc = fu_common_bytes_new_offset (fw, 0x0, + g_bytes_get_size (fw) - sizeof(guint32), + error); + if (fw_nocrc == NULL) + return FALSE; + fu_firmware_image_set_bytes (image, fw_nocrc); + return TRUE; +} + +static GBytes * +fu_bcm57xx_dict_image_write (FuFirmwareImage *image, GError **error) +{ + const guint8 *buf; + gsize bufsz = 0; + guint32 crc; + g_autoptr(GByteArray) blob = NULL; + g_autoptr(GBytes) fw_nocrc = NULL; + + /* get the CRC-less data */ + fw_nocrc = fu_firmware_image_get_bytes (image); + if (fw_nocrc == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "not supported"); + return NULL; + } + + /* add to a mutable buffer */ + buf = g_bytes_get_data (fw_nocrc, &bufsz); + blob = g_byte_array_sized_new (bufsz + sizeof(guint32)); + g_byte_array_append (blob, buf, bufsz); + + /* add CRC */ + crc = fu_bcm57xx_nvram_crc (buf, bufsz); + fu_byte_array_append_uint32 (blob, crc, G_LITTLE_ENDIAN); + return g_byte_array_free_to_bytes (g_steal_pointer (&blob)); +} + +static gboolean +fu_bcm57xx_dict_image_build (FuFirmwareImage *image, XbNode *n, GError **error) +{ + FuBcm57xxDictImage *self = FU_BCM57XX_DICT_IMAGE (image); + guint64 tmp; + + /* two simple properties */ + tmp = xb_node_query_text_as_uint (n, "kind", NULL); + if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT8) + fu_bcm57xx_dict_image_set_kind (self, tmp); + tmp = xb_node_query_text_as_uint (n, "target", NULL); + if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT8) + fu_bcm57xx_dict_image_set_target (self, tmp); + + /* success */ + return TRUE; +} + +static void +fu_bcm57xx_dict_image_ensure_id (FuBcm57xxDictImage *self) +{ + g_autofree gchar *id = NULL; + struct { + guint8 target; + guint8 kind; + const gchar *id; + } ids[] = { + { 0x00, 0x00, "pxe" }, + { 0x0D, 0x00, "ape" }, + { 0x09, 0x00, "iscsi1" }, + { 0x05, 0x00, "iscsi2" }, + { 0x0b, 0x00, "iscsi3" }, + { 0x00, 0x01, "cfg1000" }, + { 0x04, 0x01, "vpd2" }, + { 0xff, 0xff, NULL } + }; + if (self->target == 0xff || self->kind == 0xff) + return; + for (guint i = 0; ids[i].id != NULL; i++) { + if (self->target == ids[i].target && self->kind == ids[i].kind) { + g_debug ("using %s for %02x:%02x", + ids[i].id, self->target, self->kind); + fu_firmware_image_set_id (FU_FIRMWARE_IMAGE (self), ids[i].id); + return; + } + } + id = g_strdup_printf ("dict-%02x-%02x", self->target, self->kind); + g_warning ("falling back to %s, please report", id); + fu_firmware_image_set_id (FU_FIRMWARE_IMAGE (self), id); +} + +void +fu_bcm57xx_dict_image_set_target (FuBcm57xxDictImage *self, guint8 target) +{ + self->target = target; + fu_bcm57xx_dict_image_ensure_id (self); +} + +guint8 +fu_bcm57xx_dict_image_get_target (FuBcm57xxDictImage *self) +{ + return self->target; +} + +void +fu_bcm57xx_dict_image_set_kind (FuBcm57xxDictImage *self, guint8 kind) +{ + self->kind = kind; + fu_bcm57xx_dict_image_ensure_id (self); +} + +guint8 +fu_bcm57xx_dict_image_get_kind (FuBcm57xxDictImage *self) +{ + return self->kind; +} + +static void +fu_bcm57xx_dict_image_init (FuBcm57xxDictImage *self) +{ + self->target = 0xff; + self->kind = 0xff; +} + +static void +fu_bcm57xx_dict_image_class_init (FuBcm57xxDictImageClass *klass) +{ + FuFirmwareImageClass *klass_image = FU_FIRMWARE_IMAGE_CLASS (klass); + klass_image->parse = fu_bcm57xx_dict_image_parse; + klass_image->write = fu_bcm57xx_dict_image_write; + klass_image->build = fu_bcm57xx_dict_image_build; + klass_image->to_string = fu_bcm57xx_dict_image_to_string; +} + +FuFirmwareImage * +fu_bcm57xx_dict_image_new (void) +{ + return FU_FIRMWARE_IMAGE (g_object_new (FU_TYPE_BCM57XX_DICT_IMAGE, NULL)); +} diff -Nru fwupd-1.4.5/plugins/bcm57xx/fu-bcm57xx-dict-image.h fwupd-1.5.8/plugins/bcm57xx/fu-bcm57xx-dict-image.h --- fwupd-1.4.5/plugins/bcm57xx/fu-bcm57xx-dict-image.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/bcm57xx/fu-bcm57xx-dict-image.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-firmware-image.h" + +#define FU_TYPE_BCM57XX_DICT_IMAGE (fu_bcm57xx_dict_image_get_type ()) +G_DECLARE_FINAL_TYPE (FuBcm57xxDictImage, fu_bcm57xx_dict_image, FU, BCM57XX_DICT_IMAGE, FuFirmwareImage) + +FuFirmwareImage *fu_bcm57xx_dict_image_new (void); +void fu_bcm57xx_dict_image_set_kind (FuBcm57xxDictImage *self, + guint8 kind); +guint8 fu_bcm57xx_dict_image_get_kind (FuBcm57xxDictImage *self); +void fu_bcm57xx_dict_image_set_target (FuBcm57xxDictImage *self, + guint8 target); +guint8 fu_bcm57xx_dict_image_get_target (FuBcm57xxDictImage *self); diff -Nru fwupd-1.4.5/plugins/bcm57xx/fu-bcm57xx-firmware.c fwupd-1.5.8/plugins/bcm57xx/fu-bcm57xx-firmware.c --- fwupd-1.4.5/plugins/bcm57xx/fu-bcm57xx-firmware.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/bcm57xx/fu-bcm57xx-firmware.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,607 @@ +/* + * Copyright (C) 2018 Evan Lojewski + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-common.h" + +#include "fu-bcm57xx-common.h" +#include "fu-bcm57xx-firmware.h" +#include "fu-bcm57xx-dict-image.h" +#include "fu-bcm57xx-stage1-image.h" +#include "fu-bcm57xx-stage2-image.h" + +struct _FuBcm57xxFirmware { + FuFirmware parent_instance; + guint16 vendor; + guint16 model; + gboolean is_backup; + guint32 phys_addr; + gsize source_size; + guint8 source_padchar; +}; + +G_DEFINE_TYPE (FuBcm57xxFirmware, fu_bcm57xx_firmware, FU_TYPE_FIRMWARE) + +#define BCM_STAGE1_HEADER_MAGIC_BROADCOM 0x0E000E03 +#define BCM_STAGE1_HEADER_MAGIC_MEKLORT 0x3C1D0800 + +#define BCM_APE_HEADER_MAGIC 0x1A4D4342 + +#define BCM_CODE_DIRECTORY_ADDR_APE 0x07 + +static void +fu_bcm57xx_firmware_to_string (FuFirmware *firmware, guint idt, GString *str) +{ + FuBcm57xxFirmware *self = FU_BCM57XX_FIRMWARE (firmware); + fu_common_string_append_kx (str, idt, "Vendor", self->vendor); + fu_common_string_append_kx (str, idt, "Model", self->model); + fu_common_string_append_kb (str, idt, "IsBackup", self->is_backup); + fu_common_string_append_kx (str, idt, "PhysAddr", self->phys_addr); +} + +static gboolean +fu_bcm57xx_firmware_parse_header (FuBcm57xxFirmware *self, GBytes *fw, GError **error) +{ + gsize bufsz = 0x0; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + + /* verify magic and CRC */ + if (!fu_bcm57xx_verify_magic (fw, 0x0, error)) + return FALSE; + if (!fu_bcm57xx_verify_crc (fw, error)) + return FALSE; + + /* get address */ + return fu_common_read_uint32_safe (buf, bufsz, BCM_NVRAM_HEADER_PHYS_ADDR, + &self->phys_addr, G_BIG_ENDIAN, error); +} + +static FuFirmwareImage * +fu_bcm57xx_firmware_parse_info (FuBcm57xxFirmware *self, GBytes *fw, GError **error) +{ + gsize bufsz = 0x0; + guint32 mac_addr0 = 0; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + g_autoptr(FuFirmwareImage) img = fu_firmware_image_new (fw); + + /* if the MAC is set non-zero this is an actual backup rather than a container */ + if (!fu_common_read_uint32_safe (buf, bufsz, BCM_NVRAM_INFO_MAC_ADDR0, + &mac_addr0, G_BIG_ENDIAN, error)) + return NULL; + self->is_backup = mac_addr0 != 0x0 && mac_addr0 != 0xffffffff; + + /* read vendor + model */ + if (!fu_common_read_uint16_safe (buf, bufsz, BCM_NVRAM_INFO_VENDOR, + &self->vendor, G_BIG_ENDIAN, error)) + return NULL; + if (!fu_common_read_uint16_safe (buf, bufsz, BCM_NVRAM_INFO_DEVICE, + &self->model, G_BIG_ENDIAN, error)) + return NULL; + + /* success */ + fu_firmware_image_set_id (img, "info"); + return g_steal_pointer (&img); +} + +static FuFirmwareImage * +fu_bcm57xx_firmware_parse_stage1 (FuBcm57xxFirmware *self, + GBytes *fw, + guint32 *out_stage1_sz, + FwupdInstallFlags flags, + GError **error) +{ + gsize bufsz = 0x0; + guint32 stage1_wrds = 0; + guint32 stage1_sz; + guint32 stage1_off = 0; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + g_autoptr(FuFirmwareImage) img = fu_bcm57xx_stage1_image_new (); + g_autoptr(GBytes) blob = NULL; + + if (!fu_common_read_uint32_safe (buf, bufsz, + BCM_NVRAM_HEADER_BASE + BCM_NVRAM_HEADER_SIZE_WRDS, + &stage1_wrds, G_BIG_ENDIAN, error)) + return NULL; + if (!fu_common_read_uint32_safe (buf, bufsz, + BCM_NVRAM_HEADER_BASE + BCM_NVRAM_HEADER_OFFSET, + &stage1_off, G_BIG_ENDIAN, error)) + return NULL; + stage1_sz = (stage1_wrds * sizeof(guint32)); + if (stage1_off != BCM_NVRAM_STAGE1_BASE) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "stage1 offset invalid, got: 0x%x, expected 0x%x", + (guint) stage1_sz, (guint) BCM_NVRAM_STAGE1_BASE); + return NULL; + } + if (stage1_off + stage1_sz > bufsz) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "bigger than firmware, got: 0x%x @ 0x%x", + (guint) stage1_sz, (guint) stage1_off); + return NULL; + } + + /* verify CRC */ + blob = fu_common_bytes_new_offset (fw, stage1_off, stage1_sz, error); + if (blob == NULL) + return NULL; + if (!fu_firmware_image_parse (img, blob, flags, error)) + return NULL; + + /* needed for stage2 */ + if (out_stage1_sz != NULL) + *out_stage1_sz = stage1_sz; + + /* success */ + fu_firmware_image_set_id (img, "stage1"); + fu_firmware_image_set_offset (img, stage1_off); + return g_steal_pointer (&img); +} + +static FuFirmwareImage * +fu_bcm57xx_firmware_parse_stage2 (FuBcm57xxFirmware *self, + GBytes *fw, + guint32 stage1_sz, + FwupdInstallFlags flags, + GError **error) +{ + gsize bufsz = 0x0; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + guint32 stage2_off = 0; + guint32 stage2_sz = 0; + g_autoptr(FuFirmwareImage) img = fu_bcm57xx_stage2_image_new (); + g_autoptr(GBytes) blob = NULL; + + stage2_off = BCM_NVRAM_STAGE1_BASE + stage1_sz; + if (!fu_bcm57xx_verify_magic (fw, stage2_off, error)) + return NULL; + if (!fu_common_read_uint32_safe (buf, bufsz, stage2_off + sizeof(guint32), + &stage2_sz, G_BIG_ENDIAN, error)) + return NULL; + if (stage2_off + stage2_sz > bufsz) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "bigger than firmware, got: 0x%x @ 0x%x", + (guint) stage2_sz, (guint) stage2_off); + return NULL; + } + + /* verify CRC */ + blob = fu_common_bytes_new_offset (fw, stage2_off + 0x8, stage2_sz, error); + if (blob == NULL) + return NULL; + if (!fu_firmware_image_parse (img, blob, flags, error)) + return NULL; + + /* success */ + fu_firmware_image_set_id (img, "stage2"); + fu_firmware_image_set_offset (img, stage2_off); + return g_steal_pointer (&img); +} + +static gboolean +fu_bcm57xx_firmware_parse_dict (FuBcm57xxFirmware *self, GBytes *fw, guint idx, + FwupdInstallFlags flags, GError **error) +{ + gsize bufsz = 0x0; + guint32 dict_addr = 0x0; + guint32 dict_info = 0x0; + guint32 dict_off = 0x0; + guint32 dict_sz; + guint32 base = BCM_NVRAM_DIRECTORY_BASE + (idx * BCM_NVRAM_DIRECTORY_SZ); + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + g_autoptr(FuFirmwareImage) img = fu_bcm57xx_dict_image_new (); + g_autoptr(GBytes) blob = NULL; + + /* header */ + if (!fu_common_read_uint32_safe (buf, bufsz, + base + BCM_NVRAM_DIRECTORY_ADDR, + &dict_addr, G_BIG_ENDIAN, error)) + return FALSE; + if (!fu_common_read_uint32_safe (buf, bufsz, + base + BCM_NVRAM_DIRECTORY_SIZE_WRDS, + &dict_info, G_BIG_ENDIAN, error)) + return FALSE; + if (!fu_common_read_uint32_safe (buf, bufsz, + base + BCM_NVRAM_DIRECTORY_OFFSET, + &dict_off, G_BIG_ENDIAN, error)) + return FALSE; + + /* no dict stored */ + if (dict_addr == 0 && dict_info == 0 && dict_off == 0) + return TRUE; + + dict_sz = (dict_info & 0x00FFFFFF) * sizeof(guint32); /* implies that maximum size is 16 MB */ + fu_bcm57xx_dict_image_set_target (FU_BCM57XX_DICT_IMAGE (img), (dict_info & 0x0F000000) >> 24); + fu_bcm57xx_dict_image_set_kind (FU_BCM57XX_DICT_IMAGE (img), (dict_info & 0xF0000000) >> 28); + fu_firmware_image_set_addr (img, dict_addr); + fu_firmware_image_set_offset (img, dict_off); + fu_firmware_image_set_idx (img, 0x80 + idx); + + /* empty */ + if (dict_sz == 0) { + blob = g_bytes_new (NULL, 0); + fu_firmware_image_set_bytes (img, blob); + fu_firmware_add_image (FU_FIRMWARE (self), img); + return TRUE; + } + + /* check against image size */ + if (dict_off + dict_sz > bufsz) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "bigger than firmware, got: 0x%x @ 0x%x", + (guint) dict_sz, (guint) dict_off); + return FALSE; + } + blob = fu_common_bytes_new_offset (fw, dict_off, dict_sz, error); + if (blob == NULL) + return FALSE; + if (!fu_firmware_image_parse (img, blob, flags, error)) + return FALSE; + + /* success */ + fu_firmware_add_image (FU_FIRMWARE (self), img); + return TRUE; +} + +static gboolean +fu_bcm57xx_firmware_parse (FuFirmware *firmware, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error) +{ + FuBcm57xxFirmware *self = FU_BCM57XX_FIRMWARE (firmware); + gsize bufsz = 0x0; + guint32 magic = 0; + guint32 stage1_sz = 0; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + g_autoptr(FuFirmwareImage) img_info2 = NULL; + g_autoptr(FuFirmwareImage) img_info = NULL; + g_autoptr(FuFirmwareImage) img_stage1 = NULL; + g_autoptr(FuFirmwareImage) img_stage2 = NULL; + g_autoptr(FuFirmwareImage) img_vpd = NULL; + g_autoptr(GBytes) blob_header = NULL; + g_autoptr(GBytes) blob_info2 = NULL; + g_autoptr(GBytes) blob_info = NULL; + g_autoptr(GBytes) blob_vpd = NULL; + + /* try to autodetect the file type */ + if (!fu_common_read_uint32_safe (buf, bufsz, 0x0, &magic, G_BIG_ENDIAN, error)) + return FALSE; + + /* standalone APE */ + if (magic == BCM_APE_HEADER_MAGIC) { + g_autoptr(FuFirmwareImage) img = fu_bcm57xx_dict_image_new (); + fu_bcm57xx_dict_image_set_target (FU_BCM57XX_DICT_IMAGE (img), 0xD); + fu_bcm57xx_dict_image_set_kind (FU_BCM57XX_DICT_IMAGE (img), 0x0); + fu_firmware_image_set_bytes (img, fw); + fu_firmware_image_set_addr (img, BCM_CODE_DIRECTORY_ADDR_APE); + fu_firmware_image_set_id (img, "ape"); + fu_firmware_add_image (firmware, img); + return TRUE; + } + + /* standalone stage1 */ + if (magic == BCM_STAGE1_HEADER_MAGIC_BROADCOM || + magic == BCM_STAGE1_HEADER_MAGIC_MEKLORT) { + img_stage1 = fu_firmware_image_new (fw); + fu_firmware_image_set_id (img_stage1, "stage1"); + fu_firmware_add_image (firmware, img_stage1); + return TRUE; + } + + /* not full NVRAM image */ + if (magic != BCM_NVRAM_MAGIC) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "file not supported, got: 0x%08X", + magic); + return FALSE; + } + + /* save the size so we can export the padding for a perfect roundtrip */ + self->source_size = bufsz; + self->source_padchar = buf[bufsz - 1]; + + /* NVRAM header */ + blob_header = fu_common_bytes_new_offset (fw, + BCM_NVRAM_HEADER_BASE, + BCM_NVRAM_HEADER_SZ, + error); + if (blob_header == NULL) + return FALSE; + if (!fu_bcm57xx_firmware_parse_header (self, blob_header, error)) { + g_prefix_error (error, "failed to parse header: "); + return FALSE; + } + + /* info */ + blob_info = fu_common_bytes_new_offset (fw, + BCM_NVRAM_INFO_BASE, + BCM_NVRAM_INFO_SZ, + error); + if (blob_info == NULL) + return FALSE; + img_info = fu_bcm57xx_firmware_parse_info (self, blob_info, error); + if (img_info == NULL) { + g_prefix_error (error, "failed to parse info: "); + return FALSE; + } + fu_firmware_image_set_offset (img_info, BCM_NVRAM_INFO_BASE); + fu_firmware_add_image (firmware, img_info); + + /* VPD */ + blob_vpd = fu_common_bytes_new_offset (fw, + BCM_NVRAM_VPD_BASE, + BCM_NVRAM_VPD_SZ, + error); + if (blob_vpd == NULL) + return FALSE; + img_vpd = fu_firmware_image_new (blob_vpd); + fu_firmware_image_set_id (img_vpd, "vpd"); + fu_firmware_image_set_offset (img_vpd, BCM_NVRAM_VPD_BASE); + fu_firmware_add_image (firmware, img_vpd); + + /* info2 */ + blob_info2 = fu_common_bytes_new_offset (fw, + BCM_NVRAM_INFO2_BASE, + BCM_NVRAM_INFO2_SZ, + error); + if (blob_info2 == NULL) + return FALSE; + img_info2 = fu_firmware_image_new (blob_info2); + fu_firmware_image_set_id (img_info2, "info2"); + fu_firmware_image_set_offset (img_info2, BCM_NVRAM_INFO2_BASE); + fu_firmware_add_image (firmware, img_info2); + + /* stage1 */ + img_stage1 = fu_bcm57xx_firmware_parse_stage1 (self, fw, &stage1_sz, flags, error); + if (img_stage1 == NULL) { + g_prefix_error (error, "failed to parse stage1: "); + return FALSE; + } + fu_firmware_add_image (firmware, img_stage1); + + /* stage2 */ + img_stage2 = fu_bcm57xx_firmware_parse_stage2 (self, fw, stage1_sz, flags, error); + if (img_stage2 == NULL) { + g_prefix_error (error, "failed to parse stage2: "); + return FALSE; + } + fu_firmware_add_image (firmware, img_stage2); + + /* dictionaries, e.g. APE */ + for (guint i = 0; i < 8; i++) { + if (!fu_bcm57xx_firmware_parse_dict (self, fw, i, flags, error)) { + g_prefix_error (error, "failed to parse dict 0x%x: ", i); + return FALSE; + } + } + + /* success */ + return TRUE; +} + +static void +_g_byte_array_append_bytes (GByteArray *buf, GBytes *bytes) +{ + g_byte_array_append (buf, g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes)); +} + +static GBytes * +_g_bytes_new_sized (gsize sz) +{ + GByteArray *tmp = g_byte_array_sized_new (sz); + for (gsize i = 0; i < sz; i++) + fu_byte_array_append_uint8 (tmp, 0x0); + return g_byte_array_free_to_bytes (tmp); +} + +static gboolean +fu_bcm57xx_firmware_build (FuFirmware *firmware, XbNode *n, GError **error) +{ + FuBcm57xxFirmware *self = FU_BCM57XX_FIRMWARE (firmware); + guint64 tmp; + + /* two simple properties */ + tmp = xb_node_query_text_as_uint (n, "vendor", NULL); + if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT16) + self->vendor = tmp; + tmp = xb_node_query_text_as_uint (n, "model", NULL); + if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT16) + self->model = tmp; + + /* success */ + return TRUE; +} + +static GBytes * +fu_bcm57xx_firmware_write (FuFirmware *firmware, GError **error) +{ + gsize off = BCM_NVRAM_STAGE1_BASE; + FuBcm57xxFirmware *self = FU_BCM57XX_FIRMWARE (firmware); + g_autoptr(GByteArray) buf = g_byte_array_sized_new (self->source_size); + g_autoptr(FuFirmwareImage) img_info2 = NULL; + g_autoptr(FuFirmwareImage) img_info = NULL; + g_autoptr(FuFirmwareImage) img_stage1 = NULL; + g_autoptr(FuFirmwareImage) img_stage2 = NULL; + g_autoptr(FuFirmwareImage) img_vpd = NULL; + g_autoptr(GBytes) blob_info2 = NULL; + g_autoptr(GBytes) blob_info = NULL; + g_autoptr(GBytes) blob_stage1 = NULL; + g_autoptr(GBytes) blob_stage2 = NULL; + g_autoptr(GBytes) blob_vpd = NULL; + g_autoptr(GPtrArray) blob_dicts = NULL; + + /* write out the things we need to pre-compute */ + img_stage1 = fu_firmware_get_image_by_id (firmware, "stage1", error); + if (img_stage1 == NULL) + return NULL; + blob_stage1 = fu_firmware_image_write (img_stage1, error); + if (blob_stage1 == NULL) + return NULL; + off += g_bytes_get_size (blob_stage1); + img_stage2 = fu_firmware_get_image_by_id (firmware, "stage2", error); + if (img_stage2 == NULL) + return NULL; + blob_stage2 = fu_firmware_image_write (img_stage2, error); + if (blob_stage2 == NULL) + return NULL; + off += g_bytes_get_size (blob_stage2); + + /* add header */ + fu_byte_array_append_uint32 (buf, BCM_NVRAM_MAGIC, G_BIG_ENDIAN); + fu_byte_array_append_uint32 (buf, self->phys_addr, G_BIG_ENDIAN); + fu_byte_array_append_uint32 (buf, g_bytes_get_size (blob_stage1) / sizeof(guint32), G_BIG_ENDIAN); + fu_byte_array_append_uint32 (buf, BCM_NVRAM_STAGE1_BASE, G_BIG_ENDIAN); + fu_byte_array_append_uint32 (buf, fu_bcm57xx_nvram_crc (buf->data, buf->len), G_LITTLE_ENDIAN); + + /* add directory entries */ + blob_dicts = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref); + for (guint i = 0; i < 8; i++) { + g_autoptr(FuFirmwareImage) img = NULL; + g_autoptr(GBytes) blob = NULL; + + img = fu_firmware_get_image_by_idx (firmware, 0x80 + i, NULL); + if (img != NULL) { + blob = fu_firmware_image_write (img, error); + if (blob == NULL) + return NULL; + } + if (blob != NULL) { + fu_byte_array_append_uint32 (buf, fu_firmware_image_get_addr (img), G_BIG_ENDIAN); + fu_byte_array_append_uint32 (buf, + (g_bytes_get_size (blob) / sizeof(guint32)) | + (guint32) fu_bcm57xx_dict_image_get_target (FU_BCM57XX_DICT_IMAGE (img)) << 24 | + (guint32) fu_bcm57xx_dict_image_get_kind (FU_BCM57XX_DICT_IMAGE (img)) << 28, + G_BIG_ENDIAN); + if (g_bytes_get_size (blob) > 0) { + fu_byte_array_append_uint32 (buf, off, G_BIG_ENDIAN); + off += g_bytes_get_size (blob); + } else { + fu_byte_array_append_uint32 (buf, 0x0, G_BIG_ENDIAN); + } + } else { + blob = g_bytes_new (NULL, 0); + for (guint32 j = 0; j < sizeof(guint32) * 3; j++) + fu_byte_array_append_uint8 (buf, 0x0); + } + g_ptr_array_add (blob_dicts, g_steal_pointer (&blob)); + } + + /* add info */ + img_info = fu_firmware_get_image_by_id (firmware, "info", NULL); + if (img_info != NULL) { + blob_info = fu_firmware_image_write (img_info, error); + if (blob_info == NULL) + return NULL; + } else { + GByteArray *tmp = g_byte_array_sized_new (BCM_NVRAM_INFO_SZ); + for (gsize i = 0; i < BCM_NVRAM_INFO_SZ; i++) + fu_byte_array_append_uint8 (tmp, 0x0); + fu_common_write_uint16 (tmp->data + BCM_NVRAM_INFO_VENDOR, + self->vendor, G_BIG_ENDIAN); + fu_common_write_uint16 (tmp->data + BCM_NVRAM_INFO_DEVICE, + self->model, G_BIG_ENDIAN); + blob_info = g_byte_array_free_to_bytes (tmp); + } + _g_byte_array_append_bytes (buf, blob_info); + + /* add vpd */ + img_vpd = fu_firmware_get_image_by_id (firmware, "vpd", NULL); + if (img_vpd != NULL) { + blob_vpd = fu_firmware_image_write (img_vpd, error); + if (blob_vpd == NULL) + return NULL; + } else { + blob_vpd = _g_bytes_new_sized (BCM_NVRAM_VPD_SZ); + } + _g_byte_array_append_bytes (buf, blob_vpd); + + /* add info2 */ + img_info2 = fu_firmware_get_image_by_id (firmware, "info2", NULL); + if (img_info2 != NULL) { + blob_info2 = fu_firmware_image_write (img_info2, error); + if (blob_info2 == NULL) + return NULL; + } else { + blob_info2 = _g_bytes_new_sized (BCM_NVRAM_INFO2_SZ); + } + _g_byte_array_append_bytes (buf, blob_info2); + + /* add stage1+2 */ + _g_byte_array_append_bytes (buf, blob_stage1); + _g_byte_array_append_bytes (buf, blob_stage2); + + /* add dictionaries, e.g. APE */ + for (guint i = 0; i < blob_dicts->len; i++) { + GBytes *blob = g_ptr_array_index (blob_dicts, i); + _g_byte_array_append_bytes (buf, blob); + } + + /* pad until full */ + for (guint32 i = buf->len; i < self->source_size; i++) + fu_byte_array_append_uint8 (buf, self->source_padchar); + + /* add EOF */ + return g_byte_array_free_to_bytes (g_steal_pointer (&buf)); +} + +guint16 +fu_bcm57xx_firmware_get_vendor (FuBcm57xxFirmware *self) +{ + return self->vendor; +} + +guint16 +fu_bcm57xx_firmware_get_model (FuBcm57xxFirmware *self) +{ + return self->model; +} + +gboolean +fu_bcm57xx_firmware_is_backup (FuBcm57xxFirmware *self) +{ + return self->is_backup; +} + +static void +fu_bcm57xx_firmware_init (FuBcm57xxFirmware *self) +{ + self->phys_addr = BCM_PHYS_ADDR_DEFAULT; + self->source_size = BCM_FIRMWARE_SIZE; + self->source_padchar = 0xff; + fu_firmware_add_flag (FU_FIRMWARE (self), FU_FIRMWARE_FLAG_DEDUPE_ID); + fu_firmware_add_flag (FU_FIRMWARE (self), FU_FIRMWARE_FLAG_HAS_CHECKSUM); + fu_firmware_add_flag (FU_FIRMWARE (self), FU_FIRMWARE_FLAG_HAS_VID_PID); +} + +static void +fu_bcm57xx_firmware_class_init (FuBcm57xxFirmwareClass *klass) +{ + FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); + klass_firmware->parse = fu_bcm57xx_firmware_parse; + klass_firmware->to_string = fu_bcm57xx_firmware_to_string; + klass_firmware->write = fu_bcm57xx_firmware_write; + klass_firmware->build = fu_bcm57xx_firmware_build; +} + +FuFirmware * +fu_bcm57xx_firmware_new (void) +{ + return FU_FIRMWARE (g_object_new (FU_TYPE_BCM57XX_FIRMWARE, NULL)); +} diff -Nru fwupd-1.4.5/plugins/bcm57xx/fu-bcm57xx-firmware.h fwupd-1.5.8/plugins/bcm57xx/fu-bcm57xx-firmware.h --- fwupd-1.4.5/plugins/bcm57xx/fu-bcm57xx-firmware.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/bcm57xx/fu-bcm57xx-firmware.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-firmware.h" + +#define FU_TYPE_BCM57XX_FIRMWARE (fu_bcm57xx_firmware_get_type ()) +G_DECLARE_FINAL_TYPE (FuBcm57xxFirmware, fu_bcm57xx_firmware, FU, BCM57XX_FIRMWARE, FuFirmware) + +FuFirmware *fu_bcm57xx_firmware_new (void); +guint16 fu_bcm57xx_firmware_get_vendor (FuBcm57xxFirmware *self); +guint16 fu_bcm57xx_firmware_get_model (FuBcm57xxFirmware *self); +gboolean fu_bcm57xx_firmware_is_backup (FuBcm57xxFirmware *self); diff -Nru fwupd-1.4.5/plugins/bcm57xx/fu-bcm57xx-recovery-device.c fwupd-1.5.8/plugins/bcm57xx/fu-bcm57xx-recovery-device.c --- fwupd-1.4.5/plugins/bcm57xx/fu-bcm57xx-recovery-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/bcm57xx/fu-bcm57xx-recovery-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,770 @@ +/* + * Copyright (C) 2018 Evan Lojewski + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: GPL-2+ + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_MMAN_H +#include +#endif + +#ifdef HAVE_VALGRIND +#include +#endif /* HAVE_VALGRIND */ + +#include "fu-common.h" + +#include "fu-bcm57xx-common.h" +#include "fu-bcm57xx-recovery-device.h" +#include "fu-bcm57xx-firmware.h" + +/* offsets into BAR[0] */ +#define REG_DEVICE_PCI_VENDOR_DEVICE_ID 0x6434 +#define REG_NVM_SOFTWARE_ARBITRATION 0x7020 +#define REG_NVM_ACCESS 0x7024 +#define REG_NVM_COMMAND 0x7000 +#define REG_NVM_ADDR 0x700c +#define REG_NVM_READ 0x7010 +#define REG_NVM_WRITE 0x7008 + +/* offsets into BAR[2] */ +#define REG_APE_MODE 0x0 + +typedef struct { + guint8 *buf; + gsize bufsz; +} FuBcm57xxMmap; + +#define FU_BCM57XX_BAR_DEVICE 0 +#define FU_BCM57XX_BAR_APE 1 +#define FU_BCM57XX_BAR_MAX 3 + +struct _FuBcm57xxRecoveryDevice { + FuUdevDevice parent_instance; + FuBcm57xxMmap bar[FU_BCM57XX_BAR_MAX]; +}; + +typedef union { + guint32 r32; + struct { + guint32 reserved_0_0 : 1; + guint32 Reset : 1; + guint32 reserved_2_2 : 1; + guint32 Done : 1; + guint32 Doit : 1; + guint32 Wr : 1; + guint32 Erase : 1; + guint32 First : 1; + guint32 Last : 1; + guint32 reserved_15_9 : 7; + guint32 WriteEnableCommand : 1; + guint32 WriteDisableCommand : 1; + guint32 reserved_31_18 : 14; + } __attribute__((packed)) bits; +} BcmRegNVMCommand; + +typedef union { + guint32 r32; + struct { + guint32 ReqSet0 : 1; + guint32 ReqSet1 : 1; + guint32 ReqSet2 : 1; + guint32 ReqSet3 : 1; + guint32 ReqClr0 : 1; + guint32 ReqClr1 : 1; + guint32 ReqClr2 : 1; + guint32 ReqClr3 : 1; + guint32 ArbWon0 : 1; + guint32 ArbWon1 : 1; + guint32 ArbWon2 : 1; + guint32 ArbWon3 : 1; + guint32 Req0 : 1; + guint32 Req1 : 1; + guint32 Req2 : 1; + guint32 Req3 : 1; + guint32 reserved_31_16 : 16; + } __attribute__((packed)) bits; +} BcmRegNVMSoftwareArbitration; + +typedef union { + guint32 r32; + struct { + guint32 Enable : 1; + guint32 WriteEnable : 1; + guint32 reserved_31_2 : 30; + } __attribute__((packed)) bits; +} BcmRegNVMAccess; + +typedef union { + guint32 r32; + struct { + guint32 Reset : 1; + guint32 Halt : 1; + guint32 FastBoot : 1; + guint32 HostDiag : 1; + guint32 reserved_4_4 : 1; + guint32 Event1 : 1; + guint32 Event2 : 1; + guint32 GRCint : 1; + guint32 reserved_8_8 : 1; + guint32 SwapATBdword : 1; + guint32 reserved_10_10 : 1; + guint32 SwapARBdword : 1; + guint32 reserved_13_12 : 2; + guint32 Channel0Enable : 1; + guint32 Channel2Enable : 1; + guint32 reserved_17_16 : 2; + guint32 MemoryECC : 1; + guint32 ICodePIPRdDisable : 1; + guint32 reserved_29_20 : 10; + guint32 Channel1Enable : 1; + guint32 Channel3Enable : 1; + } __attribute__((packed)) bits; +} BcmRegAPEMode; + +G_DEFINE_TYPE (FuBcm57xxRecoveryDevice, fu_bcm57xx_recovery_device, FU_TYPE_UDEV_DEVICE) + +#ifdef __ppc64__ +#define BARRIER() __asm__ volatile ("sync 0\neieio\n" : : : "memory") +#else +#define BARRIER() __asm__ volatile ("" : : : "memory"); +#endif + +static gboolean +fu_bcm57xx_recovery_device_bar_read (FuBcm57xxRecoveryDevice *self, + guint bar, gsize offset, guint32 *val, + GError **error) +{ + /* this should never happen */ + if (self->bar[bar].buf == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "BAR[%u] is not mapped!", bar); + return FALSE; + } + + BARRIER(); + return fu_memcpy_safe ((guint8 *) val, sizeof(*val), 0x0, /* dst */ + self->bar[bar].buf, self->bar[bar].bufsz, offset, + sizeof(*val), error); +} + +static gboolean +fu_bcm57xx_recovery_device_bar_write (FuBcm57xxRecoveryDevice *self, + guint bar, gsize offset, guint32 val, + GError **error) +{ + /* this should never happen */ + if (self->bar[bar].buf == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "BAR[%u] is not mapped!", bar); + return FALSE; + } + + BARRIER(); + if (!fu_memcpy_safe (self->bar[bar].buf, self->bar[bar].bufsz, offset, /* dst */ + (const guint8 *) &val, sizeof(val), 0x0, /* src */ + sizeof(val), error)) + return FALSE; + BARRIER(); + return TRUE; +} + +static gboolean +fu_bcm57xx_recovery_device_nvram_disable (FuBcm57xxRecoveryDevice *self, + GError **error) +{ + BcmRegNVMAccess tmp; + if (!fu_bcm57xx_recovery_device_bar_read (self, FU_BCM57XX_BAR_DEVICE, + REG_NVM_ACCESS, &tmp.r32, error)) + return FALSE; + tmp.bits.Enable = FALSE; + tmp.bits.WriteEnable = FALSE; + return fu_bcm57xx_recovery_device_bar_write (self, FU_BCM57XX_BAR_DEVICE, + REG_NVM_ACCESS, tmp.r32, error); +} + +static gboolean +fu_bcm57xx_recovery_device_nvram_enable (FuBcm57xxRecoveryDevice *self, + GError **error) +{ + BcmRegNVMAccess tmp; + if (!fu_bcm57xx_recovery_device_bar_read (self, FU_BCM57XX_BAR_DEVICE, + REG_NVM_ACCESS, &tmp.r32, error)) + return FALSE; + tmp.bits.Enable = TRUE; + tmp.bits.WriteEnable = FALSE; + return fu_bcm57xx_recovery_device_bar_write (self, FU_BCM57XX_BAR_DEVICE, + REG_NVM_ACCESS, tmp.r32, error); +} + +static gboolean +fu_bcm57xx_recovery_device_nvram_enable_write (FuBcm57xxRecoveryDevice *self, + GError **error) +{ + BcmRegNVMAccess tmp; + if (!fu_bcm57xx_recovery_device_bar_read (self, FU_BCM57XX_BAR_DEVICE, + REG_NVM_ACCESS, &tmp.r32, error)) + return FALSE; + tmp.bits.Enable = TRUE; + tmp.bits.WriteEnable = TRUE; + return fu_bcm57xx_recovery_device_bar_write (self, FU_BCM57XX_BAR_DEVICE, + REG_NVM_ACCESS, tmp.r32, error); +} + +static gboolean +fu_bcm57xx_recovery_device_nvram_acquire_lock (FuBcm57xxRecoveryDevice *self, + GError **error) +{ + BcmRegNVMSoftwareArbitration tmp = { 0 }; + g_autoptr(GTimer) timer = g_timer_new (); + tmp.bits.ReqSet1 = 1; + if (!fu_bcm57xx_recovery_device_bar_write (self, FU_BCM57XX_BAR_DEVICE, + REG_NVM_SOFTWARE_ARBITRATION, + tmp.r32, error)) + return FALSE; + do { + if (!fu_bcm57xx_recovery_device_bar_read (self, + FU_BCM57XX_BAR_DEVICE, + REG_NVM_SOFTWARE_ARBITRATION, + &tmp.r32, error)) + return FALSE; + if (tmp.bits.ArbWon1) + return TRUE; + if (g_timer_elapsed (timer, NULL) > 0.2) + break; + } while (TRUE); + + /* timed out */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_TIMED_OUT, + "timed out trying to acquire lock #1"); + return FALSE; +} + +static gboolean +fu_bcm57xx_recovery_device_nvram_release_lock (FuBcm57xxRecoveryDevice *self, + GError **error) +{ + BcmRegNVMSoftwareArbitration tmp = { 0 }; + tmp.r32 = 0; + tmp.bits.ReqClr1 = 1; + return fu_bcm57xx_recovery_device_bar_write (self, FU_BCM57XX_BAR_DEVICE, + REG_NVM_SOFTWARE_ARBITRATION, tmp.r32, + error); +} + +static gboolean +fu_bcm57xx_recovery_device_nvram_wait_done (FuBcm57xxRecoveryDevice *self, GError **error) +{ + BcmRegNVMCommand tmp = { 0 }; + g_autoptr(GTimer) timer = g_timer_new (); + do { + if (!fu_bcm57xx_recovery_device_bar_read (self, + FU_BCM57XX_BAR_DEVICE, + REG_NVM_COMMAND, &tmp.r32, + error)) + return FALSE; + if (tmp.bits.Done) + return TRUE; + if (g_timer_elapsed (timer, NULL) > 0.2) + break; + } while (TRUE); + + /* timed out */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_TIMED_OUT, + "timed out"); + return FALSE; +} + +static gboolean +fu_bcm57xx_recovery_device_nvram_clear_done (FuBcm57xxRecoveryDevice *self, GError **error) +{ + BcmRegNVMCommand tmp = { 0 }; + tmp.bits.Done = 1; + return fu_bcm57xx_recovery_device_bar_write (self, FU_BCM57XX_BAR_DEVICE, + REG_NVM_COMMAND, tmp.r32, error); +} + +static gboolean +fu_bcm57xx_recovery_device_nvram_read (FuBcm57xxRecoveryDevice *self, + guint32 address, guint32 *buf, gsize bufsz, + GError **error) +{ + for (guint i = 0; i < bufsz; i++) { + BcmRegNVMCommand tmp = { 0 }; + guint32 val32 = 0; + if (!fu_bcm57xx_recovery_device_nvram_clear_done (self, error)) + return FALSE; + if (!fu_bcm57xx_recovery_device_bar_write (self, FU_BCM57XX_BAR_DEVICE, + REG_NVM_ADDR, address, error)) + return FALSE; + tmp.bits.Doit = 1; + tmp.bits.First = i == 0; + tmp.bits.Last = i == bufsz - 1; + + if (!fu_bcm57xx_recovery_device_bar_write (self, FU_BCM57XX_BAR_DEVICE, + REG_NVM_COMMAND, tmp.r32, error)) + return FALSE; + if (!fu_bcm57xx_recovery_device_nvram_wait_done (self, error)) { + g_prefix_error (error, "failed to read @0x%x: ", address); + return FALSE; + } + if (!fu_bcm57xx_recovery_device_bar_read (self, FU_BCM57XX_BAR_DEVICE, + REG_NVM_READ, &val32, error)) + return FALSE; + buf[i] = GUINT32_FROM_BE(val32); + address += sizeof(guint32); + fu_device_set_progress_full (FU_DEVICE (self), i, bufsz); + } + + /* success */ + return TRUE; +} + +static gboolean +fu_bcm57xx_recovery_device_nvram_write (FuBcm57xxRecoveryDevice *self, + guint32 address, const guint32 *buf, gsize bufsz_dwrds, + GError **error) +{ + const guint32 page_size_dwrds = 64; + + /* can only write in pages of 64 dwords */ + if (bufsz_dwrds % page_size_dwrds != 0 || + (address * sizeof(guint32)) % page_size_dwrds != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "can only write aligned with page size 0x%x", + page_size_dwrds); + return FALSE; + } + + for (guint i = 0; i < bufsz_dwrds; i++) { + BcmRegNVMCommand tmp = { 0 }; + if (!fu_bcm57xx_recovery_device_nvram_clear_done (self, error)) + return FALSE; + if (!fu_bcm57xx_recovery_device_bar_write (self, FU_BCM57XX_BAR_DEVICE, + REG_NVM_WRITE, GUINT32_TO_BE(buf[i]), error)) + return FALSE; + if (!fu_bcm57xx_recovery_device_bar_write (self, FU_BCM57XX_BAR_DEVICE, + REG_NVM_ADDR, address, error)) + return FALSE; + tmp.bits.Wr = TRUE; + tmp.bits.Doit = TRUE; + tmp.bits.First = i % page_size_dwrds == 0; + tmp.bits.Last = (i + 1) % page_size_dwrds == 0; + if (!fu_bcm57xx_recovery_device_bar_write (self, FU_BCM57XX_BAR_DEVICE, + REG_NVM_COMMAND, tmp.r32, error)) + return FALSE; + if (!fu_bcm57xx_recovery_device_nvram_wait_done (self, error)) { + g_prefix_error (error, "failed to write @0x%x: ", address); + return FALSE; + } + address += sizeof(guint32); + fu_device_set_progress_full (FU_DEVICE (self), i, bufsz_dwrds); + } + + /* success */ + return TRUE; +} + +static gboolean +fu_bcm57xx_recovery_device_detach (FuDevice *device, GError **error) +{ + /* unbind tg3 */ + return fu_device_unbind_driver (device, error); +} + +static gboolean +fu_bcm57xx_recovery_device_attach (FuDevice *device, GError **error) +{ + g_autoptr(GError) error_local = NULL; + + /* bind tg3, which might fail if the module is not compiled */ + if (!fu_device_bind_driver (device, "pci", "tg3", &error_local)) { + if (g_error_matches (error_local, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED)) { + g_warning ("failed to bind tg3: %s", error_local->message); + } else { + g_propagate_prefixed_error (error, + g_steal_pointer (&error_local), + "failed to bind tg3: "); + return FALSE; + } + } + + /* success */ + return TRUE; +} + +static gboolean +fu_bcm57xx_recovery_device_activate (FuDevice *device, GError **error) +{ + BcmRegAPEMode mode = { 0 }; + FuBcm57xxRecoveryDevice *self = FU_BCM57XX_RECOVERY_DEVICE (device); + + /* halt */ + mode.bits.Halt = 1; + mode.bits.FastBoot = 0; + if (!fu_bcm57xx_recovery_device_bar_write (self, FU_BCM57XX_BAR_APE, + REG_APE_MODE, mode.r32, error)) + return FALSE; + + /* boot */ + mode.bits.Halt = 0; + mode.bits.FastBoot = 0; + mode.bits.Reset = 1; + return fu_bcm57xx_recovery_device_bar_write (self, FU_BCM57XX_BAR_APE, + REG_APE_MODE, mode.r32, error); +} + +static GBytes * +fu_bcm57xx_recovery_device_dump_firmware (FuDevice *device, GError **error) +{ + FuBcm57xxRecoveryDevice *self = FU_BCM57XX_RECOVERY_DEVICE (device); + gsize bufsz_dwrds = fu_device_get_firmware_size_max (FU_DEVICE (self)) / sizeof(guint32); + g_autofree guint32 *buf_dwrds = g_new0 (guint32, bufsz_dwrds); + g_autoptr(FuDeviceLocker) locker = NULL; + g_autoptr(FuDeviceLocker) locker2 = NULL; + + /* read from hardware */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_READ); + locker = fu_device_locker_new_full (self, + (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_acquire_lock, + (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_release_lock, + error); + if (locker == NULL) + return NULL; + locker2 = fu_device_locker_new_full (self, + (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_enable, + (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_disable, + error); + if (locker2 == NULL) + return NULL; + if (!fu_bcm57xx_recovery_device_nvram_read (self, 0x0, buf_dwrds, bufsz_dwrds, error)) + return NULL; + if (!fu_device_locker_close (locker2, error)) + return NULL; + return g_bytes_new (buf_dwrds, bufsz_dwrds * sizeof(guint32)); +} + +static FuFirmware * +fu_bcm57xx_recovery_device_prepare_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuFirmware) firmware_bin = fu_firmware_new (); + g_autoptr(FuFirmware) firmware_tmp = fu_bcm57xx_firmware_new (); + + /* check is a NVRAM backup */ + if (!fu_firmware_parse (firmware_tmp, fw, flags, error)) { + g_prefix_error (error, "failed to parse new firmware: "); + return NULL; + } + if (!fu_bcm57xx_firmware_is_backup (FU_BCM57XX_FIRMWARE (firmware_tmp))) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "can only recover with backup firmware"); + return NULL; + } + if (!fu_firmware_parse (firmware_bin, fw, flags, error)) + return NULL; + return g_steal_pointer (&firmware_bin); +} + +static gboolean +fu_bcm57xx_recovery_device_write_firmware (FuDevice *device, + FuFirmware *firmware, + FwupdInstallFlags flags, + GError **error) +{ + FuBcm57xxRecoveryDevice *self= FU_BCM57XX_RECOVERY_DEVICE (device); + const guint8 *buf; + gsize bufsz = 0; + gsize bufsz_dwrds; + g_autofree guint32 *buf_dwrds = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; + g_autoptr(FuDeviceLocker) locker2 = NULL; + g_autoptr(GBytes) blob = NULL; + + /* build the images into one linear blob of the correct size */ + fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); + blob = fu_firmware_write (firmware, error); + if (blob == NULL) + return FALSE; + + /* align into uint32_t buffer */ + buf = g_bytes_get_data (blob, &bufsz); + bufsz_dwrds = bufsz / sizeof(guint32); + buf_dwrds = g_new0 (guint32, bufsz_dwrds); + if (!fu_memcpy_safe ((guint8 *) buf_dwrds, bufsz_dwrds * sizeof(guint32), 0x0, /* dst */ + buf, bufsz, 0x0, /* src */ + bufsz, error)) + return FALSE; + + /* hit hardware */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + locker = fu_device_locker_new_full (self, + (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_acquire_lock, + (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_release_lock, + error); + if (locker == NULL) + return FALSE; + locker2 = fu_device_locker_new_full (self, + (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_enable_write, + (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_disable, + error); + if (locker2 == NULL) + return FALSE; + if (!fu_bcm57xx_recovery_device_nvram_write (self, 0x0, buf_dwrds, bufsz_dwrds, error)) + return FALSE; + if (!fu_device_locker_close (locker2, error)) + return FALSE; + if (!fu_device_locker_close (locker, error)) + return FALSE; + + /* reset APE */ + return fu_device_activate (device, error); +} + +static gboolean +fu_bcm57xx_recovery_device_setup (FuDevice *device, GError **error) +{ + FuBcm57xxRecoveryDevice *self = FU_BCM57XX_RECOVERY_DEVICE (device); + guint32 fwversion = 0; + g_autoptr(FuDeviceLocker) locker = NULL; + g_autoptr(FuDeviceLocker) locker2 = NULL; + + locker = fu_device_locker_new_full (self, + (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_acquire_lock, + (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_release_lock, + error); + if (locker == NULL) + return FALSE; + locker2 = fu_device_locker_new_full (self, + (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_enable, + (FuDeviceLockerFunc) fu_bcm57xx_recovery_device_nvram_disable, + error); + if (locker2 == NULL) + return FALSE; + + /* get NVRAM version */ + if (!fu_bcm57xx_recovery_device_nvram_read (self, BCM_NVRAM_STAGE1_BASE + BCM_NVRAM_STAGE1_VERSION, + &fwversion, 1, error)) + return FALSE; + if (fwversion != 0x0) { + g_autofree gchar *fwversion_str = NULL; + + /* this is only set on the OSS firmware */ + fwversion_str = fu_common_version_from_uint32 (GUINT32_FROM_BE(fwversion), + FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_set_version_format (device, FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_set_version (device, fwversion_str); + fu_device_set_version_raw (device, fwversion); + fu_device_set_branch (device, BCM_FW_BRANCH_OSS_FIRMWARE); + } else { + guint32 bufver[4] = { 0x0 }; + guint32 veraddr = 0; + g_autoptr(Bcm57xxVeritem) veritem = NULL; + + /* fall back to the string, e.g. '5719-v1.43' */ + if (!fu_bcm57xx_recovery_device_nvram_read (self, + BCM_NVRAM_STAGE1_BASE + BCM_NVRAM_STAGE1_VERADDR, + &veraddr, 1, error)) + return FALSE; + veraddr = GUINT32_FROM_BE(veraddr); + if (veraddr > BCM_PHYS_ADDR_DEFAULT) + veraddr -= BCM_PHYS_ADDR_DEFAULT; + if (!fu_bcm57xx_recovery_device_nvram_read (self, + BCM_NVRAM_STAGE1_BASE + veraddr, + bufver, 4, error)) + return FALSE; + veritem = fu_bcm57xx_veritem_new ((guint8 *) bufver, sizeof(bufver)); + if (veritem != NULL) { + fu_device_set_version (device, veritem->version); + fu_device_set_branch (device, veritem->branch); + fu_device_set_version_format (device, veritem->verfmt); + } + } + + return TRUE; +} + +static gboolean +fu_bcm57xx_recovery_device_open (FuDevice *device, GError **error) +{ +#ifdef HAVE_MMAN_H + FuBcm57xxRecoveryDevice *self = FU_BCM57XX_RECOVERY_DEVICE (device); + FuUdevDevice *udev_device = FU_UDEV_DEVICE (device); + const gchar *sysfs_path = fu_udev_device_get_sysfs_path (udev_device); +#endif + +#ifdef RUNNING_ON_VALGRIND + /* this can't work */ + if (RUNNING_ON_VALGRIND) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "cannot mmap'ing BARs when using valgrind"); + return FALSE; + } +#endif + +#ifdef HAVE_MMAN_H + /* map BARs */ + for (guint i = 0; i < FU_BCM57XX_BAR_MAX; i++) { + int memfd; + struct stat st; + g_autofree gchar *fn = NULL; + g_autofree gchar *resfn = NULL; + + /* open 64 bit resource */ + resfn = g_strdup_printf ("resource%u", i * 2); + fn = g_build_filename (sysfs_path, resfn, NULL); + memfd = open (fn, O_RDWR | O_SYNC); + if (memfd < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "error opening %s", fn); + return FALSE; + } + if (fstat (memfd, &st) < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "could not stat %s", fn); + close (memfd); + return FALSE; + } + + /* mmap */ + if (g_getenv ("FWUPD_BCM57XX_VERBOSE") != NULL) + g_debug ("mapping BAR[%u] %s for 0x%x bytes", i, fn, (guint) st.st_size); + self->bar[i].buf = (guint8 *) mmap (0, st.st_size, + PROT_READ | PROT_WRITE, + MAP_SHARED, memfd, 0); + self->bar[i].bufsz = st.st_size; + close (memfd); + if (self->bar[i].buf == MAP_FAILED) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "could not mmap %s: %s", + fn, strerror(errno)); + return FALSE; + } + } + + /* success */ + return TRUE; +#else + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "mmap() not supported as sys/mman.h not available"); + return FALSE; +#endif +} + +static gboolean +fu_bcm57xx_recovery_device_close (FuDevice *device, GError **error) +{ +#ifdef HAVE_MMAN_H + FuBcm57xxRecoveryDevice *self = FU_BCM57XX_RECOVERY_DEVICE (device); + + /* unmap BARs */ + for (guint i = 0; i < FU_BCM57XX_BAR_MAX; i++) { + if (self->bar[i].buf == NULL) + continue; + if (g_getenv ("FWUPD_BCM57XX_VERBOSE") != NULL) + g_debug ("unmapping BAR[%u]", i); + munmap (self->bar[i].buf, self->bar[i].bufsz); + self->bar[i].buf = NULL; + self->bar[i].bufsz = 0; + } + + /* success */ + return TRUE; +#else + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "munmap() not supported as sys/mman.h not available"); + return FALSE; +#endif +} + +static void +fu_bcm57xx_recovery_device_init (FuBcm57xxRecoveryDevice *self) +{ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NEEDS_REBOOT); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_BACKUP_BEFORE_INSTALL); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IGNORE_VALIDATION); + fu_device_add_protocol (FU_DEVICE (self), "com.broadcom.bcm57xx"); + fu_device_add_icon (FU_DEVICE (self), "network-wired"); + fu_device_set_logical_id (FU_DEVICE (self), "recovery"); + + /* other values are set from a quirk */ + fu_device_set_firmware_size (FU_DEVICE (self), BCM_FIRMWARE_SIZE); + + /* no BARs mapped */ + for (guint i = 0; i < FU_BCM57XX_BAR_MAX; i++) { + self->bar[i].buf = NULL; + self->bar[i].bufsz = 0; + } +} + +static gboolean +fu_bcm57xx_recovery_device_probe (FuDevice *device, GError **error) +{ + /* FuUdevDevice->probe */ + if (!FU_DEVICE_CLASS (fu_bcm57xx_recovery_device_parent_class)->probe (device, error)) + return FALSE; + return fu_udev_device_set_physical_id (FU_UDEV_DEVICE (device), "pci", error); +} + +static void +fu_bcm57xx_recovery_device_class_init (FuBcm57xxRecoveryDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + klass_device->activate = fu_bcm57xx_recovery_device_activate; + klass_device->prepare_firmware = fu_bcm57xx_recovery_device_prepare_firmware; + klass_device->setup = fu_bcm57xx_recovery_device_setup; + klass_device->reload = fu_bcm57xx_recovery_device_setup; + klass_device->open = fu_bcm57xx_recovery_device_open; + klass_device->close = fu_bcm57xx_recovery_device_close; + klass_device->write_firmware = fu_bcm57xx_recovery_device_write_firmware; + klass_device->dump_firmware = fu_bcm57xx_recovery_device_dump_firmware; + klass_device->attach = fu_bcm57xx_recovery_device_attach; + klass_device->detach = fu_bcm57xx_recovery_device_detach; + klass_device->probe = fu_bcm57xx_recovery_device_probe; +} + +FuBcm57xxRecoveryDevice * +fu_bcm57xx_recovery_device_new (void) +{ + FuUdevDevice *self = g_object_new (FU_TYPE_BCM57XX_RECOVERY_DEVICE, NULL); + return FU_BCM57XX_RECOVERY_DEVICE (self); +} diff -Nru fwupd-1.4.5/plugins/bcm57xx/fu-bcm57xx-recovery-device.h fwupd-1.5.8/plugins/bcm57xx/fu-bcm57xx-recovery-device.h --- fwupd-1.4.5/plugins/bcm57xx/fu-bcm57xx-recovery-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/bcm57xx/fu-bcm57xx-recovery-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +#define FU_TYPE_BCM57XX_RECOVERY_DEVICE (fu_bcm57xx_recovery_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuBcm57xxRecoveryDevice, fu_bcm57xx_recovery_device, FU, BCM57XX_RECOVERY_DEVICE, FuUdevDevice) + +FuBcm57xxRecoveryDevice *fu_bcm57xx_recovery_device_new (void); diff -Nru fwupd-1.4.5/plugins/bcm57xx/fu-bcm57xx-stage1-image.c fwupd-1.5.8/plugins/bcm57xx/fu-bcm57xx-stage1-image.c --- fwupd-1.4.5/plugins/bcm57xx/fu-bcm57xx-stage1-image.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/bcm57xx/fu-bcm57xx-stage1-image.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-common.h" +#include "fu-common-version.h" + +#include "fu-bcm57xx-common.h" +#include "fu-bcm57xx-stage1-image.h" + +struct _FuBcm57xxStage1Image { + FuFirmwareImage parent_instance; +}; + +G_DEFINE_TYPE (FuBcm57xxStage1Image, fu_bcm57xx_stage1_image, FU_TYPE_FIRMWARE_IMAGE) + +static gboolean +fu_bcm57xx_stage1_image_parse (FuFirmwareImage *image, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + gsize bufsz = 0x0; + guint32 fwversion = 0; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + g_autoptr(GBytes) fw_nocrc = NULL; + + /* verify CRC */ + if ((flags & FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM) == 0) { + if (!fu_bcm57xx_verify_crc (fw, error)) + return FALSE; + } + + /* get version number */ + if (!fu_common_read_uint32_safe (buf, bufsz, BCM_NVRAM_STAGE1_VERSION, + &fwversion, G_BIG_ENDIAN, error)) + return FALSE; + if (fwversion != 0x0) { + g_autofree gchar *tmp = NULL; + tmp = fu_common_version_from_uint32 (fwversion, FWUPD_VERSION_FORMAT_TRIPLET); + fu_firmware_image_set_version (image, tmp); + } else { + guint32 bufver[4] = { '\0' }; + guint32 veraddr = 0x0; + g_autoptr(Bcm57xxVeritem) veritem = NULL; + + /* fall back to the string, e.g. '5719-v1.43' */ + if (!fu_common_read_uint32_safe (buf, bufsz, BCM_NVRAM_STAGE1_VERADDR, + &veraddr, G_BIG_ENDIAN, error)) + return FALSE; + if (veraddr < BCM_PHYS_ADDR_DEFAULT + sizeof(bufver)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "version address 0x%x less than physical 0x%x", + veraddr, (guint) BCM_PHYS_ADDR_DEFAULT); + return FALSE; + } + if (!fu_memcpy_safe ((guint8 *) bufver, sizeof(bufver), 0x0, /* dst */ + buf, bufsz, veraddr - BCM_PHYS_ADDR_DEFAULT, /* src */ + sizeof(bufver), error)) + return FALSE; + veritem = fu_bcm57xx_veritem_new ((guint8 *) bufver, sizeof(bufver)); + if (veritem != NULL) + fu_firmware_image_set_version (image, veritem->version); + } + + fw_nocrc = fu_common_bytes_new_offset (fw, 0x0, + g_bytes_get_size (fw) - sizeof(guint32), + error); + if (fw_nocrc == NULL) + return FALSE; + fu_firmware_image_set_bytes (image, fw_nocrc); + return TRUE; +} + +static GBytes * +fu_bcm57xx_stage1_image_write (FuFirmwareImage *image, GError **error) +{ + const guint8 *buf; + gsize bufsz = 0; + guint32 crc; + g_autoptr(GByteArray) blob = NULL; + g_autoptr(GBytes) fw_nocrc = NULL; + g_autoptr(GBytes) fw_align = NULL; + + /* get the CRC-less data */ + fw_nocrc = fu_firmware_image_get_bytes (image); + if (fw_nocrc == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "not supported"); + return NULL; + } + + /* this has to be aligned by DWORDs */ + fw_align = fu_common_bytes_align (fw_nocrc, sizeof(guint32), 0xff); + + /* add to a mutable buffer */ + buf = g_bytes_get_data (fw_align, &bufsz); + blob = g_byte_array_sized_new (bufsz + sizeof(guint32)); + g_byte_array_append (blob, buf, bufsz); + + /* add CRC */ + crc = fu_bcm57xx_nvram_crc (buf, bufsz); + fu_byte_array_append_uint32 (blob, crc, G_LITTLE_ENDIAN); + return g_byte_array_free_to_bytes (g_steal_pointer (&blob)); +} + +static void +fu_bcm57xx_stage1_image_init (FuBcm57xxStage1Image *self) +{ +} + +static void +fu_bcm57xx_stage1_image_class_init (FuBcm57xxStage1ImageClass *klass) +{ + FuFirmwareImageClass *klass_image = FU_FIRMWARE_IMAGE_CLASS (klass); + klass_image->parse = fu_bcm57xx_stage1_image_parse; + klass_image->write = fu_bcm57xx_stage1_image_write; +} + +FuFirmwareImage * +fu_bcm57xx_stage1_image_new (void) +{ + return FU_FIRMWARE_IMAGE (g_object_new (FU_TYPE_BCM57XX_STAGE1_IMAGE, NULL)); +} diff -Nru fwupd-1.4.5/plugins/bcm57xx/fu-bcm57xx-stage1-image.h fwupd-1.5.8/plugins/bcm57xx/fu-bcm57xx-stage1-image.h --- fwupd-1.4.5/plugins/bcm57xx/fu-bcm57xx-stage1-image.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/bcm57xx/fu-bcm57xx-stage1-image.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-firmware-image.h" + +#define FU_TYPE_BCM57XX_STAGE1_IMAGE (fu_bcm57xx_stage1_image_get_type ()) +G_DECLARE_FINAL_TYPE (FuBcm57xxStage1Image, fu_bcm57xx_stage1_image, FU, BCM57XX_STAGE1_IMAGE, FuFirmwareImage) + +FuFirmwareImage *fu_bcm57xx_stage1_image_new (void); diff -Nru fwupd-1.4.5/plugins/bcm57xx/fu-bcm57xx-stage2-image.c fwupd-1.5.8/plugins/bcm57xx/fu-bcm57xx-stage2-image.c --- fwupd-1.4.5/plugins/bcm57xx/fu-bcm57xx-stage2-image.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/bcm57xx/fu-bcm57xx-stage2-image.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-common.h" + +#include "fu-bcm57xx-common.h" +#include "fu-bcm57xx-stage2-image.h" + +struct _FuBcm57xxStage2Image { + FuFirmwareImage parent_instance; +}; + +G_DEFINE_TYPE (FuBcm57xxStage2Image, fu_bcm57xx_stage2_image, FU_TYPE_FIRMWARE_IMAGE) + +static gboolean +fu_bcm57xx_stage2_image_parse (FuFirmwareImage *image, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(GBytes) fw_nocrc = NULL; + if ((flags & FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM) == 0) { + if (!fu_bcm57xx_verify_crc (fw, error)) + return FALSE; + } + fw_nocrc = fu_common_bytes_new_offset (fw, 0x0, + g_bytes_get_size (fw) - sizeof(guint32), + error); + if (fw_nocrc == NULL) + return FALSE; + fu_firmware_image_set_bytes (image, fw_nocrc); + return TRUE; +} + +static GBytes * +fu_bcm57xx_stage2_image_write (FuFirmwareImage *image, GError **error) +{ + const guint8 *buf; + gsize bufsz = 0; + g_autoptr(GByteArray) blob = NULL; + g_autoptr(GBytes) fw_nocrc = NULL; + + /* get the CRC-less data */ + fw_nocrc = fu_firmware_image_get_bytes (image); + if (fw_nocrc == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "not supported"); + return NULL; + } + + /* add to a mutable buffer */ + buf = g_bytes_get_data (fw_nocrc, &bufsz); + blob = g_byte_array_sized_new (bufsz + (sizeof(guint32) * 3)); + fu_byte_array_append_uint32 (blob, BCM_NVRAM_MAGIC, G_BIG_ENDIAN); + fu_byte_array_append_uint32 (blob, + g_bytes_get_size (fw_nocrc) + sizeof(guint32), + G_BIG_ENDIAN); + g_byte_array_append (blob, buf, bufsz); + + /* add CRC */ + fu_byte_array_append_uint32 (blob, fu_bcm57xx_nvram_crc (buf, bufsz), G_LITTLE_ENDIAN); + return g_byte_array_free_to_bytes (g_steal_pointer (&blob)); +} + +static void +fu_bcm57xx_stage2_image_init (FuBcm57xxStage2Image *self) +{ +} + +static void +fu_bcm57xx_stage2_image_class_init (FuBcm57xxStage2ImageClass *klass) +{ + FuFirmwareImageClass *klass_image = FU_FIRMWARE_IMAGE_CLASS (klass); + klass_image->parse = fu_bcm57xx_stage2_image_parse; + klass_image->write = fu_bcm57xx_stage2_image_write; +} + +FuFirmwareImage * +fu_bcm57xx_stage2_image_new (void) +{ + return FU_FIRMWARE_IMAGE (g_object_new (FU_TYPE_BCM57XX_STAGE2_IMAGE, NULL)); +} diff -Nru fwupd-1.4.5/plugins/bcm57xx/fu-bcm57xx-stage2-image.h fwupd-1.5.8/plugins/bcm57xx/fu-bcm57xx-stage2-image.h --- fwupd-1.4.5/plugins/bcm57xx/fu-bcm57xx-stage2-image.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/bcm57xx/fu-bcm57xx-stage2-image.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-firmware-image.h" + +#define FU_TYPE_BCM57XX_STAGE2_IMAGE (fu_bcm57xx_stage2_image_get_type ()) +G_DECLARE_FINAL_TYPE (FuBcm57xxStage2Image, fu_bcm57xx_stage2_image, FU, BCM57XX_STAGE2_IMAGE, FuFirmwareImage) + +FuFirmwareImage *fu_bcm57xx_stage2_image_new (void); diff -Nru fwupd-1.4.5/plugins/bcm57xx/fu-plugin-bcm57xx.c fwupd-1.5.8/plugins/bcm57xx/fu-plugin-bcm57xx.c --- fwupd-1.4.5/plugins/bcm57xx/fu-plugin-bcm57xx.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/bcm57xx/fu-plugin-bcm57xx.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" + +#include "fu-bcm57xx-device.h" +#include "fu-bcm57xx-dict-image.h" +#include "fu-bcm57xx-firmware.h" +#include "fu-bcm57xx-stage1-image.h" +#include "fu-bcm57xx-stage2-image.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_udev_subsystem (plugin, "pci"); + fu_plugin_set_device_gtype (plugin, FU_TYPE_BCM57XX_DEVICE); + fu_plugin_add_firmware_gtype (plugin, NULL, FU_TYPE_BCM57XX_FIRMWARE); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_BETTER_THAN, "optionrom"); + g_type_ensure (FU_TYPE_BCM57XX_DICT_IMAGE); + g_type_ensure (FU_TYPE_BCM57XX_STAGE1_IMAGE); + g_type_ensure (FU_TYPE_BCM57XX_STAGE2_IMAGE); +} diff -Nru fwupd-1.4.5/plugins/bcm57xx/fu-self-test.c fwupd-1.5.8/plugins/bcm57xx/fu-self-test.c --- fwupd-1.4.5/plugins/bcm57xx/fu-self-test.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/bcm57xx/fu-self-test.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include + +#include "fu-common.h" +#include "fu-bcm57xx-common.h" +#include "fu-bcm57xx-firmware.h" + +static void +fu_bcm57xx_create_verbuf (guint8 *bufver, const gchar *version) +{ + memcpy (bufver, version, strlen (version) + 1); +} + +static void +fu_bcm57xx_common_veritem_func (void) +{ + g_autoptr(Bcm57xxVeritem) veritem1 = NULL; + g_autoptr(Bcm57xxVeritem) veritem2 = NULL; + g_autoptr(Bcm57xxVeritem) veritem3 = NULL; + guint8 bufver[16] = { 0x0 }; + + fu_bcm57xx_create_verbuf (bufver, "5719-v1.43"); + veritem1 = fu_bcm57xx_veritem_new (bufver, sizeof(bufver)); + g_assert_nonnull (veritem1); + g_assert_cmpstr (veritem1->version, ==, "1.43"); + g_assert_cmpstr (veritem1->branch, ==, BCM_FW_BRANCH_UNKNOWN); + g_assert_cmpint (veritem1->verfmt, ==, FWUPD_VERSION_FORMAT_PAIR); + + fu_bcm57xx_create_verbuf (bufver, "stage1-0.4.391"); + veritem2 = fu_bcm57xx_veritem_new (bufver, sizeof(bufver)); + g_assert_nonnull (veritem2); + g_assert_cmpstr (veritem2->version, ==, "0.4.391"); + g_assert_cmpstr (veritem2->branch, ==, BCM_FW_BRANCH_OSS_FIRMWARE); + g_assert_cmpint (veritem2->verfmt, ==, FWUPD_VERSION_FORMAT_TRIPLET); + + fu_bcm57xx_create_verbuf (bufver, "RANDOM-7"); + veritem3 = fu_bcm57xx_veritem_new (bufver, sizeof(bufver)); + g_assert_nonnull (veritem3); + g_assert_cmpstr (veritem3->version, ==, "RANDOM-7"); + g_assert_cmpstr (veritem3->branch, ==, BCM_FW_BRANCH_UNKNOWN); + g_assert_cmpint (veritem3->verfmt, ==, FWUPD_VERSION_FORMAT_UNKNOWN); +} + +static void +fu_bcm57xx_firmware_talos_func (void) +{ + gboolean ret; + g_autofree gchar *fn = NULL; + g_autofree gchar *fn_out = NULL; + g_autoptr(GBytes) blob = NULL; + g_autoptr(GBytes) blob_out = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) images = NULL; + g_autoptr(FuFirmware) firmware = fu_bcm57xx_firmware_new (); + + /* load file */ + fn = g_test_build_filename (G_TEST_DIST, "tests", "Bcm5719_talos.bin", NULL); + if (!g_file_test (fn, G_FILE_TEST_EXISTS)) { + g_test_skip ("missing file"); + return; + } + blob = fu_common_get_contents_bytes (fn, &error); + g_assert_no_error (error); + g_assert_nonnull (blob); + ret = fu_firmware_parse (firmware, blob, FWUPD_INSTALL_FLAG_NONE, &error); + g_assert_no_error (error); + g_assert_true (ret); + images = fu_firmware_get_images (firmware); + g_assert_cmpint (images->len, ==, 6); + + blob_out = fu_firmware_write (firmware, &error); + g_assert_no_error (error); + g_assert_nonnull (blob_out); + fn_out = g_test_build_filename (G_TEST_BUILT, "tests", "Bcm5719_talos.bin", NULL); + ret = fu_common_set_contents_bytes (fn_out, blob_out, &error); + g_assert_no_error (error); + g_assert_true (ret); + ret = fu_common_bytes_compare (blob, blob_out, &error); + g_assert_no_error (error); + g_assert_true (ret); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + /* only critical and error are fatal */ + g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); + + /* tests go here */ + g_test_add_func ("/fwupd/bcm57xx/firmware{talos}", fu_bcm57xx_firmware_talos_func); + g_test_add_func ("/fwupd/bcm57xx/common{veritem}", fu_bcm57xx_common_veritem_func); + return g_test_run (); +} diff -Nru fwupd-1.4.5/plugins/bcm57xx/meson.build fwupd-1.5.8/plugins/bcm57xx/meson.build --- fwupd-1.4.5/plugins/bcm57xx/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/bcm57xx/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,64 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginBcm57xx"'] + +install_data(['bcm57xx.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) +shared_module('fu_plugin_bcm57xx', + fu_hash, + sources : [ + 'fu-plugin-bcm57xx.c', + 'fu-bcm57xx-common.c', # fuzzing + 'fu-bcm57xx-device.c', + 'fu-bcm57xx-dict-image.c', # fuzzing + 'fu-bcm57xx-firmware.c', # fuzzing + 'fu-bcm57xx-recovery-device.c', + 'fu-bcm57xx-stage1-image.c', # fuzzing + 'fu-bcm57xx-stage2-image.c', # fuzzing + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + valgrind, + ], +) + +if get_option('tests') + e = executable( + 'bcm57xx-self-test', + fu_hash, + sources : [ + 'fu-self-test.c', + 'fu-bcm57xx-common.c', + 'fu-bcm57xx-dict-image.c', + 'fu-bcm57xx-firmware.c', + 'fu-bcm57xx-stage1-image.c', + 'fu-bcm57xx-stage2-image.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + dependencies : [ + plugin_deps, + ], + link_with : [ + fwupd, + fwupdplugin, + ], + install : true, + install_dir : installed_test_bindir, + ) + test('bcm57xx-self-test', e) +endif diff -Nru fwupd-1.4.5/plugins/bcm57xx/README.md fwupd-1.5.8/plugins/bcm57xx/README.md --- fwupd-1.4.5/plugins/bcm57xx/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/bcm57xx/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,43 @@ +BCM57xx Support +=============== + +Introduction +------------ + +This plugin updates BCM57xx wired network adaptors from Broadcom using a +reverse-engineered flashing protocol. It is designed to be used with the +clean-room reimplementation of the BCM5719 firmware found here: +https://github.com/meklort/bcm5719-fw + +Protocol +-------- +BCM57xx devices support a custom `com.broadcom.bcm57xx` protocol which is +implemented as ioctls like ethtool does. + +GUID Generation +--------------- + +These devices use the standard PCI instance IDs, for example: + + * `PCI\VEN_14E4&DEV_1657` + * `PCI\VEN_14E4&DEV_1657&SUBSYS_17AA222E` + +Update Behavior +--------------- + +The device usually presents in runtime mode, and the firmware is written to the +device without disconnecting the working kernel driver. Once complete the APE +is reset which may cause a brief link reconnection. + +On flash failure the device is nonfunctional, but is recoverable using direct +BAR writes, which is typically much slower than updating the device using the +kernel driver and the ethtool API. + +Vendor ID Security +------------------ + +The vendor ID is set from the PCI vendor, in this instance set to `PCI:0x14E4` + +External interface access +------------------------- +This plugin requires the `SIOCETHTOOL` ioctl interface. diff -Nru fwupd-1.4.5/plugins/bios/fu-plugin-bios.c fwupd-1.5.8/plugins/bios/fu-plugin-bios.c --- fwupd-1.4.5/plugins/bios/fu-plugin-bios.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/bios/fu-plugin-bios.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2020 Mario Limonciello + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-efivar.h" +#include "fu-plugin-vfuncs.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + +gboolean +fu_plugin_startup (FuPlugin *plugin, GError **error) +{ + const gchar *vendor; + + vendor = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_BIOS_VENDOR); + if (g_strcmp0 (vendor, "coreboot") == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "system uses coreboot"); + return FALSE; + } + + return TRUE; +} + +gboolean +fu_plugin_coldplug (FuPlugin *plugin, GError **error) +{ + g_autofree gchar *sysfsfwdir = NULL; + g_autofree gchar *esrt_path = NULL; + + /* are the EFI dirs set up so we can update each device */ +#if defined(__x86_64__) || defined(__i386__) + g_autoptr(GError) error_local = NULL; + if (!fu_efivar_supported (&error_local)) { + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_LEGACY_BIOS); + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_USER_WARNING); + return TRUE; + } +#endif + + /* get the directory of ESRT entries */ + sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); + esrt_path = g_build_filename (sysfsfwdir, "efi", "esrt", NULL); + if (!g_file_test (esrt_path, G_FILE_TEST_IS_DIR)) { + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_CAPSULES_UNSUPPORTED); + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_USER_WARNING); + return TRUE; + } + + /* we appear to have UEFI capsule updates */ + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_DISABLED); + return TRUE; +} diff -Nru fwupd-1.4.5/plugins/bios/meson.build fwupd-1.5.8/plugins/bios/meson.build --- fwupd-1.4.5/plugins/bios/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/bios/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,25 @@ +if get_option('plugin_uefi_capsule') +cargs = ['-DG_LOG_DOMAIN="FuPluginBios"'] + +shared_module('fu_plugin_bios', + fu_hash, + sources : [ + 'fu-plugin-bios.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) +endif diff -Nru fwupd-1.4.5/plugins/ccgx/ccgx-ids.quirk fwupd-1.5.8/plugins/ccgx/ccgx-ids.quirk --- fwupd-1.4.5/plugins/ccgx/ccgx-ids.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/ccgx/ccgx-ids.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,319 +1,319 @@ # CCG2 - CYPD2103-20FNXI -[DeviceInstanceId=CCGX\SID_1400] -FlashRowSize = 0x80 -FlashSize = 0x8000 +[CCGX\SID_1400] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x8000 # CCG2 - CYPD2104-20FNXI -[DeviceInstanceId=CCGX\SID_1401] -FlashRowSize = 0x80 -FlashSize = 0x8000 +[CCGX\SID_1401] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x8000 # CCG2 - CYPD2105-20FNXI -[DeviceInstanceId=CCGX\SID_1402] -FlashRowSize = 0x80 -FlashSize = 0x8000 +[CCGX\SID_1402] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x8000 # CCG2 - CYPD2103-14LHXI -[DeviceInstanceId=CCGX\SID_1403] -FlashRowSize = 0x80 -FlashSize = 0x8000 +[CCGX\SID_1403] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x8000 # CCG2 - CYPD2122-24LQXI -[DeviceInstanceId=CCGX\SID_1404] -FlashRowSize = 0x80 -FlashSize = 0x8000 +[CCGX\SID_1404] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x8000 # CCG2 - CYPD2134-24LQXI -[DeviceInstanceId=CCGX\SID_1405] -FlashRowSize = 0x80 -FlashSize = 0x8000 +[CCGX\SID_1405] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x8000 # CCG2 - CYPD2122-20FNXI -[DeviceInstanceId=CCGX\SID_1406] -FlashRowSize = 0x80 -FlashSize = 0x8000 +[CCGX\SID_1406] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x8000 # CCG2 - CYPD2123-24LQXI -[DeviceInstanceId=CCGX\SID_1407] -FlashRowSize = 0x80 -FlashSize = 0x8000 +[CCGX\SID_1407] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x8000 # CCG2 - CYPD2124-24LQXI -[DeviceInstanceId=CCGX\SID_1408] -FlashRowSize = 0x80 -FlashSize = 0x8000 +[CCGX\SID_1408] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x8000 # CCG2 - CYPD2119-24LQXI -[DeviceInstanceId=CCGX\SID_1409] -FlashRowSize = 0x80 -FlashSize = 0x8000 +[CCGX\SID_1409] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x8000 # CCG2 - CYPD2121-24LQXI -[DeviceInstanceId=CCGX\SID_1410] -FlashRowSize = 0x80 -FlashSize = 0x8000 +[CCGX\SID_1410] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x8000 # CCG2 - CYPD2125-24LQXI -[DeviceInstanceId=CCGX\SID_1411] -FlashRowSize = 0x80 -FlashSize = 0x8000 +[CCGX\SID_1411] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x8000 # CCG2 - CYPD2120-24LQXI -[DeviceInstanceId=CCGX\SID_1412] -FlashRowSize = 0x80 -FlashSize = 0x8000 +[CCGX\SID_1412] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x8000 # CCG3 - CYPD3120-40LQXI -[DeviceInstanceId=CCGX\SID_1D00] -FlashRowSize = 0x80 -FlashSize = 0x20000 +[CCGX\SID_1D00] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x20000 # CCG3 - CYPD3105-42FNXI -[DeviceInstanceId=CCGX\SID_1D01] -FlashRowSize = 0x80 -FlashSize = 0x20000 +[CCGX\SID_1D01] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x20000 # CCG3 - CYPD3121-40LQXI -[DeviceInstanceId=CCGX\SID_1D02] -FlashRowSize = 0x80 -FlashSize = 0x20000 +[CCGX\SID_1D02] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x20000 # CCG3 - CYPD3122-40LQXI -[DeviceInstanceId=CCGX\SID_1D03] -FlashRowSize = 0x80 -FlashSize = 0x20000 +[CCGX\SID_1D03] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x20000 # CCG3 - CYPD3125-40LQXI -[DeviceInstanceId=CCGX\SID_1D04] -FlashRowSize = 0x80 -FlashSize = 0x20000 +[CCGX\SID_1D04] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x20000 # CCG3 - CYPD3135-40LQXI -[DeviceInstanceId=CCGX\SID_1D05] -FlashRowSize = 0x80 -FlashSize = 0x20000 +[CCGX\SID_1D05] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x20000 # CCG3 - CYPD3135-16SXQ' -[DeviceInstanceId=CCGX\SID_1D06] -FlashRowSize = 0x80 -FlashSize = 0x20000 +[CCGX\SID_1D06] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x20000 # CCG3 - CYPD3126-42FNXI -[DeviceInstanceId=CCGX\SID_1D07] -FlashRowSize = 0x80 -FlashSize = 0x20000 +[CCGX\SID_1D07] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x20000 # CCG3 - CYPD3123-40LQXI -[DeviceInstanceId=CCGX\SID_1D09] -FlashRowSize = 0x80 -FlashSize = 0x20000 +[CCGX\SID_1D09] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x20000 # CCG4 - CYPD4225-40LQXI -[DeviceInstanceId=CCGX\SID_1800] -FlashRowSize = 0x100 -FlashSize = 0x20000 +[CCGX\SID_1800] +CcgxFlashRowSize = 0x100 +CcgxFlashSize = 0x20000 # CCG4 - CYPD4125-40LQXI -[DeviceInstanceId=CCGX\SID_1801] -FlashRowSize = 0x100 -FlashSize = 0x20000 +[CCGX\SID_1801] +CcgxFlashRowSize = 0x100 +CcgxFlashSize = 0x20000 # CCG4 - CYPD4235-40LQXI -[DeviceInstanceId=CCGX\SID_1802] -FlashRowSize = 0x100 -FlashSize = 0x20000 +[CCGX\SID_1802] +CcgxFlashRowSize = 0x100 +CcgxFlashSize = 0x20000 # CCG4 - CYPD4135-40LQXI -[DeviceInstanceId=CCGX\SID_1803] -FlashRowSize = 0x100 -FlashSize = 0x20000 +[CCGX\SID_1803] +CcgxFlashRowSize = 0x100 +CcgxFlashSize = 0x20000 # CCG4 - CYPD4225A0-33FNXIT -[DeviceInstanceId=CCGX\SID_1810] -FlashRowSize = 0x100 -FlashSize = 0x20000 +[CCGX\SID_1810] +CcgxFlashRowSize = 0x100 +CcgxFlashSize = 0x20000 # CCG4 - CYPD4226-40LQXI -[DeviceInstanceId=CCGX\SID_1F00] -FlashRowSize = 0x100 -FlashSize = 0x20000 +[CCGX\SID_1F00] +CcgxFlashRowSize = 0x100 +CcgxFlashSize = 0x20000 # CCG4 - CYPD4126-40LQXI -[DeviceInstanceId=CCGX\SID_1F01] -FlashRowSize = 0x100 -FlashSize = 0x20000 +[CCGX\SID_1F01] +CcgxFlashRowSize = 0x100 +CcgxFlashSize = 0x20000 # CCG4 - CYPD4126-24LQXI -[DeviceInstanceId=CCGX\SID_1F04] -FlashRowSize = 0x100 -FlashSize = 0x20000 +[CCGX\SID_1F04] +CcgxFlashRowSize = 0x100 +CcgxFlashSize = 0x20000 # CCG4 - CYPD4236-40LQXI -[DeviceInstanceId=CCGX\SID_1F02] -FlashRowSize = 0x100 -FlashSize = 0x20000 +[CCGX\SID_1F02] +CcgxFlashRowSize = 0x100 +CcgxFlashSize = 0x20000 # CCG4 - CYPD4136-40LQXI -[DeviceInstanceId=CCGX\SID_1F03] -FlashRowSize = 0x100 -FlashSize = 0x20000 +[CCGX\SID_1F03] +CcgxFlashRowSize = 0x100 +CcgxFlashSize = 0x20000 # CCG4 - CYPD4136-24LQXI -[DeviceInstanceId=CCGX\SID_1F05] -FlashRowSize = 0x100 -FlashSize = 0x20000 +[CCGX\SID_1F05] +CcgxFlashRowSize = 0x100 +CcgxFlashSize = 0x20000 # CCG3PA - CYPD3174-24LQXQ -[DeviceInstanceId=CCGX\SID_2000] -FlashRowSize = 0x80 -FlashSize = 0x10000 +[CCGX\SID_2000] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x10000 # CCG3PA - CYPD3174-16SXQ -[DeviceInstanceId=CCGX\SID_2001] -FlashRowSize = 0x80 -FlashSize = 0x10000 +[CCGX\SID_2001] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x10000 # CCG3PA - CYPD3175-24LQXQ -[DeviceInstanceId=CCGX\SID_2002] -FlashRowSize = 0x80 -FlashSize = 0x10000 +[CCGX\SID_2002] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x10000 # CCG3PA - CYPD3171-24LQXQ -[DeviceInstanceId=CCGX\SID_2003] -FlashRowSize = 0x80 -FlashSize = 0x10000 +[CCGX\SID_2003] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x10000 # CCG3PA - CYPD3195-24LDXS -[DeviceInstanceId=CCGX\SID_2005] -FlashRowSize = 0x80 -FlashSize = 0x10000 +[CCGX\SID_2005] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x10000 # CCG3PA - CYPD3196-24LDXS -[DeviceInstanceId=CCGX\SID_2006] -FlashRowSize = 0x80 -FlashSize = 0x10000 +[CCGX\SID_2006] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x10000 # CCG3PA - CYPD3197-24LDXS -[DeviceInstanceId=CCGX\SID_2007] -FlashRowSize = 0x80 -FlashSize = 0x10000 +[CCGX\SID_2007] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x10000 # CCG3PA2 - CYPDC1185-32LQXQ -[DeviceInstanceId=CCGX\SID_2400] -FlashRowSize = 0x80 -FlashSize = 0x20000 +[CCGX\SID_2400] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x20000 # CCG3PA2 - CYPDC1186-30FNXI -[DeviceInstanceId=CCGX\SID_2401] -FlashRowSize = 0x80 -FlashSize = 0x20000 +[CCGX\SID_2401] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x20000 # CCG3PA2 - CYPDC1186B2-30FNXI -[DeviceInstanceId=CCGX\SID_2402] -FlashRowSize = 0x80 -FlashSize = 0x20000 +[CCGX\SID_2402] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x20000 # CCG5 - CYPD5225-96BZXI -[DeviceInstanceId=CCGX\SID_2100] -FlashRowSize = 0x100 -FlashSize = 0x20000 +[CCGX\SID_2100] +CcgxFlashRowSize = 0x100 +CcgxFlashSize = 0x20000 # CCG5 - CYPD5125-40LQXI -[DeviceInstanceId=CCGX\SID_2101] -FlashRowSize = 0x100 -FlashSize = 0x20000 +[CCGX\SID_2101] +CcgxFlashRowSize = 0x100 +CcgxFlashSize = 0x20000 # CCG5 - CYPD5235-96BZXI -[DeviceInstanceId=CCGX\SID_2102] -FlashRowSize = 0x100 -FlashSize = 0x20000 +[CCGX\SID_2102] +CcgxFlashRowSize = 0x100 +CcgxFlashSize = 0x20000 # CCG5 - CYPD5236-96BZXI -[DeviceInstanceId=CCGX\SID_2103] -FlashRowSize = 0x100 -FlashSize = 0x20000 +[CCGX\SID_2103] +CcgxFlashRowSize = 0x100 +CcgxFlashSize = 0x20000 # CCG5 - CYPD5237-96BZXI -[DeviceInstanceId=CCGX\SID_2104] -FlashRowSize = 0x100 -FlashSize = 0x20000 +[CCGX\SID_2104] +CcgxFlashRowSize = 0x100 +CcgxFlashSize = 0x20000 # CCG5 - CYPD5227-96BZXI -[DeviceInstanceId=CCGX\SID_2105] -FlashRowSize = 0x100 -FlashSize = 0x20000 +[CCGX\SID_2105] +CcgxFlashRowSize = 0x100 +CcgxFlashSize = 0x20000 # CCG5 - CYPD5135-40LQXI -[DeviceInstanceId=CCGX\SID_2106] -FlashRowSize = 0x100 -FlashSize = 0x20000 +[CCGX\SID_2106] +CcgxFlashRowSize = 0x100 +CcgxFlashSize = 0x20000 # CCG6 - CYPD6125-40LQXI -[DeviceInstanceId=CCGX\SID_2A00] -FlashRowSize = 0x100 -FlashSize = 0x20000 +[CCGX\SID_2A00] +CcgxFlashRowSize = 0x100 +CcgxFlashSize = 0x20000 # CCG6 - CYPD6126-96BZXI -[DeviceInstanceId=CCGX\SID_2A10] -FlashRowSize = 0x100 -FlashSize = 0x20000 +[CCGX\SID_2A10] +CcgxFlashRowSize = 0x100 +CcgxFlashSize = 0x20000 # CCG6 - CYPD5126-40LQXI -[DeviceInstanceId=CCGX\SID_2A01] -FlashRowSize = 0x100 -FlashSize = 0x20000 +[CCGX\SID_2A01] +CcgxFlashRowSize = 0x100 +CcgxFlashSize = 0x20000 # CCG6 - CYPD5137-40LQXI -[DeviceInstanceId=CCGX\SID_2A02] -FlashRowSize = 0x100 -FlashSize = 0x20000 +[CCGX\SID_2A02] +CcgxFlashRowSize = 0x100 +CcgxFlashSize = 0x20000 # CCG6 - CYPD6137-40LQXI -[DeviceInstanceId=CCGX\SID_2A03] -FlashRowSize = 0x100 -FlashSize = 0x20000 +[CCGX\SID_2A03] +CcgxFlashRowSize = 0x100 +CcgxFlashSize = 0x20000 # PAG1S - CYPAS111-24LQXQ -[DeviceInstanceId=CCGX\SID_2B01] -FlashRowSize = 0x80 -FlashSize = 0x10000 +[CCGX\SID_2B01] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x10000 # PAG1S - CYPD3184-24LQXQ -[DeviceInstanceId=CCGX\SID_2B00] -FlashRowSize = 0x80 -FlashSize = 0x10000 +[CCGX\SID_2B00] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x10000 # HX3PD - CYUSB4347-BZXC_PD -[DeviceInstanceId=CCGX\SID_1F82] -FlashRowSize = 0x100 -FlashSize = 0x20000 +[CCGX\SID_1F82] +CcgxFlashRowSize = 0x100 +CcgxFlashSize = 0x20000 # ACG1F - CYAC1126-24LQXI -[DeviceInstanceId=CCGX\SID_2F00] -FlashRowSize = 0x40 -FlashSize = 0x4000 +[CCGX\SID_2F00] +CcgxFlashRowSize = 0x40 +CcgxFlashSize = 0x4000 # ACG1F - CYAC1126-40LQXI -[DeviceInstanceId=CCGX\SID_2F01] -FlashRowSize = 0x40 -FlashSize = 0x4000 +[CCGX\SID_2F01] +CcgxFlashRowSize = 0x40 +CcgxFlashSize = 0x4000 # CCG6DF - CYPD6227-96BZXI -[DeviceInstanceId=CCGX\SID_3000] -FlashRowSize = 0x80 -FlashSize = 0x10000 +[CCGX\SID_3000] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x10000 # CCG6DF - CYPD6127-96BZXI -[DeviceInstanceId=CCGX\SID_3001] -FlashRowSize = 0x80 -FlashSize = 0x10000 +[CCGX\SID_3001] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x10000 # CCG6SF - CYPD6128-96BZXI -[DeviceInstanceId=CCGX\SID_3300] -FlashRowSize = 0x80 -FlashSize = 0x10000 +[CCGX\SID_3300] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x10000 # CCG6SF - CYPD6127-48LQXI -[DeviceInstanceId=CCGX\SID_3301] -FlashRowSize = 0x80 -FlashSize = 0x10000 +[CCGX\SID_3301] +CcgxFlashRowSize = 0x80 +CcgxFlashSize = 0x10000 diff -Nru fwupd-1.4.5/plugins/ccgx/ccgx.quirk fwupd-1.5.8/plugins/ccgx/ccgx.quirk --- fwupd-1.4.5/plugins/ccgx/ccgx.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/ccgx/ccgx.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,74 +1,74 @@ # Lenovo ThinkPad USB-C Dock Gen2 -[DeviceInstanceId=USB\VID_17EF&PID_A38F] +[USB\VID_17EF&PID_A38F] Plugin = ccgx GType = FuCcgxHidDevice ParentGuid = USB\VID_17EF&PID_A391 -[DeviceInstanceId=USB\VID_04B4&PID_521A] +[USB\VID_04B4&PID_521A] Plugin = ccgx GType = FuCcgxHpiDevice -[DeviceInstanceId=USB\VID_04B4&PID_521A&SID_1F00&APP_6D64] -ImageKind = dual-asymmetric +[USB\VID_04B4&PID_521A&SID_1F00&APP_6D64] +CcgxImageKind = dual-asymmetric Name = ThinkPad USB-C Dock Gen2 PD Controller ParentGuid = USB\VID_17EF&PID_A391 InstallDuration = 120 RemoveDelay = 60000 -[DeviceInstanceId=USB\VID_04B4&PID_521A&SID_1F00&APP_6D64&MODE_FW1] +[USB\VID_04B4&PID_521A&SID_1F00&APP_6D64&MODE_FW1] Summary = CCGx Power Delivery Device (Bootloader) Flags = is-bootloader -[DeviceInstanceId=USB\VID_04B4&PID_521A&SID_1F00&APP_6D64&MODE_FW2] +[USB\VID_04B4&PID_521A&SID_1F00&APP_6D64&MODE_FW2] Summary = CCGx Power Delivery Device CounterpartGuid = USB\VID_04B4&PID_521A&SID_1F00&APP_6D64&MODE_FW1 # Lenovo ThinkPad USB-C Dock Hybrid -[DeviceInstanceId=USB\VID_17EF&PID_A354] +[USB\VID_17EF&PID_A354] Plugin = ccgx GType = FuCcgxHidDevice ParentGuid = USB\VID_17EF&PID_1028 -[DeviceInstanceId=USB\VID_17EF&PID_A35F] +[USB\VID_17EF&PID_A35F] Plugin = ccgx GType = FuCcgxHidDevice ParentGuid = USB\VID_17EF&PID_1028 -[DeviceInstanceId=USB\VID_04B4&PID_5218] +[USB\VID_04B4&PID_5218] Plugin = ccgx GType = FuCcgxHpiDevice -[DeviceInstanceId=USB\VID_04B4&PID_5218&SID_1F00&APP_6432] -ImageKind = dual-symmetric +[USB\VID_04B4&PID_5218&SID_1F00&APP_6432] +CcgxImageKind = dual-symmetric Name = ThinkPad USB-C Dock Hybrid PD Controller ParentGuid = USB\VID_17EF&PID_1028 InstallDuration = 120 RemoveDelay = 60000 -[DeviceInstanceId=USB\VID_04B4&PID_5218&SID_1F00&APP_6432&MODE_FW1] +[USB\VID_04B4&PID_5218&SID_1F00&APP_6432&MODE_FW1] Summary = CCGx Power Delivery Device (Symmetric FW1) -[DeviceInstanceId=USB\VID_04B4&PID_5218&SID_1F00&APP_6432&MODE_FW2] +[USB\VID_04B4&PID_5218&SID_1F00&APP_6432&MODE_FW2] Summary = CCGx Power Delivery Device (Symmetric FW2) # HP USB-C Dock G5 -[DeviceInstanceId=USB\VID_03F0&PID_046B] +[USB\VID_03F0&PID_046B] Plugin = ccgx GType = FuCcgxDmcDevice Summary = Dock Management Controller Device ParentGuid = USB\VID_03F0&PID_0363 Name = HP USB-C Dock G5 -ImageKind = dmc-composite +CcgxImageKind = dmc-composite InstallDuration = 233 RemoveDelay = 203000 # HP USB-C/A Universal Dock G2 -[DeviceInstanceId=USB\VID_03F0&PID_0A6B] +[USB\VID_03F0&PID_0A6B] Plugin = ccgx GType = FuCcgxDmcDevice Summary = Dock Management Controller Device ParentGuid = USB\VID_03F0&PID_096B Name = HP USB-C/A Universal Dock G2 -ImageKind = dmc-composite +CcgxImageKind = dmc-composite InstallDuration = 180 RemoveDelay = 162000 diff -Nru fwupd-1.4.5/plugins/ccgx/fu-ccgx-dmc-device.c fwupd-1.5.8/plugins/ccgx/fu-ccgx-dmc-device.c --- fwupd-1.4.5/plugins/ccgx/fu-ccgx-dmc-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/ccgx/fu-ccgx-dmc-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -358,21 +358,20 @@ /* write start row and number of rows to a device */ if (!fu_ccgx_dmc_device_send_write_command (self, - seg_rcd->info_header.start_row, - seg_rcd->info_header.num_rows, + seg_rcd->start_row, + seg_rcd->num_rows, error)) return FALSE; /* get data records */ data_records = seg_rcd->data_records; for (guint32 data_index = 0; data_index < data_records->len; data_index++) { - FuCcgxDmcFirmwareDataRecord *data_rcd; + GBytes *data_rcd = g_ptr_array_index (data_records, data_index); const guint8 *row_buffer = NULL; gsize row_size = 0; /* write row data */ - data_rcd = g_ptr_array_index (data_records, data_index); - row_buffer = g_bytes_get_data (data_rcd->data, &row_size); + row_buffer = g_bytes_get_data (data_rcd, &row_size); if (!fu_ccgx_dmc_device_send_row_data (self, row_buffer, (guint16) row_size, @@ -626,14 +625,14 @@ { FuCcgxDmcDevice *self = FU_CCGX_DMC_DEVICE (device); - if (g_strcmp0 (key, "ImageKind") == 0) { + if (g_strcmp0 (key, "CcgxImageKind") == 0) { self->fw_image_type = fu_ccgx_fw_image_type_from_string (value); if (self->fw_image_type != FW_IMAGE_TYPE_UNKNOWN) return TRUE; g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, - "invalid ImageKind"); + "invalid CcgxImageKind"); return FALSE; } g_set_error_literal (error, @@ -648,11 +647,12 @@ { self->ep_intr_in = DMC_INTERRUPT_PIPE_ID; self->ep_bulk_out = DMC_BULK_PIPE_ID; - fu_device_set_protocol (FU_DEVICE (self), "com.cypress.ccgx.dmc"); + fu_device_add_protocol (FU_DEVICE (self), "com.cypress.ccgx.dmc"); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_QUAD); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_REQUIRE_AC); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_DUAL_IMAGE); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_SELF_RECOVERY); + fu_device_add_internal_flag (FU_DEVICE (self), FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID); } static void diff -Nru fwupd-1.4.5/plugins/ccgx/fu-ccgx-dmc-firmware.c fwupd-1.5.8/plugins/ccgx/fu-ccgx-dmc-firmware.c --- fwupd-1.4.5/plugins/ccgx/fu-ccgx-dmc-firmware.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/ccgx/fu-ccgx-dmc-firmware.c 2021-03-31 20:08:32.000000000 +0000 @@ -7,6 +7,9 @@ #include "config.h" +#include + +#include "fu-chunk.h" #include "fu-common.h" #include "fu-common-version.h" #include "fu-ccgx-dmc-common.h" @@ -19,7 +22,6 @@ GBytes *fwct_blob; GBytes *custom_meta_blob; guint32 row_data_offset_start; - FwctInfo fwct_info; guint32 fw_data_size; }; @@ -41,17 +43,8 @@ g_free (rcd); } -static void -fu_ccgx_dmc_firmware_data_record_free (FuCcgxDmcFirmwareDataRecord *rcd) -{ - if (rcd->data != NULL) - g_bytes_unref (rcd->data); - g_free (rcd); -} - G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuCcgxDmcFirmwareImageRecord, fu_ccgx_dmc_firmware_image_record_free) G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuCcgxDmcFirmwareSegmentRecord, fu_ccgx_dmc_firmware_segment_record_free) -G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuCcgxDmcFirmwareDataRecord, fu_ccgx_dmc_firmware_data_record_free) GPtrArray * fu_ccgx_dmc_firmware_get_image_records (FuCcgxDmcFirmware *self) @@ -74,13 +67,6 @@ return self->custom_meta_blob; } -FwctInfo * -fu_ccgx_dmc_firmware_get_fwct_info (FuCcgxDmcFirmware *self) -{ - g_return_val_if_fail (FU_IS_CCGX_DMC_FIRMWARE (self), NULL); - return &self->fwct_info; -} - guint32 fu_ccgx_dmc_firmware_get_fw_data_size (FuCcgxDmcFirmware *self) { @@ -98,90 +84,87 @@ static gboolean fu_ccgx_dmc_firmware_parse_segment (FuFirmware *firmware, - const guint8 *fw_buf, - gsize fw_bufsz, + const guint8 *buf, + gsize bufsz, FuCcgxDmcFirmwareImageRecord *img_rcd, - gsize *segment_info_offset, + gsize *seg_off, + FwupdInstallFlags flags, GError **error) { FuCcgxDmcFirmware *self = FU_CCGX_DMC_FIRMWARE (firmware); - gsize fw_buffer_offset = 0; - gsize row_data_offset; - gsize digestlen = DMC_HASH_SIZE; - guint8 hash[DMC_HASH_SIZE]; + gsize row_off; g_autoptr(GChecksum) csum = g_checksum_new (G_CHECKSUM_SHA256); /* set row data offset in current image */ - row_data_offset = self->row_data_offset_start + img_rcd->info_header.img_offset; - - /* create segment record array in image record */ - img_rcd->seg_records = g_ptr_array_new_with_free_func ((GFreeFunc) fu_ccgx_dmc_firmware_segment_record_free); + row_off = self->row_data_offset_start + img_rcd->img_offset; /* parse segment in image */ - for (guint32 seg_num = 0; seg_num < img_rcd->info_header.num_img_segments; seg_num++) { - guint16 actual_row_size = 0; + img_rcd->seg_records = g_ptr_array_new_with_free_func ((GFreeFunc) fu_ccgx_dmc_firmware_segment_record_free); + for (guint32 i = 0; i < img_rcd->num_img_segments; i++) { + guint16 row_size_bytes = 0; g_autofree guint8 *row_buf = NULL; g_autoptr(FuCcgxDmcFirmwareSegmentRecord) seg_rcd = NULL; - /* set segment info offset */ - fw_buffer_offset = *segment_info_offset; - /* read segment info */ seg_rcd = g_new0 (FuCcgxDmcFirmwareSegmentRecord, 1); - if (!fu_memcpy_safe ((guint8 *) &seg_rcd->info_header, sizeof(seg_rcd->info_header), 0x0, /* dst */ - fw_buf, fw_bufsz, fw_buffer_offset, /* src */ - sizeof(seg_rcd->info_header), error)) + if (!fu_common_read_uint16_safe (buf, bufsz, + *seg_off + G_STRUCT_OFFSET(FwctSegmentationInfo, start_row), + &seg_rcd->start_row, G_LITTLE_ENDIAN, error)) + return FALSE; + if (!fu_common_read_uint16_safe (buf, bufsz, + *seg_off + G_STRUCT_OFFSET(FwctSegmentationInfo, num_rows), + &seg_rcd->num_rows, G_LITTLE_ENDIAN, error)) return FALSE; /* calculate actual row size */ - actual_row_size = img_rcd->info_header.row_size * 64; + row_size_bytes = img_rcd->row_size * 64; /* create data record array in segment record */ - seg_rcd->data_records = g_ptr_array_new_with_free_func ((GFreeFunc) fu_ccgx_dmc_firmware_data_record_free); + seg_rcd->data_records = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref); /* read row data in segment */ - row_buf = g_malloc0 (actual_row_size); - for (int row = 0; row < seg_rcd->info_header.num_rows; row++) { - g_autoptr(FuCcgxDmcFirmwareDataRecord) data_rcd = NULL; - - /* set row data offset */ - fw_buffer_offset = row_data_offset; + row_buf = g_malloc0 (row_size_bytes); + for (int row = 0; row < seg_rcd->num_rows; row++) { + g_autoptr(GBytes) data_rcd = NULL; /* read row data */ - if (!fu_memcpy_safe (row_buf, actual_row_size, 0x0, /* dst */ - fw_buf, fw_bufsz, fw_buffer_offset, /* src */ - actual_row_size, error)) + if (!fu_memcpy_safe (row_buf, row_size_bytes, 0x0, /* dst */ + buf, bufsz, row_off, /* src */ + row_size_bytes, error)) { + g_prefix_error (error, "failed to read row data: "); return FALSE; + } /* update hash */ - g_checksum_update (csum, (guchar *) row_buf, actual_row_size); + g_checksum_update (csum, (guchar *) row_buf, row_size_bytes); /* add row data to data record */ - data_rcd = g_new0 (FuCcgxDmcFirmwareDataRecord, 1); - data_rcd->data = g_bytes_new (row_buf, actual_row_size); - - /* add data record to data record array */ + data_rcd = g_bytes_new (row_buf, row_size_bytes); g_ptr_array_add (seg_rcd->data_records, g_steal_pointer (&data_rcd)); /* increment row data offset */ - row_data_offset += actual_row_size; + row_off += row_size_bytes; } /* add segment record to segment array */ g_ptr_array_add (img_rcd->seg_records, g_steal_pointer (&seg_rcd)); /* increment segment info offset */ - *segment_info_offset += sizeof(FwctSegmentationInfo); + *seg_off += sizeof(FwctSegmentationInfo); } /* check checksum */ - g_checksum_get_digest (csum, hash, &digestlen); - if (memcmp (hash, img_rcd->info_header.img_digest, DMC_HASH_SIZE) != 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "invalid hash"); - return FALSE; + if ((flags & FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM) == 0) { + guint8 csumbuf[DMC_HASH_SIZE] = { 0x0 }; + gsize csumbufsz = sizeof(csumbuf); + g_checksum_get_digest (csum, csumbuf, &csumbufsz); + if (memcmp (csumbuf, img_rcd->img_digest, DMC_HASH_SIZE) != 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid hash"); + return FALSE; + } } /* success */ @@ -190,49 +173,67 @@ static gboolean fu_ccgx_dmc_firmware_parse_image (FuFirmware *firmware, - const guint8 *fw_buf, - gsize fw_bufsz, + guint8 image_count, + const guint8 *buf, + gsize bufsz, + FwupdInstallFlags flags, GError **error) { FuCcgxDmcFirmware *self = FU_CCGX_DMC_FIRMWARE (firmware); - gsize fw_buffer_offset = 0; - gsize img_info_offset = sizeof(FwctInfo); - gsize seg_info_offset = 0; + gsize img_off = sizeof(FwctInfo); + gsize seg_off = sizeof(FwctInfo) + image_count * sizeof(FwctImageInfo); /* set initial segment info offset */ - seg_info_offset = img_info_offset + self->fwct_info.image_count * sizeof(FwctImageInfo); - for (guint32 img_num = 0; img_num < self->fwct_info.image_count; img_num++) { + for (guint32 i = 0; i < image_count; i++) { g_autoptr(FuCcgxDmcFirmwareImageRecord) img_rcd = NULL; - /* set image info offset to fw buffer */ - fw_buffer_offset = img_info_offset; - /* read image info */ img_rcd = g_new0 (FuCcgxDmcFirmwareImageRecord, 1); - if (!fu_memcpy_safe ((guint8 *) &img_rcd->info_header, sizeof(img_rcd->info_header), 0x0, /* dst */ - fw_buf, fw_bufsz, fw_buffer_offset, /* src */ - sizeof(img_rcd->info_header), error)) + if (!fu_common_read_uint8_safe (buf, bufsz, + img_off + G_STRUCT_OFFSET(FwctImageInfo, row_size), + &img_rcd->row_size, error)) return FALSE; - - if (img_rcd->info_header.num_img_segments == 0) { + if (img_rcd->row_size == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid row size 0x%x", + img_rcd->row_size); + return FALSE; + } + if (!fu_common_read_uint32_safe (buf, bufsz, + img_off + G_STRUCT_OFFSET(FwctImageInfo, img_offset), + &img_rcd->img_offset, G_LITTLE_ENDIAN, error)) + return FALSE; + if (!fu_common_read_uint8_safe (buf, bufsz, + img_off + G_STRUCT_OFFSET(FwctImageInfo, num_img_segments), + &img_rcd->num_img_segments, error)) + return FALSE; + if (img_rcd->num_img_segments == 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "invalid segment number = %d", - img_rcd->info_header.num_img_segments); + img_rcd->num_img_segments); return FALSE; } + if (!fu_memcpy_safe ((guint8 *) &img_rcd->img_digest, + sizeof(img_rcd->img_digest), 0x0, /* dst */ + buf, bufsz, + img_off + G_STRUCT_OFFSET(FwctImageInfo, img_digest), /* src */ + sizeof(img_rcd->img_digest), error)) + return FALSE; /* parse segment */ - if (!fu_ccgx_dmc_firmware_parse_segment (firmware, fw_buf, fw_bufsz, img_rcd, - &seg_info_offset, error)) + if (!fu_ccgx_dmc_firmware_parse_segment (firmware, buf, bufsz, img_rcd, + &seg_off, flags, error)) return FALSE; /* add image record to image record array */ g_ptr_array_add (self->image_records, g_steal_pointer (&img_rcd)); /* increment image offset */ - img_info_offset += sizeof(FwctImageInfo); + img_off += sizeof(FwctImageInfo); } return TRUE; @@ -247,81 +248,90 @@ GError **error) { FuCcgxDmcFirmware *self = FU_CCGX_DMC_FIRMWARE (firmware); - gsize fw_bufsz = 0; - guint16 custom_meta_bufsz = 0; - const guint8 *fw_buf = g_bytes_get_data (fw, &fw_bufsz); - g_autofree guint8 *custom_meta_buf = NULL; - g_autofree guint8 *fwct_buf = NULL; + gsize bufsz = 0; + guint16 hdr_size = 0; + guint16 mdbufsz = 0; + guint32 hdr_composite_version = 0; + guint32 hdr_signature = 0; + guint8 hdr_image_count = 0; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); g_autoptr(FuFirmwareImage) img = fu_firmware_image_new (fw); - /* read fwct info */ - if (!fu_memcpy_safe ((guint8 *) &self->fwct_info, sizeof(self->fwct_info), 0x0, /* dst */ - fw_buf, fw_bufsz, 0, /* src */ - sizeof(self->fwct_info), error)) - return FALSE; - /* check for 'F' 'W' 'C' 'T' in signature */ - if (self->fwct_info.signature != DMC_FWCT_SIGN) { + if (!fu_common_read_uint32_safe (buf, bufsz, 0x0, + &hdr_signature, + G_LITTLE_ENDIAN, error)) + return FALSE; + if (hdr_signature != DMC_FWCT_SIGN) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "invalid dmc signature, expected 0x%04X got 0x%04X", (guint32) DMC_FWCT_SIGN, - (guint32) self->fwct_info.signature); + (guint32) hdr_signature); return FALSE; } + /* check fwct size */ - if (self->fwct_info.size > DMC_FWCT_MAX_SIZE || - self->fwct_info.size == 0) { + if (!fu_common_read_uint16_safe (buf, bufsz, + G_STRUCT_OFFSET(FwctInfo, size), + &hdr_size, G_LITTLE_ENDIAN, error)) + return FALSE; + if (hdr_size > DMC_FWCT_MAX_SIZE || + hdr_size == 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, - "invalid dmc fwct size, expected equal to or less than %u, got %u", - (guint32) DMC_FWCT_MAX_SIZE, - (guint32) self->fwct_info.size); + "invalid dmc fwct size, expected <= 0x%x, got 0x%x", + (guint) DMC_FWCT_MAX_SIZE, + (guint) hdr_size); return FALSE; } /* set version */ - if (self->fwct_info.composite_version != 0) { + if (!fu_common_read_uint32_safe (buf, bufsz, + G_STRUCT_OFFSET(FwctInfo, composite_version), + &hdr_composite_version, G_LITTLE_ENDIAN, error)) + return FALSE; + if (hdr_composite_version != 0) { g_autofree gchar *ver = NULL; - ver = fu_common_version_from_uint32 (self->fwct_info.composite_version, + ver = fu_common_version_from_uint32 (hdr_composite_version, FWUPD_VERSION_FORMAT_QUAD); fu_firmware_set_version (firmware, ver); + fu_firmware_set_version_raw (firmware, hdr_composite_version); } /* read fwct data */ - fwct_buf = g_malloc0 (self->fwct_info.size); - if (!fu_memcpy_safe ((guint8 *) fwct_buf, self->fwct_info.size, 0x0, /* dst */ - fw_buf, fw_bufsz, 0, /* src */ - self->fwct_info.size, error)) + self->fwct_blob = fu_common_bytes_new_offset (fw, 0x0, hdr_size, error); + if (self->fwct_blob == NULL) return FALSE; - /* create fwct binary */ - self->fwct_blob = g_bytes_new (fwct_buf, self->fwct_info.size); - /* create custom meta binary */ - if (!fu_common_read_uint16_safe (fw_buf, fw_bufsz, self->fwct_info.size, &custom_meta_bufsz, - G_LITTLE_ENDIAN,error)) + if (!fu_common_read_uint16_safe (buf, bufsz, hdr_size, &mdbufsz, + G_LITTLE_ENDIAN, error)) { + g_prefix_error (error, "failed to read metadata size: "); return FALSE; - - if (custom_meta_bufsz > 0) { - /* alloc custom meta buffer */ - custom_meta_buf = g_malloc0 (custom_meta_bufsz); - /* read custom metadata */ - if (!fu_memcpy_safe ((guint8 *)custom_meta_buf, custom_meta_bufsz, 0x0, /* dst */ - fw_buf, fw_bufsz, self->fwct_info.size + 2, /* src */ - custom_meta_bufsz, error)) + } + if (mdbufsz > 0) { + self->custom_meta_blob = fu_common_bytes_new_offset (fw, + hdr_size + 2, + mdbufsz, + error); + if (self->custom_meta_blob == NULL) return FALSE; - self->custom_meta_blob = g_bytes_new (custom_meta_buf, custom_meta_bufsz); } /* set row data start offset */ - self->row_data_offset_start = self->fwct_info.size + DMC_CUSTOM_META_LENGTH_FIELD_SIZE + custom_meta_bufsz; - self->fw_data_size = fw_bufsz - self->row_data_offset_start; + self->row_data_offset_start = hdr_size + DMC_CUSTOM_META_LENGTH_FIELD_SIZE + mdbufsz; + self->fw_data_size = bufsz - self->row_data_offset_start; /* parse image */ - if (!fu_ccgx_dmc_firmware_parse_image (firmware, fw_buf, fw_bufsz, error)) + if (!fu_common_read_uint8_safe (buf, bufsz, + G_STRUCT_OFFSET(FwctInfo, image_count), + &hdr_image_count, error)) + return FALSE; + if (!fu_ccgx_dmc_firmware_parse_image (firmware, hdr_image_count, + buf, bufsz, flags, error)) return FALSE; /* add something, although we'll use the records for the update */ @@ -330,10 +340,106 @@ return TRUE; } +static GBytes * +fu_ccgx_dmc_firmware_write (FuFirmware *firmware, GError **error) +{ + g_autoptr(GByteArray) buf = g_byte_array_new (); + g_autoptr(GPtrArray) images = fu_firmware_get_images (firmware); + + /* add header */ + fu_byte_array_append_uint32 (buf, DMC_FWCT_SIGN, G_LITTLE_ENDIAN); + fu_byte_array_append_uint16 (buf, + sizeof(FwctInfo) + (images->len * + (sizeof(FwctImageInfo) + + sizeof(FwctSegmentationInfo))), /* size */ + G_LITTLE_ENDIAN); + fu_byte_array_append_uint8 (buf, 0x0); /* checksum, unused */ + fu_byte_array_append_uint8 (buf, 0x2); /* version */ + fu_byte_array_append_uint8 (buf, 0x3); /* custom_meta_type */ + fu_byte_array_append_uint8 (buf, 0x1); /* cdtt_version */ + fu_byte_array_append_uint16 (buf, 0x0, G_LITTLE_ENDIAN); /* vid, unused */ + fu_byte_array_append_uint16 (buf, 0x0, G_LITTLE_ENDIAN); /* pid, unused */ + fu_byte_array_append_uint16 (buf, 0x1, G_LITTLE_ENDIAN); /* device_id */ + for (guint j = 0; j < 16; j++) + fu_byte_array_append_uint8 (buf, 0x0); /* reserv0 */ + fu_byte_array_append_uint32 (buf, fu_firmware_get_version_raw (firmware), G_LITTLE_ENDIAN); + fu_byte_array_append_uint8 (buf, images->len); + for (guint j = 0; j < 3; j++) + fu_byte_array_append_uint8 (buf, 0x0); /* reserv1 */ + + /* add image headers */ + for (guint i = 0; i < images->len; i++) { + fu_byte_array_append_uint8 (buf, 0x2); /* device_type, unknown */ + fu_byte_array_append_uint8 (buf, 0x1); /* img_type, unknown */ + fu_byte_array_append_uint8 (buf, 0x0); /* comp_id, unknown */ + fu_byte_array_append_uint8 (buf, 0x1); /* row_size, multiplier for num_rows */ + for (guint j = 0; j < 4; j++) + fu_byte_array_append_uint8 (buf, 0x0); /* reserv0 */ + fu_byte_array_append_uint32 (buf, 0x330006d2, G_LITTLE_ENDIAN); /* fw_version, hardcoded */ + fu_byte_array_append_uint32 (buf, 0x14136161, G_LITTLE_ENDIAN); /* app_version, hardcoded */ + fu_byte_array_append_uint32 (buf, 0x0, G_LITTLE_ENDIAN); /* start of element data */ + fu_byte_array_append_uint32 (buf, 0x0, G_LITTLE_ENDIAN); /* img_size */ + for (guint j = 0; j < 32; j++) + fu_byte_array_append_uint8 (buf, 0x0); /* img_digest */ + fu_byte_array_append_uint8 (buf, 0x1); /* num_img_segments */ + for (guint j = 0; j < 3; j++) + fu_byte_array_append_uint8 (buf, 0x0); /* reserv1 */ + } + + /* add segments */ + for (guint i = 0; i < images->len; i++) { + FuFirmwareImage *img = g_ptr_array_index (images, i); + g_autoptr(GBytes) img_bytes = fu_firmware_image_get_bytes (img); + g_autoptr(GPtrArray) chunks = fu_chunk_array_new_from_bytes (img_bytes, 0x0, 0x0, 64); + fu_byte_array_append_uint8 (buf, 0x0); /* img_id */ + fu_byte_array_append_uint8 (buf, 0x0); /* type */ + fu_byte_array_append_uint16 (buf, 0x0, G_LITTLE_ENDIAN); /* start_row, unknown */ + fu_byte_array_append_uint16 (buf, MAX (chunks->len, 1), G_LITTLE_ENDIAN); /* num_rows */ + for (guint j = 0; j < 2; j++) + fu_byte_array_append_uint8 (buf, 0x0); /* reserv0 */ + } + + /* metadata */ + fu_byte_array_append_uint16 (buf, 0x1, G_LITTLE_ENDIAN); + fu_byte_array_append_uint8 (buf, 0xff); + + /* add image headers */ + for (guint i = 0; i < images->len; i++) { + FuFirmwareImage *img = g_ptr_array_index (images, i); + gsize csumbufsz = DMC_HASH_SIZE; + gsize img_offset = sizeof(FwctInfo) + (i * sizeof(FwctImageInfo)); + guint8 csumbuf[DMC_HASH_SIZE] = { 0x0 }; + g_autoptr(GChecksum) csum = g_checksum_new (G_CHECKSUM_SHA256); + g_autoptr(GBytes) img_bytes = fu_firmware_image_get_bytes (img); + g_autoptr(GBytes) img_padded = NULL; + g_autoptr(GPtrArray) chunks = NULL; + + chunks = fu_chunk_array_new_from_bytes (img_bytes, 0x0, 0x0, 64); + img_padded = fu_common_bytes_pad (img_bytes, MAX (chunks->len, 1) * 64); + g_byte_array_append (buf, + g_bytes_get_data (img_padded, NULL), + g_bytes_get_size (img_padded)); + g_checksum_update (csum, + (const guchar *) g_bytes_get_data (img_padded, NULL), + g_bytes_get_size (img_padded)); + g_checksum_get_digest (csum, csumbuf, &csumbufsz); + + /* update checksum */ + if (!fu_memcpy_safe (buf->data, buf->len, /* dst */ + img_offset + G_STRUCT_OFFSET(FwctImageInfo, img_digest), + csumbuf, sizeof(csumbuf), 0x0, /* src */ + sizeof(csumbuf), error)) + return NULL; + } + + return g_byte_array_free_to_bytes (g_steal_pointer (&buf)); +} + static void fu_ccgx_dmc_firmware_init (FuCcgxDmcFirmware *self) { self->image_records = g_ptr_array_new_with_free_func ((GFreeFunc) fu_ccgx_dmc_firmware_image_record_free); + fu_firmware_add_flag (FU_FIRMWARE (self), FU_FIRMWARE_FLAG_HAS_CHECKSUM); } static void @@ -358,6 +464,7 @@ FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); object_class->finalize = fu_ccgx_dmc_firmware_finalize; klass_firmware->parse = fu_ccgx_dmc_firmware_parse; + klass_firmware->write = fu_ccgx_dmc_firmware_write; klass_firmware->to_string = fu_ccgx_dmc_firmware_to_string; } diff -Nru fwupd-1.4.5/plugins/ccgx/fu-ccgx-dmc-firmware.h fwupd-1.5.8/plugins/ccgx/fu-ccgx-dmc-firmware.h --- fwupd-1.4.5/plugins/ccgx/fu-ccgx-dmc-firmware.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/ccgx/fu-ccgx-dmc-firmware.h 2021-03-31 20:08:32.000000000 +0000 @@ -14,16 +14,16 @@ G_DECLARE_FINAL_TYPE (FuCcgxDmcFirmware, fu_ccgx_dmc_firmware, FU,CCGX_DMC_FIRMWARE, FuFirmware) typedef struct { - GBytes *data; -} FuCcgxDmcFirmwareDataRecord; - -typedef struct { - FwctSegmentationInfo info_header; + guint16 start_row; + guint16 num_rows; GPtrArray *data_records; } FuCcgxDmcFirmwareSegmentRecord; typedef struct { - FwctImageInfo info_header; + guint8 row_size; + guint32 img_offset; + guint8 img_digest[32]; + guint8 num_img_segments; GPtrArray *seg_records; } FuCcgxDmcFirmwareImageRecord; @@ -31,5 +31,4 @@ GPtrArray *fu_ccgx_dmc_firmware_get_image_records (FuCcgxDmcFirmware *self); GBytes *fu_ccgx_dmc_firmware_get_fwct_record (FuCcgxDmcFirmware *self); GBytes *fu_ccgx_dmc_firmware_get_custom_meta_record (FuCcgxDmcFirmware *self); -FwctInfo *fu_ccgx_dmc_firmware_get_fwct_info (FuCcgxDmcFirmware *self); guint32 fu_ccgx_dmc_firmware_get_fw_data_size (FuCcgxDmcFirmware *self); diff -Nru fwupd-1.4.5/plugins/ccgx/fu-ccgx-firmware.c fwupd-1.5.8/plugins/ccgx/fu-ccgx-firmware.c --- fwupd-1.4.5/plugins/ccgx/fu-ccgx-firmware.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/ccgx/fu-ccgx-firmware.c 2021-03-31 20:08:32.000000000 +0000 @@ -7,6 +7,8 @@ #include "config.h" +#include + #include "fu-common.h" #include "fu-common-version.h" #include "fu-firmware-common.h" @@ -77,29 +79,25 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuCcgxFirmwareRecord, fu_ccgx_firmware_record_free) static gboolean -fu_ccgx_firmware_add_record (FuCcgxFirmware *self, const gchar *line, GError **error) +fu_ccgx_firmware_add_record (FuCcgxFirmware *self, + const gchar *line, + FwupdInstallFlags flags, + GError **error) { guint16 linesz = strlen (line); guint16 buflen; - guint8 checksum_file; guint8 checksum_calc = 0; g_autoptr(FuCcgxFirmwareRecord) rcd = NULL; g_autoptr(GByteArray) data = g_byte_array_new (); - /* https://community.cypress.com/docs/DOC-10562 */ - if (linesz < 12) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "invalid record, expected >= 12 chars"); - return FALSE; - } - - /* parse */ + /* parse according to https://community.cypress.com/docs/DOC-10562 */ rcd = g_new0 (FuCcgxFirmwareRecord, 1); - rcd->array_id = fu_firmware_strparse_uint8 (line + 0); - rcd->row_number = fu_firmware_strparse_uint16 (line + 2); - buflen = fu_firmware_strparse_uint16 (line + 6); + if (!fu_firmware_strparse_uint8_safe (line, linesz, 0, &rcd->array_id, error)) + return FALSE; + if (!fu_firmware_strparse_uint16_safe (line, linesz, 2, &rcd->row_number, error)) + return FALSE; + if (!fu_firmware_strparse_uint16_safe (line, linesz, 6, &buflen, error)) + return FALSE; if (linesz != (buflen * 2) + 12) { g_set_error (error, FWUPD_ERROR, @@ -111,26 +109,36 @@ /* parse payload, adding checksum */ for (guint i = 0; i < buflen; i++) { - guint8 tmp = fu_firmware_strparse_uint8 (line + 10 + (i * 2)); + guint8 tmp = 0; + if (!fu_firmware_strparse_uint8_safe (line, linesz, 10 + (i * 2), &tmp, error)) + return FALSE; fu_byte_array_append_uint8 (data, tmp); checksum_calc += tmp; } rcd->data = g_byte_array_free_to_bytes (g_steal_pointer (&data)); /* verify 2s complement checksum */ - checksum_file = fu_firmware_strparse_uint8 (line + (buflen * 2) + 10); - for (guint i = 0; i < 5; i++) { - guint8 tmp = fu_firmware_strparse_uint8 (line + (i * 2)); - checksum_calc += tmp; - } - checksum_calc = 1 + ~checksum_calc; - if (checksum_file != checksum_calc) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "checksum invalid, got %02x, expected %02x", - checksum_calc, checksum_file); - return FALSE; + if ((flags & FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM) == 0) { + guint8 checksum_file; + if (!fu_firmware_strparse_uint8_safe (line, linesz, (buflen * 2) + 10, + &checksum_file, error)) + return FALSE; + for (guint i = 0; i < 5; i++) { + guint8 tmp = 0; + if (!fu_firmware_strparse_uint8_safe (line, linesz, i * 2, + &tmp, error)) + return FALSE; + checksum_calc += tmp; + } + checksum_calc = 1 + ~checksum_calc; + if (checksum_file != checksum_calc) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "checksum invalid, got %02x, expected %02x", + checksum_calc, checksum_file); + return FALSE; + } } /* success */ @@ -138,8 +146,22 @@ return TRUE; } +static guint8 +fu_ccgx_firmware_record_calc_checksum (FuCcgxFirmwareRecord *rcd) +{ + guint8 csum = 0x0; + gsize bufsz = 0; + const guint8 *buf = g_bytes_get_data (rcd->data, &bufsz); + for (gsize j = 0; j < bufsz; j++) + csum += buf[j]; + return csum; +} + static gboolean -fu_ccgx_firmware_parse_md_block (FuCcgxFirmware *self, FuFirmwareImage *img, GError **error) +fu_ccgx_firmware_parse_md_block (FuCcgxFirmware *self, + FuFirmwareImage *img, + FwupdInstallFlags flags, + GError **error) { FuCcgxFirmwareRecord *rcd; CCGxMetaData metadata; @@ -150,7 +172,6 @@ guint32 rcd_version_idx = 0; guint32 version = 0; guint8 checksum_calc = 0; - g_autofree gchar *version_str = NULL; /* sanity check */ if (self->records->len == 0) { @@ -198,10 +219,8 @@ } for (guint i = 0; i < self->records->len - 1; i++) { rcd = g_ptr_array_index (self->records, i); - buf = g_bytes_get_data (rcd->data, &bufsz); - fw_size += bufsz; - for (gsize j = 0; j < bufsz; j++) - checksum_calc += buf[j]; + checksum_calc += fu_ccgx_firmware_record_calc_checksum (rcd); + fw_size += g_bytes_get_size (rcd->data); } if (fw_size != metadata.fw_size) { g_set_error (error, @@ -212,33 +231,38 @@ return FALSE; } checksum_calc = 1 + ~checksum_calc; - if (metadata.fw_checksum != checksum_calc) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "checksum invalid, got %02x, expected %02x", - checksum_calc, metadata.fw_checksum); - return FALSE; + if ((flags & FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM) == 0) { + if (metadata.fw_checksum != checksum_calc) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "checksum invalid, got %02x, expected %02x", + checksum_calc, metadata.fw_checksum); + return FALSE; + } } - /* get version */ + /* get version if enough data */ rcd_version_idx = CCGX_APP_VERSION_OFFSET / bufsz; - if (rcd_version_idx >= self->records->len) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "invalid version index of %02x", - rcd_version_idx); - return FALSE; + if (rcd_version_idx < self->records->len) { + g_autofree gchar *version_str = NULL; + rcd = g_ptr_array_index (self->records, rcd_version_idx); + buf = g_bytes_get_data (rcd->data, &bufsz); + if (bufsz == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "metadata record had zero size"); + return FALSE; + } + if (!fu_common_read_uint32_safe (buf, bufsz, CCGX_APP_VERSION_OFFSET % bufsz, + &version, G_LITTLE_ENDIAN, error)) + return FALSE; + self->app_type = version & 0xffff; + version_str = fu_ccgx_version_to_string (version); + fu_firmware_set_version (FU_FIRMWARE (self), version_str); + fu_firmware_set_version_raw (FU_FIRMWARE (self), version); } - rcd = g_ptr_array_index (self->records, rcd_version_idx); - buf = g_bytes_get_data (rcd->data, &bufsz); - if (!fu_common_read_uint32_safe (buf, bufsz, CCGX_APP_VERSION_OFFSET % bufsz, - &version, G_LITTLE_ENDIAN, error)) - return FALSE; - self->app_type = version & 0xffff; - version_str = fu_ccgx_version_to_string (version); - fu_firmware_set_version (FU_FIRMWARE (self), version_str); /* work out the FWMode */ if (self->records->len > 0) { @@ -260,29 +284,49 @@ GError **error) { FuCcgxFirmware *self = FU_CCGX_FIRMWARE (firmware); + gsize linesz; gsize sz = 0; + guint32 device_id = 0; const gchar *data = g_bytes_get_data (fw, &sz); g_auto(GStrv) lines = fu_common_strnsplit (data, sz, "\n", -1); g_autoptr(FuFirmwareImage) img = fu_firmware_image_new (fw); /* parse header */ + if (lines[0] == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid header, expected == 12 chars"); + return FALSE; + } g_strdelimit (lines[0], "\r\x1a", '\0'); - if (lines[0] == NULL || strlen (lines[0]) != 12) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "invalid header, expected == 12 chars -- got %s", - lines[0]); + linesz = strlen (lines[0]); + if (linesz != 12) { + g_autofree gchar *strsafe = fu_common_strsafe (lines[0], 12); + if (strsafe != NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid header, expected == 12 chars -- got %s", + strsafe); + return FALSE; + } + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid header, expected == 12 chars"); return FALSE; } - self->silicon_id = fu_firmware_strparse_uint32 (lines[0]) >> 16; + if (!fu_firmware_strparse_uint32_safe (lines[0], linesz, 0, &device_id, error)) + return FALSE; + self->silicon_id = device_id >> 16; /* parse data */ for (guint ln = 1; lines[ln] != NULL; ln++) { g_strdelimit (lines[ln], "\r\x1a", '\0'); if (lines[ln][0] == '\0') continue; - if (!fu_ccgx_firmware_add_record (self, lines[ln] + 1, error)) { + if (!fu_ccgx_firmware_add_record (self, lines[ln] + 1, flags, error)) { g_prefix_error (error, "error on line %u: ", ln + 1); return FALSE; } @@ -295,8 +339,10 @@ } /* parse metadata block */ - if (!fu_ccgx_firmware_parse_md_block (self, img, error)) + if (!fu_ccgx_firmware_parse_md_block (self, img, flags, error)) { + g_prefix_error (error, "failed to parse metadata: "); return FALSE; + } /* add something, although we'll use the records for the update */ fu_firmware_add_image (firmware, img); @@ -304,9 +350,116 @@ } static void +fu_ccgx_firmware_write_record (GString *str, + guint8 array_id, + guint8 row_number, + const guint8 *buf, + guint16 bufsz) +{ + guint8 checksum_calc = 0xff; + g_autoptr(GString) datastr = g_string_new (NULL); + + /* offset for bootloader perhaps? */ + row_number += 0xE; + + checksum_calc += array_id; + checksum_calc += row_number; + checksum_calc += bufsz & 0xff; + checksum_calc += (bufsz >> 8) & 0xff; + for (guint j = 0; j < bufsz; j++) { + g_string_append_printf (datastr, "%02X", buf[j]); + checksum_calc += buf[j]; + } + g_string_append_printf (str, ":%02X%04X%04X%s%02X\n", + array_id, row_number, bufsz, datastr->str, + (guint) ((guint8) ~checksum_calc)); +} + +static GBytes * +fu_ccgx_firmware_write (FuFirmware *firmware, GError **error) +{ + FuCcgxFirmware *self = FU_CCGX_FIRMWARE (firmware); + CCGxMetaData metadata = { 0x0 }; + gsize fwbufsz = 0; + guint8 checksum_img = 0xff; + const guint8 *fwbuf; + g_autoptr(GByteArray) mdbuf = g_byte_array_new (); + g_autoptr(GBytes) fw = NULL; + g_autoptr(GPtrArray) chunks = NULL; + g_autoptr(GPtrArray) images = fu_firmware_get_images (firmware); + g_autoptr(GString) str = g_string_new (NULL); + + /* can only contain one image */ + if (images->len != 1) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "only supports writing one image"); + return NULL; + } + + /* header record */ + g_string_append_printf (str, "%04X%04X%02X%02X\n", + self->silicon_id, (guint) 0x11AF, /* SiliconID */ + (guint) 0x0, /* SiliconRev */ + (guint) 0x0); /* Checksum, or 0x0 */ + + /* add image in chunks */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return NULL; + chunks = fu_chunk_array_new_from_bytes (fw, 0x0, 0x0, 0x100); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + fu_ccgx_firmware_write_record (str, 0x0, i, + fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk)); + } + + /* add metadata */ + fwbuf = g_bytes_get_data (fw, &fwbufsz); + for (guint j = 0; j < fwbufsz; j++) + checksum_img += fwbuf[j]; + metadata.fw_checksum = ~checksum_img; + metadata.fw_entry = 0x0; /* unknown */ + metadata.last_boot_row = 0x13; + metadata.fw_size = fwbufsz; + metadata.metadata_valid = CCGX_METADATA_VALID_SIG; + metadata.boot_seq = 0x0; /* unknown */ + + /* copy into place */ + fu_byte_array_set_size (mdbuf, 0x80); + if (!fu_memcpy_safe (mdbuf->data, mdbuf->len, 0x40, /* dst */ + (const guint8 *) &metadata, sizeof(metadata), 0x0, /* src */ + sizeof(metadata), error)) + return NULL; + fu_ccgx_firmware_write_record (str, 0x0, 0xFE, /* FW2: penultimate row */ + mdbuf->data, mdbuf->len); + + return g_string_free_to_bytes (g_steal_pointer (&str)); +} + +static gboolean +fu_ccgx_firmware_build (FuFirmware *firmware, XbNode *n, GError **error) +{ + FuCcgxFirmware *self = FU_CCGX_FIRMWARE (firmware); + guint64 tmp; + + /* optional properties */ + tmp = xb_node_query_text_as_uint (n, "silicon_id", NULL); + if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT16) + self->silicon_id = tmp; + + /* success */ + return TRUE; +} + +static void fu_ccgx_firmware_init (FuCcgxFirmware *self) { self->records = g_ptr_array_new_with_free_func ((GFreeFunc) fu_ccgx_firmware_record_free); + fu_firmware_add_flag (FU_FIRMWARE (self), FU_FIRMWARE_FLAG_HAS_CHECKSUM); + fu_firmware_add_flag (FU_FIRMWARE (self), FU_FIRMWARE_FLAG_HAS_VID_PID); } static void @@ -324,6 +477,8 @@ FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); object_class->finalize = fu_ccgx_firmware_finalize; klass_firmware->parse = fu_ccgx_firmware_parse; + klass_firmware->write = fu_ccgx_firmware_write; + klass_firmware->build = fu_ccgx_firmware_build; klass_firmware->to_string = fu_ccgx_firmware_to_string; } diff -Nru fwupd-1.4.5/plugins/ccgx/fu-ccgx-hid-device.c fwupd-1.5.8/plugins/ccgx/fu-ccgx-hid-device.c --- fwupd-1.4.5/plugins/ccgx/fu-ccgx-hid-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/ccgx/fu-ccgx-hid-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -75,9 +75,10 @@ static void fu_ccgx_hid_device_init (FuCcgxHidDevice *self) { - fu_device_set_protocol (FU_DEVICE (self), "com.cypress.ccgx"); + fu_device_add_protocol (FU_DEVICE (self), "com.cypress.ccgx"); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_REQUIRE_AC); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_WILL_DISAPPEAR); + fu_device_add_internal_flag (FU_DEVICE (self), FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID); fu_device_retry_set_delay (FU_DEVICE (self), FU_CCGX_HID_DEVICE_RETRY_DELAY); } diff -Nru fwupd-1.4.5/plugins/ccgx/fu-ccgx-hpi-common.h fwupd-1.5.8/plugins/ccgx/fu-ccgx-hpi-common.h --- fwupd-1.4.5/plugins/ccgx/fu-ccgx-hpi-common.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/ccgx/fu-ccgx-hpi-common.h 2021-03-31 20:08:32.000000000 +0000 @@ -25,7 +25,7 @@ #define CY_I2C_ENABLE_PRECISE_TIMING 1 #define CY_I2C_EVENT_NOTIFICATION_LEN 3 -#define PD_I2C_SLAVE_ADDRESS 0x08 +#define PD_I2C_TARGET_ADDRESS 0x08 /* timeout (ms) for USB I2C communication */ #define FU_CCGX_HPI_WAIT_TIMEOUT 5000 @@ -60,11 +60,11 @@ * length = 16, data_out = 16 byte configuration information */ CY_I2C_WRITE_CMD, /* perform I2C write operation * value = bit0 - start, bit1 - stop, bit3 - start on idle, - * bits[14:8] - slave address, bit15 - scbIndex. length = 0 the + * bits[14:8] - target address, bit15 - scbIndex. length = 0 the * data is provided over the bulk endpoints */ CY_I2C_READ_CMD, /* rerform I2C read operation. * value = bit0 - start, bit1 - stop, bit2 - Nak last byte, - * bit3 - start on idle, bits[14:8] - slave address, bit15 - scbIndex, + * bit3 - start on idle, bits[14:8] - target address, bit15 - scbIndex, * length = 0. The data is provided over the bulk endpoints */ CY_I2C_GET_STATUS_CMD, /* retrieve the I2C bus status. * value = bit0 - 0: TX 1: RX, bit15 - scbIndex, length = 3, @@ -107,10 +107,10 @@ typedef struct __attribute__((packed)) { guint32 frequency; /* frequency of operation. Only valid values are 100KHz and 400KHz */ - guint8 slave_address; /* slave address to be used when in slave mode */ + guint8 target_address; /* target address to be used when in target mode */ guint8 is_msb_first; /* whether to transmit most significant bit first */ - guint8 is_master; /* whether to block is to be configured as a master*/ - guint8 s_ignore; /* ignore general call in slave mode */ + guint8 is_initiator; /* whether to block is to be configured as a initiator */ + guint8 s_ignore; /* ignore general call in target mode */ guint8 is_clock_stretch; /* whether to stretch clock in case of no FIFO availability */ guint8 is_loop_back; /* whether to loop back TX data to RX. Valid only for debug purposes */ guint8 reserved[6]; diff -Nru fwupd-1.4.5/plugins/ccgx/fu-ccgx-hpi-device.c fwupd-1.5.8/plugins/ccgx/fu-ccgx-hpi-device.c --- fwupd-1.4.5/plugins/ccgx/fu-ccgx-hpi-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/ccgx/fu-ccgx-hpi-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -7,6 +7,8 @@ #include "config.h" +#include + #include "fu-chunk.h" #include "fu-ccgx-common.h" @@ -26,7 +28,7 @@ guint8 num_ports; /* max number of ports */ FWMode fw_mode; FWImageType fw_image_type; - guint8 slave_address; + guint8 target_address; guint8 ep_bulk_in; guint8 ep_bulk_out; guint8 ep_intr_in; @@ -68,9 +70,9 @@ fu_common_string_append_kx (str, idt, "EpBulkOut", self->ep_bulk_out); fu_common_string_append_kx (str, idt, "EpIntrIn", self->ep_intr_in); if (self->flash_row_size > 0) - fu_common_string_append_kx (str, idt, "FlashRowSize", self->flash_row_size); + fu_common_string_append_kx (str, idt, "CcgxFlashRowSize", self->flash_row_size); if (self->flash_size > 0) - fu_common_string_append_kx (str, idt, "FlashSize", self->flash_size); + fu_common_string_append_kx (str, idt, "CcgxFlashSize", self->flash_size); } typedef struct { @@ -273,19 +275,19 @@ CyI2CDataConfigBits cfg_bits, GError **error) { - guint8 slave_address = 0; + guint8 target_address = 0; if (!fu_ccgx_hpi_device_check_i2c_status (self, CY_I2C_MODE_READ, error)) { g_prefix_error (error, "i2c read error: "); return FALSE; } - slave_address = (self->slave_address & 0x7F) | (self->scb_index << 7); + target_address = (self->target_address & 0x7F) | (self->scb_index << 7); if (!g_usb_device_control_transfer (fu_usb_device_get_dev (FU_USB_DEVICE (self)), G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, G_USB_DEVICE_REQUEST_TYPE_VENDOR, G_USB_DEVICE_RECIPIENT_DEVICE, CY_I2C_READ_CMD, - (((guint16) slave_address) << 8) | cfg_bits, + (((guint16) target_address) << 8) | cfg_bits, bufsz, NULL, 0x0, NULL, FU_CCGX_HPI_WAIT_TIMEOUT, NULL, error)) { @@ -316,20 +318,19 @@ CyI2CDataConfigBits cfg_bits, GError **error) { - guint8 slave_address; - g_autoptr(GError) error_local = NULL; + guint8 target_address; if (!fu_ccgx_hpi_device_check_i2c_status (self, CY_I2C_MODE_WRITE, error)) { g_prefix_error (error, "i2c get status error: "); return FALSE; } - slave_address = (self->slave_address & 0x7F) | (self->scb_index << 7); + target_address = (self->target_address & 0x7F) | (self->scb_index << 7); if (!g_usb_device_control_transfer (fu_usb_device_get_dev (FU_USB_DEVICE (self)), G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, G_USB_DEVICE_REQUEST_TYPE_VENDOR, G_USB_DEVICE_RECIPIENT_DEVICE, CY_I2C_WRITE_CMD, - ((guint16) slave_address << 8) | (cfg_bits & CY_I2C_DATA_CONFIG_STOP), + ((guint16) target_address << 8) | (cfg_bits & CY_I2C_DATA_CONFIG_STOP), bufsz, /* idx */ NULL, 0x0, NULL, FU_CCGX_HPI_WAIT_TIMEOUT, @@ -360,20 +361,20 @@ CyI2CDataConfigBits cfg_bits, GError **error) { - guint8 slave_address = 0; + guint8 target_address = 0; g_autoptr(GError) error_local = NULL; if (!fu_ccgx_hpi_device_check_i2c_status (self, CY_I2C_MODE_WRITE, error)) { g_prefix_error (error, "i2c write error: "); return FALSE; } - slave_address = (self->slave_address & 0x7F) | (self->scb_index << 7); + target_address = (self->target_address & 0x7F) | (self->scb_index << 7); if (!g_usb_device_control_transfer (fu_usb_device_get_dev (FU_USB_DEVICE (self)), G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, G_USB_DEVICE_REQUEST_TYPE_VENDOR, G_USB_DEVICE_RECIPIENT_DEVICE, CY_I2C_WRITE_CMD, - ((guint16) slave_address << 8) | (cfg_bits & CY_I2C_DATA_CONFIG_STOP), + ((guint16) target_address << 8) | (cfg_bits & CY_I2C_DATA_CONFIG_STOP), bufsz, NULL, 0x0, NULL, FU_CCGX_HPI_WAIT_TIMEOUT, NULL, error)) { @@ -539,7 +540,7 @@ reg_addr, buf, sizeof(buf), error)) { - g_prefix_error (error, "read response reg error:"); + g_prefix_error (error, "read response reg error: "); return FALSE; } @@ -555,7 +556,7 @@ event->event_data, event->event_length, error)) { - g_prefix_error (error, "read event data error:"); + g_prefix_error (error, "read event data error: "); return FALSE; } } @@ -565,7 +566,7 @@ CY_PD_REG_RESPONSE_ADDR, buf, sizeof(buf), error)) { - g_prefix_error (error, "read response reg error:"); + g_prefix_error (error, "read response reg error: "); return FALSE; } event->event_code = buf[0]; @@ -577,7 +578,7 @@ event->event_data, event->event_length, error)) { - g_prefix_error (error, "read event data error:"); + g_prefix_error (error, "read event data error: "); return FALSE; } } @@ -882,7 +883,7 @@ /* write data to memory */ addr_tmp = self->hpi_addrsz > 1 ? HPI_DEV_REG_FLASH_MEM : CY_PD_REG_BOOTDATA_MEMORY_ADDR; if (!fu_ccgx_hpi_device_reg_write (self, addr_tmp, helper->buf, helper->bufsz, error)) { - g_prefix_error (error, "write buf to memory error"); + g_prefix_error (error, "write buf to memory error: "); return FALSE; } if (!fu_ccgx_hpi_device_reg_write (self, CY_PD_REG_FLASH_READ_WRITE_ADDR, @@ -897,7 +898,7 @@ &hpi_event, HPI_CMD_COMMAND_RESPONSE_TIME_MS, error)) { - g_prefix_error (error, "write flash resp error"); + g_prefix_error (error, "write flash resp error: "); return FALSE; } if (hpi_event != CY_PD_RESP_SUCCESS) { @@ -975,7 +976,7 @@ } addr_tmp = self->hpi_addrsz > 1 ? HPI_DEV_REG_FLASH_MEM : CY_PD_REG_BOOTDATA_MEMORY_ADDR; if (!fu_ccgx_hpi_device_reg_read (self, addr_tmp, helper->buf, helper->bufsz, error)) { - g_prefix_error (error, "read data from memory error"); + g_prefix_error (error, "read data from memory error: "); return FALSE; } return TRUE; @@ -1083,7 +1084,7 @@ self->silicon_id, fw_silicon_id); return NULL; } - if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + if ((flags & FWUPD_INSTALL_FLAG_IGNORE_VID_PID) == 0) { fw_app_type = fu_ccgx_firmware_get_app_type (FU_CCGX_FIRMWARE (firmware)); if (fw_app_type != self->fw_app_type) { g_set_error (error, @@ -1376,7 +1377,7 @@ return FALSE; } i2c_config.frequency = FU_CCGX_HPI_FREQ; - i2c_config.is_master = TRUE; + i2c_config.is_initiator = TRUE; i2c_config.is_msb_first = TRUE; if (!fu_ccgx_hpi_device_set_i2c_config (self, &i2c_config, error)) { g_prefix_error (error, "set config error: "); @@ -1485,7 +1486,7 @@ "invalid SiliconId"); return FALSE; } - if (g_strcmp0 (key, "FlashRowSize") == 0) { + if (g_strcmp0 (key, "CcgxFlashRowSize") == 0) { guint64 tmp = fu_common_strtoull (value); if (tmp < G_MAXUINT32) { self->flash_row_size = tmp; @@ -1494,10 +1495,10 @@ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, - "invalid FlashRowSize"); + "invalid CcgxFlashRowSize"); return FALSE; } - if (g_strcmp0 (key, "FlashSize") == 0) { + if (g_strcmp0 (key, "CcgxFlashSize") == 0) { guint64 tmp = fu_common_strtoull (value); if (tmp < G_MAXUINT32) { self->flash_size = tmp; @@ -1506,17 +1507,17 @@ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, - "invalid FlashSize"); + "invalid CcgxFlashSize"); return FALSE; } - if (g_strcmp0 (key, "ImageKind") == 0) { + if (g_strcmp0 (key, "CcgxImageKind") == 0) { self->fw_image_type = fu_ccgx_fw_image_type_from_string (value); if (self->fw_image_type != FW_IMAGE_TYPE_UNKNOWN) return TRUE; g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, - "invalid ImageKind"); + "invalid CcgxImageKind"); return FALSE; } g_set_error_literal (error, @@ -1527,11 +1528,16 @@ } static gboolean -fu_ccgx_hpi_device_open (FuUsbDevice *device, GError **error) +fu_ccgx_hpi_device_open (FuDevice *device, GError **error) { FuCcgxHpiDevice *self = FU_CCGX_HPI_DEVICE (device); g_autoptr(GError) error_local = NULL; - if (!g_usb_device_claim_interface (fu_usb_device_get_dev (device), + + /* FuUsbDevice->open */ + if (!FU_DEVICE_CLASS (fu_ccgx_hpi_device_parent_class)->open (device, error)) + return FALSE; + + if (!g_usb_device_claim_interface (fu_usb_device_get_dev (FU_USB_DEVICE (device)), self->inf_num, G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, &error_local)) { @@ -1546,15 +1552,15 @@ } static gboolean -fu_ccgx_hpi_device_close (FuUsbDevice *device, GError **error) +fu_ccgx_hpi_device_close (FuDevice *device, GError **error) { FuCcgxHpiDevice *self = FU_CCGX_HPI_DEVICE (device); g_autoptr(GError) error_local = NULL; /* do not close handle when device restarts */ - if (fu_device_get_status (FU_DEVICE (device)) == FWUPD_STATUS_DEVICE_RESTART) + if (fu_device_get_status (device) == FWUPD_STATUS_DEVICE_RESTART) return TRUE; - if (!g_usb_device_release_interface (fu_usb_device_get_dev (device), + if (!g_usb_device_release_interface (fu_usb_device_get_dev (FU_USB_DEVICE (device)), self->inf_num, G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, &error_local)) { @@ -1565,7 +1571,8 @@ error_local->message); return FALSE; } - return TRUE; + /* FuUsbDevice->close */ + return FU_DEVICE_CLASS (fu_ccgx_hpi_device_parent_class)->close (device, error); } static void @@ -1574,15 +1581,16 @@ self->inf_num = 0x0; self->hpi_addrsz = 1; self->num_ports = 1; - self->slave_address = PD_I2C_SLAVE_ADDRESS; + self->target_address = PD_I2C_TARGET_ADDRESS; self->ep_bulk_out = PD_I2C_USB_EP_BULK_OUT; self->ep_bulk_in = PD_I2C_USB_EP_BULK_IN; self->ep_intr_in = PD_I2C_USB_EP_INTR_IN; - fu_device_set_protocol (FU_DEVICE (self), "com.cypress.ccgx"); + fu_device_add_protocol (FU_DEVICE (self), "com.cypress.ccgx"); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_TRIPLET); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_REQUIRE_AC); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_DUAL_IMAGE); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_SELF_RECOVERY); + fu_device_add_internal_flag (FU_DEVICE (self), FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID); fu_device_retry_set_delay (FU_DEVICE (self), HPI_CMD_RETRY_DELAY); /* we can recover the I²C link using reset */ @@ -1604,7 +1612,6 @@ fu_ccgx_hpi_device_class_init (FuCcgxHpiDeviceClass *klass) { FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); klass_device->to_string = fu_ccgx_hpi_device_to_string; klass_device->write_firmware = fu_ccgx_hpi_write_firmware; klass_device->prepare_firmware = fu_ccgx_hpi_device_prepare_firmware; @@ -1612,6 +1619,6 @@ klass_device->attach = fu_ccgx_hpi_device_attach; klass_device->setup = fu_ccgx_hpi_device_setup; klass_device->set_quirk_kv = fu_ccgx_hpi_device_set_quirk_kv; - klass_usb_device->open = fu_ccgx_hpi_device_open; - klass_usb_device->close = fu_ccgx_hpi_device_close; + klass_device->open = fu_ccgx_hpi_device_open; + klass_device->close = fu_ccgx_hpi_device_close; } diff -Nru fwupd-1.4.5/plugins/ccgx/fu-plugin-ccgx.c fwupd-1.5.8/plugins/ccgx/fu-plugin-ccgx.c --- fwupd-1.4.5/plugins/ccgx/fu-plugin-ccgx.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/ccgx/fu-plugin-ccgx.c 2021-03-31 20:08:32.000000000 +0000 @@ -6,7 +6,6 @@ #include "config.h" -#include "fu-hash.h" #include "fu-plugin-vfuncs.h" #include "fu-ccgx-firmware.h" @@ -19,9 +18,12 @@ fu_plugin_init (FuPlugin *plugin) { fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); - fu_plugin_add_firmware_gtype (plugin, "ccgx", FU_TYPE_CCGX_FIRMWARE); - fu_plugin_add_firmware_gtype (plugin, "ccgx", FU_TYPE_CCGX_DMC_FIRMWARE); + fu_plugin_add_firmware_gtype (plugin, NULL, FU_TYPE_CCGX_FIRMWARE); + fu_plugin_add_firmware_gtype (plugin, NULL, FU_TYPE_CCGX_DMC_FIRMWARE); fu_plugin_set_device_gtype (plugin, FU_TYPE_CCGX_HID_DEVICE); fu_plugin_set_device_gtype (plugin, FU_TYPE_CCGX_HPI_DEVICE); fu_plugin_set_device_gtype (plugin, FU_TYPE_CCGX_DMC_DEVICE); + fu_plugin_add_possible_quirk_key (plugin, "CcgxFlashRowSize"); + fu_plugin_add_possible_quirk_key (plugin, "CcgxFlashSize"); + fu_plugin_add_possible_quirk_key (plugin, "CcgxImageKind"); } diff -Nru fwupd-1.4.5/plugins/ccgx/meson.build fwupd-1.5.8/plugins/ccgx/meson.build --- fwupd-1.4.5/plugins/ccgx/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/ccgx/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,4 @@ +if get_option('gusb') cargs = ['-DG_LOG_DOMAIN="FuPluginCcgx"'] install_data([ @@ -11,14 +12,14 @@ fu_hash, sources : [ 'fu-plugin-ccgx.c', - 'fu-ccgx-common.c', - 'fu-ccgx-firmware.c', + 'fu-ccgx-common.c', # fuzzing + 'fu-ccgx-firmware.c', # fuzzing 'fu-ccgx-hid-device.c', 'fu-ccgx-hpi-common.c', 'fu-ccgx-hpi-device.c', 'fu-ccgx-dmc-device.c', - 'fu-ccgx-dmc-firmware.c', - 'fu-ccgx-dmc-common.c', + 'fu-ccgx-dmc-firmware.c', # fuzzing + 'fu-ccgx-dmc-common.c', # fuzzing ], include_directories : [ root_incdir, @@ -37,3 +38,4 @@ gudev, ], ) +endif diff -Nru fwupd-1.4.5/plugins/ccgx/README.md fwupd-1.5.8/plugins/ccgx/README.md --- fwupd-1.4.5/plugins/ccgx/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/ccgx/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -93,7 +93,22 @@ * `USB\VID_1234&PID_5678&SID_9ABC&APP_DEF1` * `USB\VID_1234&PID_5678&SID_9ABC&APP_DEF1&MODE_FW2` + +Update Behavior +--------------- + +The device usually presents in runtime HID mode, but on detach re-enumerates +with with a DMC or HPI interface. On attach the device again re-enumerates +back to the runtime HID mode. + +For this reason the `REPLUG_MATCH_GUID` internal device flag is used so that +the DMC/HPI and runtime modes are treated as the same device. + Vendor ID Security ------------------ The vendor ID is set from the USB vendor, for example set to `USB:0x04B4` + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff -Nru fwupd-1.4.5/plugins/colorhug/colorhug.quirk fwupd-1.5.8/plugins/colorhug/colorhug.quirk --- fwupd-1.4.5/plugins/colorhug/colorhug.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/colorhug/colorhug.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ # ColorHug1 -[DeviceInstanceId=USB\VID_273F&PID_1000] +[USB\VID_273F&PID_1000] Plugin = colorhug Flags = is-bootloader,self-recovery Guid = 40338ceb-b966-4eae-adae-9c32edfcc484 @@ -8,7 +8,7 @@ CounterpartGuid = USB\VID_273F&PID_1001 InstallDuration = 8 -[DeviceInstanceId=USB\VID_273F&PID_1001] +[USB\VID_273F&PID_1001] Plugin = colorhug Flags = self-recovery Summary = An open source display colorimeter @@ -18,7 +18,7 @@ InstallDuration = 8 # ColorHug2 -[DeviceInstanceId=USB\VID_273F&PID_1004] +[USB\VID_273F&PID_1004] Plugin = colorhug Flags = self-recovery Summary = An open source display colorimeter @@ -29,7 +29,7 @@ CounterpartGuid = USB\VID_273F&PID_1005 InstallDuration = 8 -[DeviceInstanceId=USB\VID_273F&PID_1005] +[USB\VID_273F&PID_1005] Plugin = colorhug Flags = is-bootloader,self-recovery Guid = 2082b5e0-7a64-478a-b1b2-e3404fab6dad @@ -37,7 +37,7 @@ InstallDuration = 8 # ColorHugALS -[DeviceInstanceId=USB\VID_273F&PID_1007] +[USB\VID_273F&PID_1007] Plugin = colorhug Flags = halfsize,self-recovery Summary = An open source ambient light sensor @@ -47,7 +47,7 @@ CounterpartGuid = USB\VID_273F&PID_1006 InstallDuration = 5 -[DeviceInstanceId=USB\VID_273F&PID_1006] +[USB\VID_273F&PID_1006] Plugin = colorhug Flags = halfsize,is-bootloader,self-recovery Guid = 84f40464-9272-4ef7-9399-cd95f12da696 diff -Nru fwupd-1.4.5/plugins/colorhug/fu-colorhug-common.c fwupd-1.5.8/plugins/colorhug/fu-colorhug-common.c --- fwupd-1.4.5/plugins/colorhug/fu-colorhug-common.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/colorhug/fu-colorhug-common.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2018 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -77,10 +77,10 @@ return "Self test failed: ADC Vss"; if (error_enum == CH_ERROR_SELF_TEST_ADC_VREF) return "Self test failed: ADC Vref"; - if (error_enum == CH_ERROR_I2C_SLAVE_ADDRESS) - return "I2C set slave address failed"; - if (error_enum == CH_ERROR_I2C_SLAVE_CONFIG) - return "I2C set slave config failed"; + if (error_enum == CH_ERROR_I2C_TARGET_ADDRESS) + return "I2C set target address failed"; + if (error_enum == CH_ERROR_I2C_TARGET_CONFIG) + return "I2C set target config failed"; if (error_enum == CH_ERROR_SELF_TEST_EEPROM) return "Self test failed: EEPROM"; return NULL; diff -Nru fwupd-1.4.5/plugins/colorhug/fu-colorhug-common.h fwupd-1.5.8/plugins/colorhug/fu-colorhug-common.h --- fwupd-1.4.5/plugins/colorhug/fu-colorhug-common.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/colorhug/fu-colorhug-common.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2018 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -42,8 +42,8 @@ CH_ERROR_SELF_TEST_ADC_VDD, CH_ERROR_SELF_TEST_ADC_VSS, CH_ERROR_SELF_TEST_ADC_VREF, - CH_ERROR_I2C_SLAVE_ADDRESS, - CH_ERROR_I2C_SLAVE_CONFIG, + CH_ERROR_I2C_TARGET_ADDRESS, + CH_ERROR_I2C_TARGET_CONFIG, CH_ERROR_SELF_TEST_EEPROM, CH_ERROR_LAST } ChError; diff -Nru fwupd-1.4.5/plugins/colorhug/fu-colorhug-device.c fwupd-1.5.8/plugins/colorhug/fu-colorhug-device.c --- fwupd-1.4.5/plugins/colorhug/fu-colorhug-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/colorhug/fu-colorhug-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2017 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -293,26 +293,33 @@ } static gboolean -fu_colorhug_device_probe (FuUsbDevice *device, GError **error) +fu_colorhug_device_probe (FuDevice *device, GError **error) { FuColorhugDevice *self = FU_COLORHUG_DEVICE (device); + /* FuUsbDevice->probe */ + if (!FU_DEVICE_CLASS (fu_colorhug_device_parent_class)->probe (device, error)) + return FALSE; + /* compact memory layout */ - if (fu_device_has_custom_flag (FU_DEVICE (device), - FU_COLORHUG_DEVICE_FLAG_HALFSIZE)) + if (fu_device_has_custom_flag (device, FU_COLORHUG_DEVICE_FLAG_HALFSIZE)) self->start_addr = CH_EEPROM_ADDR_RUNCODE_ALS; /* add hardcoded bits */ - fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); /* success */ return TRUE; } static gboolean -fu_colorhug_device_open (FuUsbDevice *device, GError **error) +fu_colorhug_device_open (FuDevice *device, GError **error) { - GUsbDevice *usb_device = fu_usb_device_get_dev (device); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + + /* FuUsbDevice->open */ + if (!FU_DEVICE_CLASS (fu_colorhug_device_parent_class)->open (device, error)) + return FALSE; /* got the version using the HID API */ if (!g_usb_device_set_configuration (usb_device, CH_USB_CONFIG, error)) @@ -332,13 +339,15 @@ { FuColorhugDevice *self = FU_COLORHUG_DEVICE (device); - if (fu_device_get_version (FU_DEVICE (device)) == NULL) { + /* using the USB descriptor and old firmware */ + if (fu_device_get_version_format (device) == FWUPD_VERSION_FORMAT_BCD) { g_autofree gchar *version = NULL; g_autoptr(GError) error_local = NULL; version = fu_colorhug_device_get_version (self, &error_local); if (version != NULL) { g_debug ("obtained fwver using API '%s'", version); fu_device_set_version (device, version); + fu_device_set_version_format (device, FWUPD_VERSION_FORMAT_TRIPLET); } else { g_warning ("failed to get firmware version: %s", error_local->message); @@ -395,12 +404,13 @@ g_autoptr(GError) error_local = NULL; /* set address, length, checksum, data */ - fu_common_write_uint16 (buf + 0, chk->address, G_LITTLE_ENDIAN); - buf[2] = chk->data_sz; - buf[3] = ch_colorhug_device_calculate_checksum (chk->data, chk->data_sz); + fu_common_write_uint16 (buf + 0, fu_chunk_get_address (chk), G_LITTLE_ENDIAN); + buf[2] = fu_chunk_get_data_sz (chk); + buf[3] = ch_colorhug_device_calculate_checksum (fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk)); if (!fu_memcpy_safe (buf, sizeof(buf), 0x4, /* dst */ - chk->data, chk->data_sz, 0x0, /* src */ - chk->data_sz, error)) + fu_chunk_get_data (chk), fu_chunk_get_data_sz (chk), 0x0, /* src */ + fu_chunk_get_data_sz (chk), error)) return FALSE; if (!fu_colorhug_device_msg (self, CH_CMD_WRITE_FLASH, buf, sizeof(buf), /* in */ @@ -427,8 +437,8 @@ g_autoptr(GError) error_local = NULL; /* set address */ - fu_common_write_uint16 (buf + 0, chk->address, G_LITTLE_ENDIAN); - buf[2] = chk->data_sz; + fu_common_write_uint16 (buf + 0, fu_chunk_get_address (chk), G_LITTLE_ENDIAN); + buf[2] = fu_chunk_get_data_sz (chk); if (!fu_colorhug_device_msg (self, CH_CMD_READ_FLASH, buf, sizeof(buf), /* in */ buf_out, sizeof(buf_out), /* out */ @@ -442,13 +452,16 @@ } /* verify */ - if (memcmp (buf_out + 1, chk->data, chk->data_sz) != 0) { + if (memcmp (buf_out + 1, + fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk)) != 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_WRITE, "failed to verify firmware for chunk %u, " "address 0x%0x, length 0x%0x", - i, (guint) chk->address, chk->data_sz); + i, (guint) fu_chunk_get_address (chk), + fu_chunk_get_data_sz (chk)); return FALSE; } @@ -467,23 +480,22 @@ { /* this is the application code */ self->start_addr = CH_EEPROM_ADDR_RUNCODE; - fu_device_set_protocol (FU_DEVICE (self), "com.hughski.colorhug"); - fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_add_protocol (FU_DEVICE (self), "com.hughski.colorhug"); fu_device_set_remove_delay (FU_DEVICE (self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_ADD_COUNTERPART_GUIDS); + fu_device_add_internal_flag (FU_DEVICE (self), FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID); } static void fu_colorhug_device_class_init (FuColorhugDeviceClass *klass) { FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); klass_device->write_firmware = fu_colorhug_device_write_firmware; klass_device->attach = fu_colorhug_device_attach; klass_device->detach = fu_colorhug_device_detach; klass_device->reload = fu_colorhug_device_reload; klass_device->setup = fu_colorhug_device_setup; - klass_usb_device->open = fu_colorhug_device_open; - klass_usb_device->probe = fu_colorhug_device_probe; + klass_device->open = fu_colorhug_device_open; + klass_device->probe = fu_colorhug_device_probe; } diff -Nru fwupd-1.4.5/plugins/colorhug/fu-colorhug-device.h fwupd-1.5.8/plugins/colorhug/fu-colorhug-device.h --- fwupd-1.4.5/plugins/colorhug/fu-colorhug-device.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/colorhug/fu-colorhug-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2017 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/colorhug/fu-plugin-colorhug.c fwupd-1.5.8/plugins/colorhug/fu-plugin-colorhug.c --- fwupd-1.4.5/plugins/colorhug/fu-plugin-colorhug.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/colorhug/fu-plugin-colorhug.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2017 Richard Hughes + * Copyright (C) 2015 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -7,7 +7,6 @@ #include "config.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #include "fu-colorhug-device.h" diff -Nru fwupd-1.4.5/plugins/colorhug/meson.build fwupd-1.5.8/plugins/colorhug/meson.build --- fwupd-1.4.5/plugins/colorhug/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/colorhug/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,4 @@ +if get_option('gusb') cargs = ['-DG_LOG_DOMAIN="FuPluginColorHug"'] install_data([ @@ -29,3 +30,4 @@ plugin_deps, ], ) +endif diff -Nru fwupd-1.4.5/plugins/colorhug/README.md fwupd-1.5.8/plugins/colorhug/README.md --- fwupd-1.4.5/plugins/colorhug/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/colorhug/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -30,7 +30,21 @@ * `USB\VID_273F&PID_1001` * `USB\VID_273F` +Update Behavior +--------------- + +The device usually presents in runtime mode, but on detach re-enumerates with a +different USB PID in a bootloader mode. On attach the device again re-enumerates +back to the runtime mode. + +For this reason the `REPLUG_MATCH_GUID` internal device flag is used so that +the bootloader and runtime modes are treated as the same device. + Vendor ID Security ------------------ The vendor ID is set from the USB vendor, in this instance set to `USB:0x273F` + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff -Nru fwupd-1.4.5/plugins/coreboot/coreboot.quirk fwupd-1.5.8/plugins/coreboot/coreboot.quirk --- fwupd-1.4.5/plugins/coreboot/coreboot.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/coreboot/coreboot.quirk 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -[SmbiosManufacturer=LENOVO] -CorebootVersionQuirks = lenovo-cbet-prefix diff -Nru fwupd-1.4.5/plugins/coreboot/fu-coreboot-common.c fwupd-1.5.8/plugins/coreboot/fu-coreboot-common.c --- fwupd-1.4.5/plugins/coreboot/fu-coreboot-common.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/coreboot/fu-coreboot-common.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2019 9elements Agency GmbH - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include -#include - -#include "fu-plugin-coreboot.h" - -/** - * FU_QUIRKS_COREBOOT_VERSION: - * @key: The SMBIOS manufacturer name - * @value: One of the following: "lenovo-cbet-prefix" - * - * "lenovo-cbet-prefix" quirk: - * The thinkpad_acpi kernel module requires a specific pattern - * in the DMI version string. To satisfy those requirements - * coreboot adds the CBETxxxx prefix to the DMI version string - * on all Lenovo devices. The prefix isn't present in the - * version string found in coreboot tables, or on other - * coreboot enabled devices. - * - * Since: 1.3.5 - */ -#define FU_QUIRKS_COREBOOT_VERSION "CorebootVersionQuirks" -#define FU_QUIRK_CBET_PREFIX "lenovo-cbet-prefix" - -/* Tries to convert the coreboot version string to a triplet string. - * Returns NULL on error. */ -gchar * -fu_plugin_coreboot_version_string_to_triplet (const gchar *coreboot_version, - GError **error) -{ - guint cb_major = 0; - guint cb_minor = 0; - guint cb_build = 0; - gint rc; - - rc = sscanf (coreboot_version, "%u.%u-%u", &cb_major, &cb_minor, &cb_build); - - if (rc < 0) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "Failed to parse firmware version"); - return NULL; - } - - /* Sanity check */ - if (cb_major == 0) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "Invalid firmware version"); - return NULL; - } - - return g_strdup_printf ("%u.%u.%u", cb_major, cb_minor, cb_build); -} - -/* convert firmware type to user friendly string representation */ -gchar * -fu_plugin_coreboot_get_name_for_type (FuPlugin *plugin, - const gchar *vboot_partition) -{ - GString *display_name; - - if (vboot_partition != NULL) { - display_name = g_string_new (vboot_partition); - g_string_prepend (display_name, ", VBOOT partition "); - } else { - display_name = g_string_new (""); - } - - g_string_prepend (display_name, "coreboot System Firmware"); - return g_string_free (display_name, FALSE); -} - -/* Returns the version string with possible quirks applied */ -const gchar * -fu_plugin_coreboot_get_version_string (FuPlugin *plugin) -{ - const gchar *version; - const gchar *manufacturer; - const gchar *quirk = NULL; - - version = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_BIOS_VERSION); - if (version == NULL) - return NULL; - - manufacturer = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_MANUFACTURER); - if (manufacturer != NULL) { - g_autofree gchar *group = NULL; - - /* any quirks match */ - group = g_strdup_printf ("SmbiosManufacturer=%s", manufacturer); - quirk = fu_plugin_lookup_quirk_by_id (plugin, group, - FU_QUIRKS_COREBOOT_VERSION); - } - - if (quirk == NULL) - return version; - - if (g_strcmp0(quirk, FU_QUIRK_CBET_PREFIX) == 0) { - if (strlen (version) > 9 && g_str_has_prefix (version, "CBET")) - version += 9; - return version; - } - - return version; -} diff -Nru fwupd-1.4.5/plugins/coreboot/fu-plugin-coreboot.c fwupd-1.5.8/plugins/coreboot/fu-plugin-coreboot.c --- fwupd-1.4.5/plugins/coreboot/fu-plugin-coreboot.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/coreboot/fu-plugin-coreboot.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,147 +0,0 @@ -/* - * Copyright (C) 2019 9elements Agency GmbH - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include -#include -#include -#include - -#include "fu-plugin-vfuncs.h" -#include "fu-hash.h" -#include "fu-device-metadata.h" -#include "fu-device-private.h" -#include "fu-plugin-coreboot.h" - -void -fu_plugin_init (FuPlugin *plugin) -{ - fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); -} - -gboolean -fu_plugin_coldplug (FuPlugin *plugin, GError **error) -{ - const gchar *major; - const gchar *minor; - const gchar *version; - GBytes *bios_table; - gboolean updatable = FALSE; /* TODO: Implement update support */ - g_autofree gchar *name = NULL; - g_autofree gchar *triplet = NULL; - g_autoptr(FuDevice) dev = NULL; - - /* don't include FU_HWIDS_KEY_BIOS_VERSION */ - static const gchar *hwids[] = { - "HardwareID-3", - "HardwareID-4", - "HardwareID-5", - "HardwareID-6", - "HardwareID-10", - }; - - version = fu_plugin_coreboot_get_version_string (plugin); - if (version != NULL) - triplet = fu_plugin_coreboot_version_string_to_triplet (version, error); - - if (version == NULL || triplet == NULL) { - major = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_BIOS_MAJOR_RELEASE); - if (major == NULL) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_NOT_FOUND, - "Missing BIOS major release"); - return FALSE; - } - minor = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_BIOS_MINOR_RELEASE); - if (minor == NULL) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_NOT_FOUND, - "Missing BIOS minor release"); - return FALSE; - } - triplet = g_strdup_printf ("%s.%s.0", major, minor); - } - - if (triplet == NULL) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "No version string found"); - - return FALSE; - } - dev = fu_device_new (); - fu_device_set_version_format (dev, FWUPD_VERSION_FORMAT_TRIPLET); - fu_device_set_version (dev, triplet); - fu_device_set_summary (dev, "Open Source system boot firmware"); - fu_device_set_id (dev, "coreboot"); - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_INTERNAL); - fu_device_add_icon (dev, "computer"); - name = fu_plugin_coreboot_get_name_for_type (plugin, NULL); - if (name != NULL) { - fu_device_set_name (dev, name); - } else { - fu_device_set_name (dev, fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_PRODUCT_NAME)); - } - fu_device_set_vendor (dev, fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_MANUFACTURER)); - fu_device_add_instance_id (dev, "main-system-firmware"); - fu_device_set_vendor_id (dev, "DMI:coreboot"); - - for (guint i = 0; i < G_N_ELEMENTS (hwids); i++) { - char *str; - str = fu_plugin_get_hwid_replace_value (plugin, hwids[i], NULL); - if (str != NULL) - fu_device_add_instance_id (dev, str); - } - - bios_table = fu_plugin_get_smbios_data (plugin, FU_SMBIOS_STRUCTURE_TYPE_BIOS); - if (bios_table != NULL) { - guint32 bios_characteristics; - gsize len; - const guint8 *value = g_bytes_get_data (bios_table, &len); - if (len >= 0x9) { - gint firmware_size = (value[0x9] + 1) * 64 * 1024; - fu_device_set_firmware_size_max (dev, firmware_size); - } - if (len >= (0xa + sizeof(guint32))) { - memcpy (&bios_characteristics, &value[0xa], sizeof (guint32)); - /* Read the "BIOS is upgradeable (Flash)" flag */ - if (!(bios_characteristics & (1 << 11))) - updatable = FALSE; - } - } - - if (updatable) - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); - - /* convert instances to GUID */ - fu_device_convert_instance_ids (dev); - - fu_plugin_device_add (plugin, dev); - - return TRUE; -} - -gboolean -fu_plugin_startup (FuPlugin *plugin, GError **error) -{ - const gchar *vendor; - - vendor = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_BIOS_VENDOR); - if (g_strcmp0 (vendor, "coreboot") != 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "No coreboot detected on this machine."); - return FALSE; - } - - return TRUE; -} - diff -Nru fwupd-1.4.5/plugins/coreboot/fu-plugin-coreboot.h fwupd-1.5.8/plugins/coreboot/fu-plugin-coreboot.h --- fwupd-1.4.5/plugins/coreboot/fu-plugin-coreboot.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/coreboot/fu-plugin-coreboot.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -/* - * Copyright (C) 2019 9elements Agency GmbH - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include "fu-plugin.h" -#include "fu-device.h" - -gchar *fu_plugin_coreboot_version_string_to_triplet (const gchar *coreboot_version, - GError **error); -gchar *fu_plugin_coreboot_get_name_for_type (FuPlugin *plugin, - const gchar *vboot_partition); -const gchar *fu_plugin_coreboot_get_version_string (FuPlugin *plugin); diff -Nru fwupd-1.4.5/plugins/coreboot/meson.build fwupd-1.5.8/plugins/coreboot/meson.build --- fwupd-1.4.5/plugins/coreboot/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/coreboot/meson.build 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -cargs = ['-DG_LOG_DOMAIN="FuPluginCoreboot"'] - -install_data(['coreboot.quirk'], - install_dir: join_paths(datadir, 'fwupd', 'quirks.d') -) - -shared_module('fu_plugin_coreboot', - fu_hash, - sources : [ - 'fu-plugin-coreboot.c', - 'fu-coreboot-common.c', - ], - include_directories : [ - root_incdir, - fwupd_incdir, - fwupdplugin_incdir, - ], - install : true, - install_dir: plugin_dir, - link_with : [ - fwupd, - fwupdplugin, - ], - c_args : [ - cargs, - ], - dependencies : [ - plugin_deps, - ], -) diff -Nru fwupd-1.4.5/plugins/coreboot/README.md fwupd-1.5.8/plugins/coreboot/README.md --- fwupd-1.4.5/plugins/coreboot/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/coreboot/README.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,59 +0,0 @@ -coreboot -======== - -Introduction ------------- - -Until now only the version detection has been implemented. - -System identification ---------------------- - -coreboot can be detected the following ways: -1. by parsing SMBIOS type 0 vendor string. On coreboot enabled platforms - it's always `coreboot`. -2. by parsing ACPI tables. An ACPI device with the _HID `BOOT0000` exists. - (This HID has been reserved for coreboot enabled platforms) -3. by parsing the devicetree. A node under *firmware/coreboot* with the - compatible id `coreboot` exists. - -coreboot version string ------------------------ - -The coreboot version string can have an optional prefix (see below). -After the optional prefix the *major*, *minor* string follows and finally -the *build string*, containing the exact commit and repository state, follows. - -For example: -> 4.10-989-gc8a4e4b9c5-dirty - -**Exception on Lenovo devices:** - -The thinkpad_acpi kernel module requires a specific pattern in the DMI version -string. To satisfy those requirements coreboot adds the CBETxxxx prefix to the -DMI version string on all Lenovo devices. - -For example: -> CBET4000 4.10-989-gc8a4e4b9c5-dirty - -The coreboot DMI version string always starts with `CBET`. - -GUID Generation ---------------- - -These device uses hardware ID values which are derived from SMBIOS. -The following HWIDs are added on coreboot enabled platforms: - -* HardwareID-3 -* HardwareID-4 -* HardwareID-5 -* HardwareID-6 -* HardwareID-10 - -They do match the values provided by `fwupdtool hwids` or -the `ComputerHardwareIds.exe` Windows utility. - -Vendor ID Security ------------------- - -The vendor ID is set from the BIOS vendor, in this instance `DMI:coreboot` diff -Nru fwupd-1.4.5/plugins/cpu/cpu.quirk fwupd-1.5.8/plugins/cpu/cpu.quirk --- fwupd-1.4.5/plugins/cpu/cpu.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/cpu/cpu.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,3 @@ +# Intel Atom Bay Trail [Silvermont] +[CPUID\PRO_0&FAM_06&MOD_37] +PciBcrAddr = 0x0 diff -Nru fwupd-1.4.5/plugins/cpu/fu-cpu-device.c fwupd-1.5.8/plugins/cpu/fu-cpu-device.c --- fwupd-1.4.5/plugins/cpu/fu-cpu-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/cpu/fu-cpu-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -10,36 +10,87 @@ struct _FuCpuDevice { FuDevice parent_instance; + FuCpuDeviceFlag flags; }; G_DEFINE_TYPE (FuCpuDevice, fu_cpu_device, FU_TYPE_DEVICE) -static void fu_cpu_device_parse_section (FuDevice *dev, const gchar *data) +gboolean +fu_cpu_device_has_flag (FuCpuDevice *self, FuCpuDeviceFlag flag) { - g_auto(GStrv) lines = NULL; + return (self->flags & flag) > 0; +} - lines = g_strsplit (data, "\n", 0); - for (guint i = 0; lines[i] != NULL; i++) { - if (g_str_has_prefix (lines[i], "vendor_id")) { - g_auto(GStrv) fields = g_strsplit (lines[i], ":", -1); - if (fields[1] != NULL) - fu_device_set_vendor (dev, g_strchug (fields[1])); - } else if (g_str_has_prefix (lines[i], "model name")) { - g_auto(GStrv) fields = g_strsplit (lines[i], ":", -1); - if (fields[1] != NULL) - fu_device_set_name (dev, g_strchug (fields[1])); - } else if (g_str_has_prefix (lines[i], "microcode")) { - g_auto(GStrv) fields = g_strsplit (lines[i], ":", -1); - if (fields[1] != NULL) - fu_device_set_version (dev, g_strchug (fields[1])); - } else if (g_str_has_prefix (lines[i], "physical id")) { - g_auto(GStrv) fields = g_strsplit (lines[i], ":", -1); - if (fields[1] != NULL) { - g_autofree gchar *tmp = g_strdup_printf ("cpu:%s", g_strchug (fields[1])); - fu_device_set_physical_id (dev, tmp); - } - } - } +static void +fu_cpu_device_to_string (FuDevice *device, guint idt, GString *str) +{ + FuCpuDevice *self = FU_CPU_DEVICE (device); + fu_common_string_append_kb (str, idt, "HasSHSTK", + fu_cpu_device_has_flag (self, FU_CPU_DEVICE_FLAG_SHSTK)); + fu_common_string_append_kb (str, idt, "HasIBT", + fu_cpu_device_has_flag (self, FU_CPU_DEVICE_FLAG_IBT)); + fu_common_string_append_kb (str, idt, "HasTME", + fu_cpu_device_has_flag (self, FU_CPU_DEVICE_FLAG_TME)); + fu_common_string_append_kb (str, idt, "HasSMAP", + fu_cpu_device_has_flag (self, FU_CPU_DEVICE_FLAG_SMAP)); +} + +static const gchar * +fu_cpu_device_convert_vendor (const gchar *vendor) +{ + if (g_strcmp0 (vendor, "GenuineIntel") == 0) + return "Intel"; + if (g_strcmp0 (vendor, "AuthenticAMD") == 0 || + g_strcmp0 (vendor, "AMDisbetter!") == 0) + return "AMD"; + if (g_strcmp0 (vendor, "CentaurHauls") == 0) + return "IDT"; + if (g_strcmp0 (vendor, "CyrixInstead") == 0) + return "Cyrix"; + if (g_strcmp0 (vendor, "TransmetaCPU") == 0 || + g_strcmp0 (vendor, "GenuineTMx86") == 0) + return "Transmeta"; + if (g_strcmp0 (vendor, "Geode by NSC") == 0) + return "National Semiconductor"; + if (g_strcmp0 (vendor, "NexGenDriven") == 0) + return "NexGen"; + if (g_strcmp0 (vendor, "RiseRiseRise") == 0) + return "Rise"; + if (g_strcmp0 (vendor, "SiS SiS SiS ") == 0) + return "SiS"; + if (g_strcmp0 (vendor, "UMC UMC UMC ") == 0) + return "UMC"; + if (g_strcmp0 (vendor, "VIA VIA VIA ") == 0) + return "VIA"; + if (g_strcmp0 (vendor, "Vortex86 SoC") == 0) + return "Vortex"; + if (g_strcmp0 (vendor, " Shanghai ") == 0) + return "Zhaoxin"; + if (g_strcmp0 (vendor, "HygonGenuine") == 0) + return "Hygon"; + if (g_strcmp0 (vendor, "E2K MACHINE") == 0) + return "MCST"; + if (g_strcmp0 (vendor, "bhyve bhyve ") == 0) + return "bhyve"; + if (g_strcmp0 (vendor, " KVMKVMKVM ") == 0) + return "KVM"; + if (g_strcmp0 (vendor, "TCGTCGTCGTCG") == 0) + return "QEMU"; + if (g_strcmp0 (vendor, "Microsoft Hv") == 0) + return "Microsoft"; + if (g_strcmp0 (vendor, " lrpepyh vr") == 0) + return "Parallels"; + if (g_strcmp0 (vendor, "VMwareVMware") == 0) + return "VMware"; + if (g_strcmp0 (vendor, "XenVMMXenVMM") == 0) + return "Xen"; + if (g_strcmp0 (vendor, "ACRNACRNACRN") == 0) + return "ACRN"; + if (g_strcmp0 (vendor, " QNXQVMBSQG ") == 0) + return "QNX"; + if (g_strcmp0 (vendor, "VirtualApple") == 0) + return "Apple"; + return vendor; } static void @@ -49,18 +100,180 @@ fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL); fu_device_add_icon (FU_DEVICE (self), "computer"); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_HEX); + fu_device_set_physical_id (FU_DEVICE (self), "cpu:0"); +} + +static gboolean +fu_cpu_device_add_instance_ids (FuDevice *device, GError **error) +{ + guint32 eax = 0; + guint32 family_id; + guint32 family_id_ext; + guint32 model_id; + guint32 model_id_ext; + guint32 processor_id; + guint32 stepping_id; + g_autofree gchar *devid1 = NULL; + g_autofree gchar *devid2 = NULL; + g_autofree gchar *devid3 = NULL; + + /* decode according to https://en.wikipedia.org/wiki/CPUID */ + if (!fu_common_cpuid (0x1, &eax, NULL, NULL, NULL, error)) + return FALSE; + processor_id = (eax >> 12) & 0x3; + model_id = (eax >> 4) & 0xf; + family_id = (eax >> 8) & 0xf; + model_id_ext = (eax >> 16) & 0xf; + family_id_ext = (eax >> 20) & 0xff; + stepping_id = eax & 0xf; + + /* use extended IDs where required */ + if (family_id == 6 || family_id == 15) + model_id |= model_id_ext << 4; + if (family_id == 15) + family_id += family_id_ext; + + devid1 = g_strdup_printf ("CPUID\\PRO_%01X&FAM_%02X", + processor_id, + family_id); + fu_device_add_instance_id (device, devid1); + devid2 = g_strdup_printf ("CPUID\\PRO_%01X&FAM_%02X&MOD_%02X", + processor_id, + family_id, + model_id); + fu_device_add_instance_id (device, devid2); + devid3 = g_strdup_printf ("CPUID\\PRO_%01X&FAM_%02X&MOD_%02X&STP_%01X", + processor_id, + family_id, + model_id, + stepping_id); + fu_device_add_instance_id (device, devid3); + return TRUE; +} + +static gboolean +fu_cpu_device_probe_manufacturer_id (FuDevice *device, GError **error) +{ + guint32 ebx = 0; + guint32 ecx = 0; + guint32 edx = 0; + gchar str[13] = { '\0' }; + if (!fu_common_cpuid (0x0, NULL, &ebx, &ecx, &edx, error)) + return FALSE; + if (!fu_memcpy_safe ((guint8 *) str, sizeof(str), 0x0, /* dst */ + (const guint8 *) &ebx, sizeof(ebx), 0x0, /* src */ + sizeof(guint32), error)) + return FALSE; + if (!fu_memcpy_safe ((guint8 *) str, sizeof(str), 0x4, /* dst */ + (const guint8 *) &edx, sizeof(edx), 0x0, /* src */ + sizeof(guint32), error)) + return FALSE; + if (!fu_memcpy_safe ((guint8 *) str, sizeof(str), 0x8, /* dst */ + (const guint8 *) &ecx, sizeof(ecx), 0x0, /* src */ + sizeof(guint32), error)) + return FALSE; + fu_device_set_vendor (device, fu_cpu_device_convert_vendor (str)); + return TRUE; +} + +static gboolean +fu_cpu_device_probe_model (FuDevice *device, GError **error) +{ + guint32 eax = 0; + guint32 ebx = 0; + guint32 ecx = 0; + guint32 edx = 0; + gchar str[49] = { '\0' }; + + for (guint32 i = 0; i < 3; i++) { + if (!fu_common_cpuid (0x80000002 + i, &eax, &ebx, &ecx, &edx, error)) + return FALSE; + if (!fu_memcpy_safe ((guint8 *) str, sizeof(str), (16 * i) + 0x0, /* dst */ + (const guint8 *) &eax, sizeof(eax), 0x0, /* src */ + sizeof(guint32), error)) + return FALSE; + if (!fu_memcpy_safe ((guint8 *) str, sizeof(str), (16 * i) + 0x4, /* dst */ + (const guint8 *) &ebx, sizeof(ebx), 0x0, /* src */ + sizeof(guint32), error)) + return FALSE; + if (!fu_memcpy_safe ((guint8 *) str, sizeof(str), (16 * i) + 0x8, /* dst */ + (const guint8 *) &ecx, sizeof(ecx), 0x0, /* src */ + sizeof(guint32), error)) + return FALSE; + if (!fu_memcpy_safe ((guint8 *) str, sizeof(str), (16 * i) + 0xc, /* dst */ + (const guint8 *) &edx, sizeof(edx), 0x0, /* src */ + sizeof(guint32), error)) + return FALSE; + } + fu_device_set_name (device, str); + return TRUE; +} + +static gboolean +fu_cpu_device_probe_extended_features (FuDevice *device, GError **error) +{ + FuCpuDevice *self = FU_CPU_DEVICE (device); + guint32 ebx = 0; + guint32 ecx = 0; + + if (!fu_common_cpuid (0x7, NULL, &ebx, &ecx, NULL, error)) + return FALSE; + if ((ebx >> 20) & 0x1) + self->flags |= FU_CPU_DEVICE_FLAG_SMAP; + if ((ecx >> 7) & 0x1) + self->flags |= FU_CPU_DEVICE_FLAG_SHSTK; + if ((ecx >> 13) & 0x1) + self->flags |= FU_CPU_DEVICE_FLAG_TME; + if ((ecx >> 20) & 0x1) + self->flags |= FU_CPU_DEVICE_FLAG_IBT; + return TRUE; +} + +static gboolean +fu_cpu_device_probe (FuDevice *device, GError **error) +{ + if (!fu_cpu_device_probe_manufacturer_id (device, error)) + return FALSE; + if (!fu_cpu_device_probe_model (device, error)) + return FALSE; + if (!fu_cpu_device_probe_extended_features (device, error)) + return FALSE; + if (!fu_cpu_device_add_instance_ids (device, error)) + return FALSE; + return TRUE; +} + +static gboolean +fu_cpu_device_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + if (g_strcmp0 (key, "PciBcrAddr") == 0) { + guint64 tmp = fu_common_strtoull (value); + fu_device_set_metadata_integer (device, "PciBcrAddr", tmp); + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "no supported"); + return FALSE; } static void fu_cpu_device_class_init (FuCpuDeviceClass *klass) { + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + klass_device->to_string = fu_cpu_device_to_string; + klass_device->probe = fu_cpu_device_probe; + klass_device->set_quirk_kv = fu_cpu_device_set_quirk_kv; } FuCpuDevice * -fu_cpu_device_new (const gchar *section) +fu_cpu_device_new (void) { FuCpuDevice *device = NULL; device = g_object_new (FU_TYPE_CPU_DEVICE, NULL); - fu_cpu_device_parse_section (FU_DEVICE (device), section); return device; } diff -Nru fwupd-1.4.5/plugins/cpu/fu-cpu-device.h fwupd-1.5.8/plugins/cpu/fu-cpu-device.h --- fwupd-1.4.5/plugins/cpu/fu-cpu-device.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/cpu/fu-cpu-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -11,4 +11,14 @@ #define FU_TYPE_CPU_DEVICE (fu_cpu_device_get_type ()) G_DECLARE_FINAL_TYPE (FuCpuDevice, fu_cpu_device, FU, CPU_DEVICE, FuDevice) -FuCpuDevice *fu_cpu_device_new (const gchar *section); +typedef enum { + FU_CPU_DEVICE_FLAG_NONE = 0, + FU_CPU_DEVICE_FLAG_SHSTK = 1 << 0, + FU_CPU_DEVICE_FLAG_IBT = 1 << 1, + FU_CPU_DEVICE_FLAG_TME = 1 << 2, + FU_CPU_DEVICE_FLAG_SMAP = 1 << 3, +} FuCpuDeviceFlag; + +FuCpuDevice *fu_cpu_device_new (void); +gboolean fu_cpu_device_has_flag (FuCpuDevice *self, + FuCpuDeviceFlag flag); diff -Nru fwupd-1.4.5/plugins/cpu/fu-cpu-helper-cet.c fwupd-1.5.8/plugins/cpu/fu-cpu-helper-cet.c --- fwupd-1.4.5/plugins/cpu/fu-cpu-helper-cet.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/cpu/fu-cpu-helper-cet.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2020 Richard Hughes + * Copyright (C) 2020 H.J. Lu + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include + +#include "fu-cpu-helper-cet-common.h" + +#ifdef HAVE_SIGACTION +static __attribute__((noreturn))void +segfault_sigaction (int signal, siginfo_t *si, void *arg) +{ + /* CET did exactly as it should to protect the system */ + exit (0); +} +#endif + +int +main (int argc, char *argv[]) +{ +#ifdef HAVE_SIGACTION + struct sigaction sa = { 0 }; + + sigemptyset (&sa.sa_mask); + sa.sa_sigaction = segfault_sigaction; + sa.sa_flags = SA_SIGINFO; + sigaction (SIGSEGV, &sa, NULL); +#endif + + fu_cpu_helper_cet_testfn1 (); + + /* this means CET did not work */ + return 1; +} diff -Nru fwupd-1.4.5/plugins/cpu/fu-cpu-helper-cet-common.c fwupd-1.5.8/plugins/cpu/fu-cpu-helper-cet-common.c --- fwupd-1.4.5/plugins/cpu/fu-cpu-helper-cet-common.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/cpu/fu-cpu-helper-cet-common.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2020 Richard Hughes + * Copyright (C) 2020 H.J. Lu + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-cpu-helper-cet-common.h" + +static void +fu_cpu_helper_cet_testfn_fptr (void) +{ +} + +static void +__attribute__ ((noinline, noclone)) +fu_cpu_helper_cet_testfn_call_fptr (void (*func) (void)) +{ + func (); +} + +void +__attribute__ ((noinline, noclone)) +fu_cpu_helper_cet_testfn1 (void) +{ + fu_cpu_helper_cet_testfn_call_fptr (fu_cpu_helper_cet_testfn_fptr); +} diff -Nru fwupd-1.4.5/plugins/cpu/fu-cpu-helper-cet-common.h fwupd-1.5.8/plugins/cpu/fu-cpu-helper-cet-common.h --- fwupd-1.4.5/plugins/cpu/fu-cpu-helper-cet-common.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/cpu/fu-cpu-helper-cet-common.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,10 @@ +/* + * Copyright (C) 2020 Richard Hughes + * Copyright (C) 2020 H.J. Lu + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +void fu_cpu_helper_cet_testfn1 (void); diff -Nru fwupd-1.4.5/plugins/cpu/fu-plugin-cpu.c fwupd-1.5.8/plugins/cpu/fu-plugin-cpu.c --- fwupd-1.4.5/plugins/cpu/fu-plugin-cpu.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/cpu/fu-plugin-cpu.c 2021-03-31 20:08:32.000000000 +0000 @@ -7,35 +7,161 @@ #include "config.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #include "fu-cpu-device.h" void fu_plugin_init (FuPlugin *plugin) { fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_BEFORE, "msr"); } gboolean fu_plugin_coldplug (FuPlugin *plugin, GError **error) { - gsize length; - g_autofree gchar *data = NULL; - g_auto(GStrv) lines = NULL; - - if (!g_file_get_contents ("/proc/cpuinfo", &data, &length, error)) + g_autoptr(FuCpuDevice) dev = fu_cpu_device_new (); + fu_device_set_quirks (FU_DEVICE (dev), fu_plugin_get_quirks (plugin)); + if (!fu_device_probe (FU_DEVICE (dev), error)) + return FALSE; + if (!fu_device_setup (FU_DEVICE (dev), error)) return FALSE; + fu_plugin_cache_add (plugin, "cpu", dev); + fu_plugin_device_add (plugin, FU_DEVICE (dev)); + return TRUE; +} - lines = g_strsplit (data, "\n\n", 0); - for (guint i = 0; lines[i] != NULL; i++) { - g_autoptr(FuCpuDevice) dev = NULL; - if (strlen (lines[i]) == 0) - continue; - dev = fu_cpu_device_new (lines[i]); - if (!fu_device_setup (FU_DEVICE (dev), error)) - return FALSE; - fu_plugin_device_add (plugin, FU_DEVICE (dev)); +static void +fu_plugin_add_security_attrs_intel_cet_enabled (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuCpuDevice *device = fu_plugin_cache_lookup (plugin, "cpu"); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* no CPU */ + if (device == NULL) + return; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_INTEL_CET_ENABLED); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL); + fu_security_attrs_append (attrs, attr); + + /* check for CET */ + if (!fu_cpu_device_has_flag (device, FU_CPU_DEVICE_FLAG_SHSTK) || + !fu_cpu_device_has_flag (device, FU_CPU_DEVICE_FLAG_IBT)) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED); + return; } - return TRUE; + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); +} + +static void +fu_plugin_add_security_attrs_intel_cet_active (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuCpuDevice *device = fu_plugin_cache_lookup (plugin, "cpu"); + gint exit_status = 0xff; + g_autofree gchar *toolfn = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GError) error_local = NULL; + + /* no CPU */ + if (device == NULL) + return; + + /* check for CET */ + if (!fu_cpu_device_has_flag (device, FU_CPU_DEVICE_FLAG_SHSTK) || + !fu_cpu_device_has_flag (device, FU_CPU_DEVICE_FLAG_IBT)) + return; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_INTEL_CET_ACTIVE); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); + fu_security_attrs_append (attrs, attr); + + /* check that userspace has been compiled for CET support */ + toolfn = g_build_filename (FWUPD_LIBEXECDIR, "fwupd", "fwupd-detect-cet", NULL); + if (!g_spawn_command_line_sync (toolfn, NULL, NULL, &exit_status, &error_local)) { + g_warning ("failed to test CET: %s", error_local->message); + return; + } + if (!g_spawn_check_exit_status (exit_status, &error_local)) { + g_debug ("CET does not function, not supported: %s", error_local->message); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED); + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_SUPPORTED); +} + +static void +fu_plugin_add_security_attrs_intel_tme (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuCpuDevice *device = fu_plugin_cache_lookup (plugin, "cpu"); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* no CPU */ + if (device == NULL) + return; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_ENCRYPTED_RAM); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_PROTECTION); + fu_security_attrs_append (attrs, attr); + + /* check for TME */ + if (!fu_cpu_device_has_flag (device, FU_CPU_DEVICE_FLAG_TME)) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); +} + +static void +fu_plugin_add_security_attrs_intel_smap (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuCpuDevice *device = fu_plugin_cache_lookup (plugin, "cpu"); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* no CPU */ + if (device == NULL) + return; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_INTEL_SMAP); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_PROTECTION); + fu_security_attrs_append (attrs, attr); + + /* check for SMEP and SMAP */ + if (!fu_cpu_device_has_flag (device, FU_CPU_DEVICE_FLAG_SMAP)) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + /* only Intel */ + if (fu_common_get_cpu_vendor () != FU_CPU_VENDOR_INTEL) + return; + + fu_plugin_add_security_attrs_intel_cet_enabled (plugin, attrs); + fu_plugin_add_security_attrs_intel_cet_active (plugin, attrs); + fu_plugin_add_security_attrs_intel_tme (plugin, attrs); + fu_plugin_add_security_attrs_intel_smap (plugin, attrs); } diff -Nru fwupd-1.4.5/plugins/cpu/meson.build fwupd-1.5.8/plugins/cpu/meson.build --- fwupd-1.4.5/plugins/cpu/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/cpu/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,9 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginCpu"'] +install_data(['cpu.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + shared_module('fu_plugin_cpu', fu_hash, sources : [ @@ -22,3 +26,32 @@ plugin_deps, ], ) + +if cc.has_argument('-fcf-protection') + libfwupdcethelper = static_library('fwupdcethelper', + sources : [ + 'fu-cpu-helper-cet-common.c', + ], + include_directories : [ + root_incdir, + ], + c_args : ['-fcf-protection=none'], + install : false, + ) + + executable( + 'fwupd-detect-cet', + sources : [ + 'fu-cpu-helper-cet.c', + ], + include_directories : [ + root_incdir, + ], + link_with : [ + libfwupdcethelper, + ], + c_args : ['-fcf-protection=full'], + install : true, + install_dir : join_paths(libexecdir, 'fwupd') + ) +endif diff -Nru fwupd-1.4.5/plugins/cpu/README.md fwupd-1.5.8/plugins/cpu/README.md --- fwupd-1.4.5/plugins/cpu/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/cpu/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -7,3 +7,16 @@ This plugin reads the sysfs attributes associated with CPU microcode. It displays a read-only value of the CPU microcode version loaded onto the physical CPU at fwupd startup. + +GUID Generation +--------------- + +These devices add extra instance IDs from the CPUID values, e.g. + + * `CPUID\PRO_0&FAM_06` + * `CPUID\PRO_0&FAM_06&MOD_0E` + * `CPUID\PRO_0&FAM_06&MOD_0E&STP_3` + +External interface access +------------------------- +This plugin requires no extra access. diff -Nru fwupd-1.4.5/plugins/cros-ec/cros-ec.quirk fwupd-1.5.8/plugins/cros-ec/cros-ec.quirk --- fwupd-1.4.5/plugins/cros-ec/cros-ec.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/cros-ec/cros-ec.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,19 @@ +# Servo Micro +[USB\VID_18D1&PID_501A] +Plugin = cros_ec +Summary = Servo Micro (aka "uServo") Debug Board + +# Quiche +[USB\VID_18D1&PID_5048] +Plugin = cros_ec +Summary = Quiche Reference Board + +# Baklava (D501) +[USB\VID_0502&PID_1195] +Plugin = cros_ec +Summary = D501 Device (Google Quiche derivative) + +# Gingerbread +[USB\VID_18D1&PID_5049] +Plugin = cros_ec +Summary = Gingerbread Reference Board diff -Nru fwupd-1.4.5/plugins/cros-ec/data/lsusb-servo-micro.txt fwupd-1.5.8/plugins/cros-ec/data/lsusb-servo-micro.txt --- fwupd-1.4.5/plugins/cros-ec/data/lsusb-servo-micro.txt 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/cros-ec/data/lsusb-servo-micro.txt 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,239 @@ + +Bus 003 Device 006: ID 18d1:501a Google Inc. +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 0 (Defined at Interface level) + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x18d1 Google Inc. + idProduct 0x501a + bcdDevice 1.00 + iManufacturer 1 Google Inc. + iProduct 2 Servo Micro + iSerial 3 CMO653-00166-040491U00771 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 170 + bNumInterfaces 7 + bConfigurationValue 1 + iConfiguration 4 servo_micro_v2.4.17-df61092c3 + bmAttributes 0x80 + (Bus Powered) + MaxPower 100mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 80 + bInterfaceProtocol 1 + iInterface 6 UART3 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 10 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0020 1x 32 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 83 + bInterfaceProtocol 255 + iInterface 10 Firmware update + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 10 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 2 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 81 + bInterfaceProtocol 1 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 10 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x03 EP 3 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 3 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 80 + bInterfaceProtocol 1 + iInterface 7 Servo Shell + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x84 EP 4 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 10 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x04 EP 4 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 4 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 82 + bInterfaceProtocol 1 + iInterface 5 I2C + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x85 EP 5 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 10 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x05 EP 5 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 5 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 80 + bInterfaceProtocol 1 + iInterface 8 CPU + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x86 EP 6 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 10 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x06 EP 6 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0020 1x 32 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 6 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 80 + bInterfaceProtocol 1 + iInterface 9 EC + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x87 EP 7 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 10 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x07 EP 7 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0020 1x 32 bytes + bInterval 0 +Device Status: 0x0000 + (Bus Powered) diff -Nru fwupd-1.4.5/plugins/cros-ec/fu-cros-ec-common.c fwupd-1.5.8/plugins/cros-ec/fu-cros-ec-common.c --- fwupd-1.4.5/plugins/cros-ec/fu-cros-ec-common.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/cros-ec/fu-cros-ec-common.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2020 Benson Leung + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-cros-ec-common.h" + +gboolean +fu_cros_ec_parse_version (const gchar *version_raw, + struct cros_ec_version *version, GError **error) +{ + g_auto(GStrv) v_split = NULL; + g_auto(GStrv) marker_split = NULL; + g_auto(GStrv) triplet_split = NULL; + + if (NULL == version_raw || 0 == strlen (version_raw)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "no version string to parse"); + return FALSE; + } + + /* sample version string: cheese_v1.1.1755-4da9520 */ + v_split = g_strsplit (version_raw, "_v", 2); + if (g_strv_length (v_split) < 2) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "version marker not found"); + return FALSE; + } + marker_split = g_strsplit_set (v_split[1], "-+", 2); + if (g_strv_length (marker_split) < 2) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "hash marker not found: %s", v_split[1]); + return FALSE; + } + triplet_split = g_strsplit_set (marker_split[0], ".", 3); + if (g_strv_length (triplet_split) < 3) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "improper version triplet: %s", marker_split[0]); + return FALSE; + } + g_strlcpy (version->triplet, marker_split[0], 32); + if (g_strlcpy (version->boardname, v_split[0], 32) == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "empty board name"); + return FALSE; + } + if (g_strlcpy (version->sha1, marker_split[1], 32) == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "empty SHA"); + return FALSE; + } + version->dirty = (g_strrstr(v_split[1], "+") != NULL); + + return TRUE; +} diff -Nru fwupd-1.4.5/plugins/cros-ec/fu-cros-ec-common.h fwupd-1.5.8/plugins/cros-ec/fu-cros-ec-common.h --- fwupd-1.4.5/plugins/cros-ec/fu-cros-ec-common.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/cros-ec/fu-cros-ec-common.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2020 Benson Leung + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#include "fu-plugin.h" + +#define UPDATE_PROTOCOL_VERSION 6 +#define FU_CROS_EC_STRLEN 32 + +/* + * This is the format of the update PDU header. + * + * block digest: the first four bytes of the sha1 digest of the rest of the + * structure (can be 0 on boards where digest is ignored). + * block_base: offset of this PDU into the flash SPI. + */ +typedef struct __attribute__((packed)) { + guint32 block_digest; + guint32 block_base; + /* The actual payload goes here. */ +} update_command; + +/* + * This is the frame format the host uses when sending update PDUs over USB. + * + * The PDUs are up to 1K bytes in size, they are fragmented into USB chunks of + * 64 bytes each and reassembled on the receive side before being passed to + * the flash update function. + * + * The flash update function receives the unframed PDU body (starting at the + * cmd field below), and puts its reply into the same buffer the PDU was in. + */ +struct update_frame_header { + guint32 block_size; /* Total frame size, including this field. */ + update_command cmd; +}; + +/* + * A convenience structure which allows to group together various revision + * fields of the header created by the signer (cr50-specific). + * + * These fields are compared when deciding if versions of two images are the + * same or when deciding which one of the available images to run. + */ +struct signed_header_version { + guint32 minor; + guint32 major; + guint32 epoch; +}; + +/* + * Response to the connection establishment request. + * + * When responding to the very first packet of the update sequence, the + * original USB update implementation was responding with a four byte value, + * just as to any other block of the transfer sequence. + * + * It became clear that there is a need to be able to enhance the update + * protocol, while staying backwards compatible. + * + * All newer protocol versions (starting with version 2) respond to the very + * first packet with an 8 byte or larger response, where the first 4 bytes are + * a version specific data, and the second 4 bytes - the protocol version + * number. + * + * This way the host receiving of a four byte value in response to the first + * packet is considered an indication of the target running the 'legacy' + * protocol, version 1. Receiving of an 8 byte or longer response would + * communicates the protocol version in the second 4 bytes. + */ +struct first_response_pdu { + guint32 return_value; + + /* The below fields are present in versions 2 and up. */ + + /* Type of header following (one of first_response_pdu_header_type) */ + guint16 header_type; + + /* Must be UPDATE_PROTOCOL_VERSION */ + guint16 protocol_version; + + /* In version 6 and up, a board-specific header follows. */ + union { + /* cr50 (header_type = UPDATE_HEADER_TYPE_CR50) */ + struct { + /* The below fields are present in versions 3 and up. */ + guint32 backup_ro_offset; + guint32 backup_rw_offset; + + /* The below fields are present in versions 4 and up. */ + /* + * Versions of the currently active RO and RW sections. + */ + struct signed_header_version shv[2]; + + /* The below fields are present in versions 5 and up */ + /* keyids of the currently active RO and RW sections. */ + guint32 keyid[2]; + } cr50; + /* Common code (header_type = UPDATE_HEADER_TYPE_COMMON) */ + struct { + /* Maximum PDU size */ + guint32 maximum_pdu_size; + + /* Flash protection status */ + guint32 flash_protection; + + /* Offset of the other region */ + guint32 offset; + + /* Version string of the other region */ + gchar version[FU_CROS_EC_STRLEN]; + + /* Minimum rollback version that RO will accept */ + gint32 min_rollback; + + /* RO public key version */ + guint32 key_version; + } common; + }; +}; + +enum first_response_pdu_header_type { + UPDATE_HEADER_TYPE_CR50 = 0, /* Must be 0 for backwards compatibility */ + UPDATE_HEADER_TYPE_COMMON = 1, +}; + +struct cros_ec_version { + gchar boardname[FU_CROS_EC_STRLEN]; + gchar triplet[FU_CROS_EC_STRLEN]; + gchar sha1[FU_CROS_EC_STRLEN]; + gboolean dirty; +}; + +gboolean fu_cros_ec_parse_version (const gchar *version_raw, + struct cros_ec_version *version, + GError **error); diff -Nru fwupd-1.4.5/plugins/cros-ec/fu-cros-ec-firmware.c fwupd-1.5.8/plugins/cros-ec/fu-cros-ec-firmware.c --- fwupd-1.4.5/plugins/cros-ec/fu-cros-ec-firmware.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/cros-ec/fu-cros-ec-firmware.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2020 Benson Leung + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-fmap-firmware.h" +#include "fu-cros-ec-common.h" +#include "fu-cros-ec-firmware.h" + +#define MAXSECTIONS 2 + +struct _FuCrosEcFirmware { + FuFmapFirmware parent_instance; + struct cros_ec_version version; + GPtrArray *sections; +}; + +G_DEFINE_TYPE (FuCrosEcFirmware, fu_cros_ec_firmware, FU_TYPE_FMAP_FIRMWARE) + +gboolean +fu_cros_ec_firmware_pick_sections (FuCrosEcFirmware *self, + guint32 writeable_offset, + GError **error) +{ + gboolean found = FALSE; + + for (gsize i = 0; i < self->sections->len; i++) { + FuCrosEcFirmwareSection *section = g_ptr_array_index (self->sections, i); + guint32 offset = section->offset; + + if (offset != writeable_offset) + continue; + + section->ustatus = FU_CROS_EC_FW_NEEDED; + found = TRUE; + } + + if (!found) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "no writeable section found with offset: 0x%x", + writeable_offset); + return FALSE; + } + + /* success */ + return TRUE; +} + +GPtrArray * +fu_cros_ec_firmware_get_sections (FuCrosEcFirmware *self) +{ + return self->sections; +} + +static gboolean +fu_cros_ec_firmware_parse (FuFirmware *firmware, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error) +{ + FuCrosEcFirmware *self = FU_CROS_EC_FIRMWARE (firmware); + FuFirmware *fmap_firmware = FU_FIRMWARE (firmware); + + for (gsize i = 0; i < self->sections->len; i++) { + gboolean rw = FALSE; + FuCrosEcFirmwareSection *section = g_ptr_array_index (self->sections, i); + const gchar *fmap_name; + const gchar *fmap_fwid_name; + g_autoptr(FuFirmwareImage) img = NULL; + g_autoptr(FuFirmwareImage) fwid_img = NULL; + g_autoptr(GBytes) payload_bytes = NULL; + g_autoptr(GBytes) fwid_bytes = NULL; + + if (g_strcmp0 (section->name, "RO") == 0) { + fmap_name = "EC_RO"; + fmap_fwid_name = "RO_FRID"; + } else if (g_strcmp0 (section->name, "RW") == 0) { + rw = TRUE; + fmap_name = "EC_RW"; + fmap_fwid_name = "RW_FWID"; + } else { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "incorrect section name"); + return FALSE; + } + + img = fu_firmware_get_image_by_id (fmap_firmware, + fmap_name, error); + if (img == NULL) { + g_prefix_error (error, "%s image not found: ", + fmap_name); + return FALSE; + } + + fwid_img = fu_firmware_get_image_by_id (fmap_firmware, + fmap_fwid_name, error); + if (fwid_img == NULL) { + g_prefix_error (error, "%s image not found: ", + fmap_fwid_name); + return FALSE; + } + fwid_bytes = fu_firmware_image_write (fwid_img, error); + if (fwid_bytes == NULL) { + g_prefix_error (error, + "unable to get bytes from %s: ", + fmap_fwid_name); + return FALSE; + } + if (!fu_memcpy_safe ((guint8 *) section->raw_version, + FU_FMAP_FIRMWARE_STRLEN, 0x0, + g_bytes_get_data (fwid_bytes, NULL), + g_bytes_get_size (fwid_bytes), 0x0, + g_bytes_get_size (fwid_bytes), error)) + return FALSE; + + payload_bytes = fu_firmware_image_write (img, error); + if (payload_bytes == NULL) { + g_prefix_error (error, + "unable to get bytes from %s: ", + fmap_name); + return FALSE; + } + section->offset = fu_firmware_image_get_addr (img); + section->size = g_bytes_get_size (payload_bytes); + fu_firmware_image_set_version (img, section->raw_version); + section->image_idx = fu_firmware_image_get_idx (img); + + if (!fu_cros_ec_parse_version (section->raw_version, + §ion->version, + error)) { + g_prefix_error (error, + "failed parsing firmware's version: %32s: ", + section->raw_version); + return FALSE; + } + + if (rw) { + if (!fu_cros_ec_parse_version (section->raw_version, + &self->version, + error)) { + g_prefix_error (error, + "failed parsing firmware's version: %32s: ", + section->raw_version); + return FALSE; + } + fu_firmware_set_version (firmware, + self->version.triplet); + } + } + + /* success */ + return TRUE; +} + +static void +fu_cros_ec_firmware_init (FuCrosEcFirmware *self) +{ + FuCrosEcFirmwareSection *section; + + self->sections = g_ptr_array_new_with_free_func (g_free); + section = g_new0 (FuCrosEcFirmwareSection, 1); + section->name = "RO"; + g_ptr_array_add (self->sections, section); + section = g_new0 (FuCrosEcFirmwareSection, 1); + section->name = "RW"; + g_ptr_array_add (self->sections, section); +} + +static void +fu_cros_ec_firmware_finalize (GObject *object) +{ + FuCrosEcFirmware *self = FU_CROS_EC_FIRMWARE (object); + g_ptr_array_free (self->sections, TRUE); + G_OBJECT_CLASS (fu_cros_ec_firmware_parent_class)->finalize (object); +} + +static void +fu_cros_ec_firmware_class_init (FuCrosEcFirmwareClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuFmapFirmwareClass *klass_firmware = FU_FMAP_FIRMWARE_CLASS (klass); + klass_firmware->parse = fu_cros_ec_firmware_parse; + object_class->finalize = fu_cros_ec_firmware_finalize; +} + +FuFirmware * +fu_cros_ec_firmware_new (void) +{ + return g_object_new (FU_TYPE_CROS_EC_FIRMWARE, NULL); +} diff -Nru fwupd-1.4.5/plugins/cros-ec/fu-cros-ec-firmware.h fwupd-1.5.8/plugins/cros-ec/fu-cros-ec-firmware.h --- fwupd-1.4.5/plugins/cros-ec/fu-cros-ec-firmware.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/cros-ec/fu-cros-ec-firmware.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2020 Benson Leung + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-firmware.h" +#include "fu-fmap-firmware.h" +#include "fu-cros-ec-common.h" + +#define FU_TYPE_CROS_EC_FIRMWARE (fu_cros_ec_firmware_get_type ()) +G_DECLARE_FINAL_TYPE (FuCrosEcFirmware, fu_cros_ec_firmware, FU, CROS_EC_FIRMWARE, FuFmapFirmware) + +/* + * Each RO or RW section of the new image can be in one of the following + * states. + */ +typedef enum { + FU_CROS_EC_FW_NOT_NEEDED= 0, /* Version below or equal that on the target. */ + FU_CROS_EC_FW_NOT_POSSIBLE, /* + * RO is newer, but can't be transferred due to + * target RW shortcomings. + */ + FU_CROS_EC_FW_NEEDED /* + * This section needs to be transferred to the + * target. + */ +} FuCrosEcFirmwareUpgradeStatus; + +typedef struct { + const gchar *name; + guint32 offset; + gsize size; + FuCrosEcFirmwareUpgradeStatus ustatus; + gchar raw_version[FU_FMAP_FIRMWARE_STRLEN]; + struct cros_ec_version version; + gint32 rollback; + guint32 key_version; + guint64 image_idx; +} FuCrosEcFirmwareSection; + +gboolean fu_cros_ec_firmware_pick_sections (FuCrosEcFirmware *self, + guint32 writeable_offset, + GError **error); +GPtrArray *fu_cros_ec_firmware_get_sections (FuCrosEcFirmware *self); +FuFirmware *fu_cros_ec_firmware_new (void); diff -Nru fwupd-1.4.5/plugins/cros-ec/fu-cros-ec-usb-device.c fwupd-1.5.8/plugins/cros-ec/fu-cros-ec-usb-device.c --- fwupd-1.4.5/plugins/cros-ec/fu-cros-ec-usb-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/cros-ec/fu-cros-ec-usb-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,1021 @@ +/* + * Copyright (C) 2020 Benson Leung + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-chunk.h" +#include "fu-cros-ec-usb-device.h" +#include "fu-cros-ec-common.h" +#include "fu-cros-ec-firmware.h" + +#define USB_SUBCLASS_GOOGLE_UPDATE 0x53 +#define USB_PROTOCOL_GOOGLE_UPDATE 0xff + +#define SETUP_RETRY_CNT 5 +#define MAX_BLOCK_XFER_RETRIES 10 +#define FLUSH_TIMEOUT_MS 10 +#define BULK_SEND_TIMEOUT_MS 2000 +#define BULK_RECV_TIMEOUT_MS 5000 +#define CROS_EC_REMOVE_DELAY_RE_ENUMERATE 20000 + +#define UPDATE_DONE 0xB007AB1E +#define UPDATE_EXTRA_CMD 0xB007AB1F + +enum update_extra_command { + UPDATE_EXTRA_CMD_IMMEDIATE_RESET = 0, + UPDATE_EXTRA_CMD_JUMP_TO_RW = 1, + UPDATE_EXTRA_CMD_STAY_IN_RO = 2, + UPDATE_EXTRA_CMD_UNLOCK_RW = 3, + UPDATE_EXTRA_CMD_UNLOCK_ROLLBACK = 4, + UPDATE_EXTRA_CMD_INJECT_ENTROPY = 5, + UPDATE_EXTRA_CMD_PAIR_CHALLENGE = 6, + UPDATE_EXTRA_CMD_TOUCHPAD_INFO = 7, + UPDATE_EXTRA_CMD_TOUCHPAD_DEBUG = 8, + UPDATE_EXTRA_CMD_CONSOLE_READ_INIT = 9, + UPDATE_EXTRA_CMD_CONSOLE_READ_NEXT = 10, +}; + +struct _FuCrosEcUsbDevice { + FuUsbDevice parent_instance; + guint8 iface_idx; /* bInterfaceNumber */ + guint8 ep_num; /* bEndpointAddress */ + guint16 chunk_len; /* wMaxPacketSize */ + + struct first_response_pdu targ; + guint32 writeable_offset; + guint16 protocol_version; + guint16 header_type; + struct cros_ec_version version; /* version of other region */ + struct cros_ec_version active_version; /* version of active region */ + gchar configuration[FU_CROS_EC_STRLEN]; + gboolean in_bootloader; +}; + +G_DEFINE_TYPE (FuCrosEcUsbDevice, fu_cros_ec_usb_device, FU_TYPE_USB_DEVICE) + +typedef union _START_RESP { + struct first_response_pdu rpdu; + guint32 legacy_resp; +} START_RESP; + +typedef struct { + struct update_frame_header ufh; + GBytes *image_bytes; + gsize offset; + gsize payload_size; +} FuCrosEcUsbBlockInfo; + +static gboolean +fu_cros_ec_usb_device_get_configuration (FuCrosEcUsbDevice *self, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + guint8 index; + g_autofree gchar *configuration = NULL; + +#if G_USB_CHECK_VERSION(0,3,5) + index = g_usb_device_get_configuration_index (usb_device); +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "this version of GUsb is not supported"); + return FALSE; +#endif + configuration = g_usb_device_get_string_descriptor (usb_device, + index, + error); + if (configuration == NULL) + return FALSE; + + if (g_strlcpy (self->configuration, configuration, FU_CROS_EC_STRLEN) == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "empty iConfiguration"); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_cros_ec_usb_device_find_interface (FuUsbDevice *device, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (device); + FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); + g_autoptr(GPtrArray) intfs = NULL; + + /* based on usb_updater2's find_interfacei() and find_endpoint() */ + + intfs = g_usb_device_get_interfaces (usb_device, error); + if (intfs == NULL) + return FALSE; + for (guint i = 0; i < intfs->len; i++) { + GUsbInterface *intf = g_ptr_array_index (intfs, i); + if (g_usb_interface_get_class (intf) == 255 && + g_usb_interface_get_subclass (intf) == USB_SUBCLASS_GOOGLE_UPDATE && + g_usb_interface_get_protocol (intf) == USB_PROTOCOL_GOOGLE_UPDATE) { + GUsbEndpoint *ep; + g_autoptr(GPtrArray) endpoints = NULL; + + endpoints = g_usb_interface_get_endpoints (intf); + if (NULL == endpoints || 0 == endpoints->len) + continue; + ep = g_ptr_array_index (endpoints, 0); + self->iface_idx = g_usb_interface_get_number (intf); + self->ep_num = g_usb_endpoint_get_address (ep) & 0x7f; + self->chunk_len = g_usb_endpoint_get_maximum_packet_size (ep); + + return TRUE; + } + } + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "no update interface found"); + return FALSE; +} + +static gboolean +fu_cros_ec_usb_device_open (FuDevice *device, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); + + /* FuUsbDevice->open */ + if (!FU_DEVICE_CLASS (fu_cros_ec_usb_device_parent_class)->open (device, error)) + return FALSE; + + if (!g_usb_device_claim_interface (usb_device, self->iface_idx, + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + error)) { + g_prefix_error (error, "failed to claim interface: "); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_cros_ec_usb_device_probe (FuDevice *device, GError **error) +{ + FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); + + /* FuUsbDevice->probe */ + if (!FU_DEVICE_CLASS (fu_cros_ec_usb_device_parent_class)->probe (device, error)) + return FALSE; + + /* very much like usb_updater2's usb_findit() */ + + if (!fu_cros_ec_usb_device_find_interface (FU_USB_DEVICE (device), error)) { + g_prefix_error (error, "failed to find update interface: "); + return FALSE; + } + + if (self->chunk_len == 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "wMaxPacketSize isn't valid: %" G_GUINT16_FORMAT, + self->chunk_len); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_cros_ec_usb_device_do_xfer (FuCrosEcUsbDevice * self, const guint8 *outbuf, + gsize outlen, guint8 *inbuf, gsize inlen, + gboolean allow_less, gsize *rxed_count, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + gsize actual = 0; + g_autofree guint8 *outbuf_tmp = NULL; + + /* make mutable */ + outbuf_tmp = fu_memdup_safe (outbuf, outlen, error); + if (outbuf_tmp == NULL) + return FALSE; + + /* send data out */ + if (outbuf != NULL && outlen > 0) { + if (!g_usb_device_bulk_transfer (usb_device, self->ep_num, + outbuf_tmp, outlen, + &actual, BULK_SEND_TIMEOUT_MS, + NULL, error)) { + return FALSE; + } + if (actual != outlen) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_PARTIAL_INPUT, + "only sent %" G_GSIZE_FORMAT "/%" + G_GSIZE_FORMAT " bytes", + actual, outlen); + return FALSE; + } + } + + /* read reply back */ + if (inbuf != NULL && inlen > 0) { + actual = 0; + if (!g_usb_device_bulk_transfer (usb_device, + self->ep_num | 0x80, + inbuf, inlen, + &actual, BULK_RECV_TIMEOUT_MS, + NULL, error)) { + return FALSE; + } + if (actual != inlen && !allow_less) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_PARTIAL_INPUT, + "only received %" G_GSIZE_FORMAT "/%" + G_GSIZE_FORMAT " bytes", + actual, outlen); + return FALSE; + } + } + + if (rxed_count != NULL) + *rxed_count = actual; + + return TRUE; +} + +static gboolean +fu_cros_ec_usb_device_flush (FuDevice *device, gpointer user_data, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); + gsize actual = 0; + g_autofree guint8 *inbuf = g_malloc0 (self->chunk_len); + + /* bulk transfer expected to fail normally (ie, no stale data) + * but if bulk transfer succeeds, indicates stale bytes on the device + * so this will retry until they're emptied */ + if (g_usb_device_bulk_transfer (usb_device, self->ep_num | 0x80, inbuf, + self->chunk_len, &actual, + FLUSH_TIMEOUT_MS, NULL, NULL)) { + g_debug ("flushing %" G_GSIZE_FORMAT " bytes", actual); + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "flushing %" G_GSIZE_FORMAT " bytes", actual); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_cros_ec_usb_device_recovery (FuDevice *device, GError **error) +{ + /* flush all data from endpoint to recover in case of error */ + if (!fu_device_retry (device, fu_cros_ec_usb_device_flush, + SETUP_RETRY_CNT, NULL, error)) { + g_prefix_error (error, "failed to flush device to idle state: "); + return FALSE; + } + + /* success */ + return TRUE; +} + +/* + * Channel TPM extension/vendor command over USB. The payload of the USB frame + * in this case consists of the 2 byte subcommand code concatenated with the + * command body. The caller needs to indicate if a response is expected, and + * if it is - of what maximum size. + */ +static gboolean +fu_cros_ec_usb_ext_cmd (FuDevice *device, guint16 subcommand, + gpointer cmd_body, gsize body_size, + gpointer resp, gsize *resp_size, + gboolean allow_less, GError **error) +{ + FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); + guint16 *frame_ptr; + gsize usb_msg_size = sizeof (struct update_frame_header) + + sizeof (subcommand) + body_size; + g_autofree struct update_frame_header *ufh = g_malloc0 (usb_msg_size); + + ufh->block_size = GUINT32_TO_BE (usb_msg_size); + ufh->cmd.block_digest = 0; + ufh->cmd.block_base = GUINT32_TO_BE (UPDATE_EXTRA_CMD); + frame_ptr = (guint16 *)(ufh + 1); + *frame_ptr = GUINT16_TO_BE (subcommand); + + if (body_size != 0) { + gsize offset = sizeof (struct update_frame_header) + sizeof (subcommand); + if (!fu_memcpy_safe ((guint8 *) ufh, usb_msg_size, offset, + (const guint8 *) cmd_body, body_size, + 0x0, body_size, error)) + return FALSE; + } + + return fu_cros_ec_usb_device_do_xfer (self, (const guint8 *)ufh, usb_msg_size, + (guint8 *)resp, + resp_size != NULL ? *resp_size : 0, + TRUE, NULL, error); +} + +static gboolean +fu_cros_ec_usb_device_start_request (FuDevice *device, gpointer user_data, + GError **error) +{ + FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); + guint8 *start_resp = (guint8 *) user_data; + struct update_frame_header ufh; + gsize rxed_size = 0; + + memset(&ufh, 0, sizeof (ufh)); + ufh.block_size = GUINT32_TO_BE (sizeof(ufh)); + if (!fu_cros_ec_usb_device_do_xfer (self, (const guint8 *)&ufh, sizeof(ufh), + start_resp, + sizeof(START_RESP), TRUE, + &rxed_size, error)) + return FALSE; + + /* we got something, so check for errors in response */ + if (rxed_size < 8) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_PARTIAL_INPUT, + "unexpected response size %" G_GSIZE_FORMAT, + rxed_size); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_cros_ec_usb_device_setup (FuDevice *device, GError **error) +{ + FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); + guint32 error_code; + START_RESP start_resp; + g_auto(GStrv) config_split = NULL; + + if (!fu_cros_ec_usb_device_recovery (device, error)) + return FALSE; + + /* send start request */ + if (!fu_device_retry (device, fu_cros_ec_usb_device_start_request, + SETUP_RETRY_CNT, &start_resp, error)) { + g_prefix_error (error, "failed to send start request: "); + return FALSE; + } + + self->protocol_version = GUINT16_FROM_BE (start_resp.rpdu.protocol_version); + + if (self->protocol_version < 5 || self->protocol_version > 6) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "unsupported protocol version %d", + self->protocol_version); + return FALSE; + } + self->header_type = GUINT16_FROM_BE (start_resp.rpdu.header_type); + + error_code = GUINT32_FROM_BE (start_resp.rpdu.return_value); + if (error_code != 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "target reporting error %u", error_code); + return FALSE; + } + + self->writeable_offset = GUINT32_FROM_BE (start_resp.rpdu.common.offset); + if (!fu_memcpy_safe ((guint8 *) self->targ.common.version, + FU_CROS_EC_STRLEN, 0x0, + (const guint8 *) start_resp.rpdu.common.version, + sizeof(start_resp.rpdu.common.version), 0x0, + sizeof(start_resp.rpdu.common.version), error)) + return FALSE; + self->targ.common.maximum_pdu_size = + GUINT32_FROM_BE (start_resp.rpdu.common.maximum_pdu_size); + self->targ.common.flash_protection = + GUINT32_FROM_BE (start_resp.rpdu.common.flash_protection); + self->targ.common.min_rollback = GINT32_FROM_BE (start_resp.rpdu.common.min_rollback); + self->targ.common.key_version = GUINT32_FROM_BE (start_resp.rpdu.common.key_version); + + /* get active version string and running region from iConfiguration */ + if (!fu_cros_ec_usb_device_get_configuration (self, error)) + return FALSE; + config_split = g_strsplit (self->configuration, ":", 2); + if (g_strv_length (config_split) < 2) { + /* no prefix found so fall back to offset */ + self->in_bootloader = self->writeable_offset != 0x0; + if (!fu_cros_ec_parse_version (self->configuration, + &self->active_version, error)) { + g_prefix_error (error, + "failed parsing device's version: %32s: ", + self->configuration); + return FALSE; + } + } else { + self->in_bootloader = g_strcmp0 ("RO", config_split[0]) == 0; + if (!fu_cros_ec_parse_version (config_split[1], + &self->active_version, error)) { + g_prefix_error (error, + "failed parsing device's version: %32s: ", + config_split[1]); + return FALSE; + } + } + + /* get the other region's version string from targ */ + if (!fu_cros_ec_parse_version (self->targ.common.version, + &self->version, error)) { + g_prefix_error (error, + "failed parsing device's version: %32s: ", + self->targ.common.version); + return FALSE; + } + + if (self->in_bootloader) { + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + fu_device_set_version (FU_DEVICE (device), self->version.triplet); + fu_device_set_version_bootloader (FU_DEVICE (device), + self->active_version.triplet); + } else { + fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + fu_device_set_version (FU_DEVICE (device), self->active_version.triplet); + fu_device_set_version_bootloader (FU_DEVICE (device), + self->version.triplet); + } + fu_device_add_instance_id (FU_DEVICE (device), self->version.boardname); + + /* success */ + return TRUE; +} + +static gboolean +fu_cros_ec_usb_device_transfer_block (FuDevice *device, gpointer user_data, + GError **error) +{ + FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); + FuCrosEcUsbBlockInfo *block_info = (FuCrosEcUsbBlockInfo *) user_data; + gsize image_size = 0; + gsize transfer_size = 0; + guint32 reply = 0; + g_autoptr(GBytes) block_bytes = NULL; + g_autoptr(GPtrArray) chunks = NULL; + + g_return_val_if_fail (block_info != NULL, FALSE); + + image_size = g_bytes_get_size (block_info->image_bytes); + if (block_info->offset + block_info->payload_size > image_size) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "offset %" G_GSIZE_FORMAT "plus payload_size %" + G_GSIZE_FORMAT " exceeds image size %" + G_GSIZE_FORMAT, + block_info->offset, block_info->payload_size, + image_size); + return FALSE; + } + + block_bytes = fu_common_bytes_new_offset (block_info->image_bytes, + block_info->offset, + block_info->payload_size, + error); + if (block_bytes == NULL) + return FALSE; + chunks = fu_chunk_array_new_from_bytes (block_bytes, + 0x00, + 0x00, + self->chunk_len); + + /* first send the header */ + if (!fu_cros_ec_usb_device_do_xfer (self, (const guint8 *)&block_info->ufh, + sizeof(struct update_frame_header), + NULL, + 0, FALSE, + NULL, error)) { + g_autoptr(GError) error_flush = NULL; + /* flush all data from endpoint to recover in case of error */ + if (!fu_cros_ec_usb_device_recovery (device, &error_flush)) { + g_debug ("failed to flush to idle: %s", + error_flush->message); + } + g_prefix_error (error, "failed at sending header: "); + return FALSE; + } + + /* send the block, chunk by chunk */ + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + + if (!fu_cros_ec_usb_device_do_xfer (self, + fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk), + NULL, + 0, FALSE, + NULL, error)) { + g_autoptr(GError) error_flush = NULL; + g_prefix_error (error, "failed at sending chunk: "); + + /* flush all data from endpoint to recover in case of error */ + if (!fu_cros_ec_usb_device_recovery (device, &error_flush)) { + g_debug ("failed to flush to idle: %s", + error_flush->message); + } + return FALSE; + } + } + + /* get the reply */ + if (!fu_cros_ec_usb_device_do_xfer (self, NULL, 0, + (guint8 *)&reply, sizeof (reply), + TRUE, &transfer_size, error)) { + g_autoptr(GError) error_flush = NULL; + g_prefix_error (error, "failed at reply: "); + /* flush all data from endpoint to recover in case of error */ + if (!fu_cros_ec_usb_device_recovery (device, &error_flush)) { + g_debug ("failed to flush to idle: %s", + error_flush->message); + } + return FALSE; + } + if (transfer_size == 0) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "zero bytes received for block reply"); + return FALSE; + } + if (reply != 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "error: status 0x%#x", reply); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_cros_ec_usb_device_transfer_section (FuDevice *device, + FuFirmware *firmware, + FuCrosEcFirmwareSection *section, + GError **error) +{ + FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); + const guint8 * data_ptr = NULL; + guint32 section_addr = 0; + gsize data_len = 0; + gsize offset = 0; + g_autoptr(GBytes) img_bytes = NULL; + + g_return_val_if_fail (section != NULL, FALSE); + + section_addr = section->offset; + img_bytes = fu_firmware_get_image_by_idx_bytes (firmware, + section->image_idx, + error); + if (img_bytes == NULL) { + g_prefix_error (error, "failed to find section image: "); + return FALSE; + } + + data_ptr = (const guint8 *)g_bytes_get_data (img_bytes, &data_len); + if (data_ptr == NULL || data_len != section->size) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "image and section sizes do not match: image = %" + G_GSIZE_FORMAT " bytes vs section size = %" + G_GSIZE_FORMAT " bytes", + data_len, section->size); + return FALSE; + } + + /* smart update: trim trailing bytes */ + while (data_len != 0 && (data_ptr[data_len - 1] == 0xff)) + data_len--; + g_debug ("trimmed %" G_GSIZE_FORMAT " trailing bytes", + section->size - data_len); + + g_debug ("sending 0x%zx bytes to %#x", data_len, section_addr); + while (data_len > 0) { + gsize payload_size; + guint32 block_base; + FuCrosEcUsbBlockInfo block_info; + + /* prepare the header to prepend to the block */ + block_info.image_bytes = img_bytes; + payload_size = MIN (data_len, + self->targ.common.maximum_pdu_size); + block_base = GUINT32_TO_BE (section_addr); + block_info.ufh.block_size = GUINT32_TO_BE (payload_size + + sizeof (struct update_frame_header)); + block_info.ufh.cmd.block_base = block_base; + block_info.ufh.cmd.block_digest = 0; + block_info.offset = offset; + block_info.payload_size = payload_size; + + if (!fu_device_retry (device, + fu_cros_ec_usb_device_transfer_block, + MAX_BLOCK_XFER_RETRIES, &block_info, + error)) { + g_prefix_error (error, + "failed to transfer block, %" + G_GSIZE_FORMAT " to go: ", data_len); + return FALSE; + } + data_len -= payload_size; + offset += payload_size; + section_addr += payload_size; + } + + /* success */ + return TRUE; +} + +static void +fu_cros_ec_usb_device_send_done (FuDevice *device) +{ + guint32 out = GUINT32_TO_BE (UPDATE_DONE); + g_autoptr(GError) error_local = NULL; + + /* send stop request, ignoring reply */ + if (!fu_cros_ec_usb_device_do_xfer (FU_CROS_EC_USB_DEVICE (device), + (const guint8 *)&out, sizeof (out), + (guint8 *)&out, 1, + FALSE, NULL, &error_local)) { + g_debug ("error on transfer of done: %s", + error_local->message); + } +} + +static gboolean +fu_cros_ec_usb_device_send_subcommand (FuDevice *device, guint16 subcommand, + gpointer cmd_body, gsize body_size, + gpointer resp, gsize *resp_size, + gboolean allow_less, GError **error) +{ + fu_cros_ec_usb_device_send_done (device); + + if (!fu_cros_ec_usb_ext_cmd (device, subcommand, + cmd_body, body_size, + resp, resp_size, FALSE, error)) { + g_prefix_error (error, + "failed to send subcommand %" G_GUINT16_FORMAT ": ", + subcommand); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_cros_ec_usb_device_reset_to_ro (FuDevice *device, GError **error) +{ + guint8 response; + guint16 subcommand = UPDATE_EXTRA_CMD_IMMEDIATE_RESET; + guint8 command_body[2]; /* Max command body size. */ + gsize command_body_size = 0; + gsize response_size = 1; + g_autoptr(GError) error_local = NULL; + + if (fu_device_has_custom_flag (device, "ro-written")) + fu_device_set_custom_flags (device, "ro-written,rebooting-to-ro"); + else + fu_device_set_custom_flags (device, "rebooting-to-ro"); + if (!fu_cros_ec_usb_device_send_subcommand (device, subcommand, command_body, + command_body_size, &response, + &response_size, FALSE, &error_local)) { + /* failure here is ok */ + g_debug ("ignoring failure: %s", error_local->message); + } + + /* success */ + return TRUE; +} + +static gboolean +fu_cros_ec_usb_device_jump_to_rw (FuDevice *device) +{ + guint8 response; + guint16 subcommand = UPDATE_EXTRA_CMD_JUMP_TO_RW; + guint8 command_body[2]; /* Max command body size. */ + gsize command_body_size = 0; + gsize response_size = 1; + + if (!fu_cros_ec_usb_device_send_subcommand (device, subcommand, command_body, + command_body_size, &response, + &response_size, FALSE, NULL)) { + /* bail out early here if subcommand failed, which is normal */ + return TRUE; + } + + /* Jump to rw may not work, so if we've reached here, initiate a + * full reset using immediate reset */ + subcommand = UPDATE_EXTRA_CMD_IMMEDIATE_RESET; + fu_cros_ec_usb_device_send_subcommand (device, subcommand, command_body, + command_body_size, &response, + &response_size, FALSE, NULL); + + /* success */ + return TRUE; +} + +static gboolean +fu_cros_ec_usb_device_write_firmware (FuDevice *device, + FuFirmware *firmware, + FwupdInstallFlags flags, + GError **error) +{ + FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); + GPtrArray *sections; + FuCrosEcFirmware *cros_ec_firmware = FU_CROS_EC_FIRMWARE (firmware); + gint num_txed_sections = 0; + + if (fu_device_has_custom_flag (device, "rebooting-to-ro")) { + gsize response_size = 1; + guint8 response; + guint16 subcommand = UPDATE_EXTRA_CMD_STAY_IN_RO; + guint8 command_body[2]; /* Max command body size. */ + gsize command_body_size = 0; + START_RESP start_resp; + + if (!fu_cros_ec_usb_device_send_subcommand (device, subcommand, command_body, + command_body_size, &response, + &response_size, FALSE, error)) { + g_prefix_error (error, "failed to send stay-in-ro subcommand: "); + return FALSE; + } + + /* flush all data from endpoint to recover in case of error */ + if (!fu_cros_ec_usb_device_recovery (device, error)) { + g_prefix_error (error, "failed to flush device to idle state: "); + return FALSE; + } + + /* send start request */ + if (!fu_device_retry (device, fu_cros_ec_usb_device_start_request, + SETUP_RETRY_CNT, &start_resp, error)) { + g_prefix_error (error, "failed to send start request: "); + return FALSE; + } + } + + if (fu_device_has_custom_flag (device, "rw-written") && self->in_bootloader) { + /* + * we had previously written to the rw region but somehow + * ended back up here while still in bootloader; this is + * a transitory state due to the fact that we have to boot + * through RO to get to RW. Set another write required to + * allow the RO region to auto-jump to RW + */ + fu_device_set_custom_flags (device, "special,rw-written"); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED); + return TRUE; + } + + sections = fu_cros_ec_firmware_get_sections (cros_ec_firmware); + if (sections == NULL) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid sections"); + return FALSE; + } + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + for (guint i = 0; i < sections->len; i++) { + FuCrosEcFirmwareSection *section = g_ptr_array_index (sections, i); + + if (section->ustatus == FU_CROS_EC_FW_NEEDED) { + g_autoptr(GError) error_local = NULL; + + if (!fu_cros_ec_usb_device_transfer_section (device, + firmware, + section, + &error_local)) { + if (g_error_matches (error_local, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_NOT_SUPPORTED)) { + g_debug ("failed to transfer section, trying another write, ignoring error: %s", + error_local->message); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED); + return TRUE; + } + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; + } + num_txed_sections++; + + if (self->in_bootloader) { + fu_device_set_version (FU_DEVICE (device), + section->version.triplet); + } else { + fu_device_set_version_bootloader (FU_DEVICE (device), + section->version.triplet); + } + } + } + /* send done */ + fu_cros_ec_usb_device_send_done (device); + + if (num_txed_sections == 0) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "no sections transferred"); + return FALSE; + } + + if (self->in_bootloader) { + if (fu_device_has_custom_flag (device, "ro-written")) + fu_device_set_custom_flags (device, "ro-written,rw-written"); + else + fu_device_set_custom_flags (device, "rw-written"); + } else if (fu_device_has_custom_flag (device, "rw-written")) { + fu_device_set_custom_flags (device, "ro-written,rw-written"); + } else { + fu_device_set_custom_flags (device, "ro-written"); + } + + /* logical XOR */ + if (fu_device_has_custom_flag (device, "rw-written") != + fu_device_has_custom_flag (device, "ro-written")) + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED); + + /* success */ + return TRUE; +} + +static gboolean +fu_cros_ec_usb_device_close (FuDevice *device, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); + + if (!g_usb_device_release_interface (usb_device, self->iface_idx, + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + error)) { + g_prefix_error (error, "failed to release interface: "); + return FALSE; + } + + /* FuUsbDevice->close */ + return FU_DEVICE_CLASS (fu_cros_ec_usb_device_parent_class)->close (device, error); +} + +static FuFirmware * +fu_cros_ec_usb_device_prepare_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); + FuCrosEcFirmware *cros_ec_firmware = NULL; + g_autoptr(FuFirmware) firmware = fu_cros_ec_firmware_new (); + + if (!fu_firmware_parse (firmware, fw, flags, error)) + return NULL; + cros_ec_firmware = FU_CROS_EC_FIRMWARE (firmware); + + /* pick sections */ + if (!fu_cros_ec_firmware_pick_sections (cros_ec_firmware, + self->writeable_offset, + error)) { + g_prefix_error (error, "failed to pick sections: "); + return NULL; + } + return g_steal_pointer (&firmware); +} + +static gboolean +fu_cros_ec_usb_device_attach (FuDevice *device, GError **error) +{ + FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); + + if (self->in_bootloader && fu_device_has_custom_flag (device, "special")) { + fu_device_set_remove_delay (device, CROS_EC_REMOVE_DELAY_RE_ENUMERATE); + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + return TRUE; + } + + fu_device_set_remove_delay (device, CROS_EC_REMOVE_DELAY_RE_ENUMERATE); + if (fu_device_has_custom_flag (device, "ro-written") && + !fu_device_has_custom_flag (device, "rw-written")) { + if (!fu_cros_ec_usb_device_reset_to_ro (device, error)) { + return FALSE; + } + } else { + fu_cros_ec_usb_device_jump_to_rw (device); + } + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + + /* success */ + return TRUE; +} + +static gboolean +fu_cros_ec_usb_device_detach (FuDevice *device, GError **error) +{ + FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); + + if (fu_device_has_custom_flag (device, "rw-written") && + !fu_device_has_custom_flag (device, "ro-written")) + return TRUE; + + if (self->in_bootloader) { + g_debug ("skipping immediate reboot in case of already in bootloader"); + /* in RO so skip reboot */ + return TRUE; + } else if (self->targ.common.flash_protection != 0x0) { + /* in RW, and RO region is write protected, so jump to RO */ + fu_device_set_custom_flags (device, "ro-written"); + fu_device_set_remove_delay (device, CROS_EC_REMOVE_DELAY_RE_ENUMERATE); + if (!fu_cros_ec_usb_device_reset_to_ro (device, error)) + return FALSE; + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + } + + /* success */ + return TRUE; +} + +static void +fu_cros_ec_usb_device_init (FuCrosEcUsbDevice *device) +{ + fu_device_add_protocol (FU_DEVICE (device), "com.google.usb.crosec"); + fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_internal_flag (FU_DEVICE (device), FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID); + fu_device_set_version_format (FU_DEVICE (device), FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_DUAL_IMAGE); +} + +static void +fu_cros_ec_usb_device_to_string (FuDevice *device, guint idt, GString *str) +{ + FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); + g_autofree gchar *min_rollback = NULL; + + fu_common_string_append_kv (str, idt, "GitHash", self->version.sha1); + fu_common_string_append_kb (str, idt, "Dirty", + self->version.dirty); + fu_common_string_append_ku (str, idt, "ProtocolVersion", + self->protocol_version); + fu_common_string_append_ku (str, idt, "HeaderType", + self->header_type); + fu_common_string_append_ku (str, idt, "MaxPDUSize", + self->targ.common.maximum_pdu_size); + fu_common_string_append_kx (str, idt, "FlashProtectionStatus", + self->targ.common.flash_protection); + fu_common_string_append_kv (str, idt, "RawVersion", + self->targ.common.version); + fu_common_string_append_ku (str, idt, "KeyVersion", + self->targ.common.key_version); + min_rollback = g_strdup_printf ("%" G_GINT32_FORMAT, + self->targ.common.min_rollback); + fu_common_string_append_kv (str, idt, "MinRollback", min_rollback); + fu_common_string_append_kx (str, idt, "WriteableOffset", + self->writeable_offset); +} + +static void +fu_cros_ec_usb_device_class_init (FuCrosEcUsbDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + klass_device->attach = fu_cros_ec_usb_device_attach; + klass_device->detach = fu_cros_ec_usb_device_detach; + klass_device->prepare_firmware = fu_cros_ec_usb_device_prepare_firmware; + klass_device->setup = fu_cros_ec_usb_device_setup; + klass_device->to_string = fu_cros_ec_usb_device_to_string; + klass_device->write_firmware = fu_cros_ec_usb_device_write_firmware; + klass_device->open = fu_cros_ec_usb_device_open; + klass_device->probe = fu_cros_ec_usb_device_probe; + klass_device->close = fu_cros_ec_usb_device_close; +} diff -Nru fwupd-1.4.5/plugins/cros-ec/fu-cros-ec-usb-device.h fwupd-1.5.8/plugins/cros-ec/fu-cros-ec-usb-device.h --- fwupd-1.4.5/plugins/cros-ec/fu-cros-ec-usb-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/cros-ec/fu-cros-ec-usb-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2020 Benson Leung + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +#define FU_TYPE_CROS_EC_USB_DEVICE (fu_cros_ec_usb_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuCrosEcUsbDevice, fu_cros_ec_usb_device, FU, CROS_EC_USB_DEVICE, FuUsbDevice) + +struct _FuCrosEcUsbDeviceClass +{ + FuUsbDeviceClass parent_class; +}; diff -Nru fwupd-1.4.5/plugins/cros-ec/fu-plugin-cros-ec.c fwupd-1.5.8/plugins/cros-ec/fu-plugin-cros-ec.c --- fwupd-1.4.5/plugins/cros-ec/fu-plugin-cros-ec.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/cros-ec/fu-plugin-cros-ec.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2020 Benson Leung + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" + +#include "fu-cros-ec-usb-device.h" +#include "fu-cros-ec-firmware.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_set_device_gtype (plugin, FU_TYPE_CROS_EC_USB_DEVICE); + fu_plugin_add_firmware_gtype (plugin, NULL, FU_TYPE_CROS_EC_FIRMWARE); +} diff -Nru fwupd-1.4.5/plugins/cros-ec/meson.build fwupd-1.5.8/plugins/cros-ec/meson.build --- fwupd-1.4.5/plugins/cros-ec/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/cros-ec/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,32 @@ +if get_option('gusb') +cargs = ['-DG_LOG_DOMAIN="FuPluginCrosEc"'] + +install_data(['cros-ec.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_cros_ec', + fu_hash, + sources : [ + 'fu-plugin-cros-ec.c', + 'fu-cros-ec-usb-device.c', + 'fu-cros-ec-common.c', # fuzzing + 'fu-cros-ec-firmware.c', # fuzzing + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) +endif diff -Nru fwupd-1.4.5/plugins/cros-ec/README.md fwupd-1.5.8/plugins/cros-ec/README.md --- fwupd-1.4.5/plugins/cros-ec/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/cros-ec/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,57 @@ +Chrome OS EC Support +=================== + +Introduction +------------ + +This plugin provides support for the firmware updates for Chrome OS EC +project based devices. + +Initially, it supports the USB endpoint updater, but lays the groundwork for +future updaters which use other update methods other than the USB endpoint. + +This is based on the chromeos ec project's usb_updater2 application [1]. + +Information about the USB update protocol is available at [2]. + +Firmware Format +--------------- +The daemon will decompress the cabinet archive and extract a firmware blob in +the Google fmap [3] file format. + +This plugin supports the following protocol ID: + + * com.google.usb.crosec + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_18D1&PID_501A` + +Update Behavior +--------------- + +The device usually presents in runtime mode, but on detach re-enumerates with +the same USB PID in an unlocked mode. On attach the device again re-enumerates +back to the runtime locked mode. + +For this reason the `REPLUG_MATCH_GUID` internal device flag is used so that +the bootloader and runtime modes are treated as the same device. + +Vendor ID Security +------------------ + +The vendor ID is set from the USB vendor, which is set to various different +values depending on the model and device mode. The list of USB VIDs used is: + + * `USB:0x18D1` + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. + +[1] https://chromium.googlesource.com/chromiumos/platform/ec/+/master/extra/usb_updater/usb_updater2.c +[2] https://chromium.googlesource.com/chromiumos/platform/ec/+/master/docs/usb_updater.md +[3] https://www.chromium.org/chromium-os/firmware-porting-guide/fmap diff -Nru fwupd-1.4.5/plugins/csr/csr-aiaiai.quirk fwupd-1.5.8/plugins/csr/csr-aiaiai.quirk --- fwupd-1.4.5/plugins/csr/csr-aiaiai.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/csr/csr-aiaiai.quirk 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -[DeviceInstanceId=USB\VID_0A12&PID_1337] -Plugin = csr -Name = H05 -Summary = Bluetooth Headphones -Icon = audio-headphones -Vendor = AIAIAI -[DeviceInstanceId=USB\VID_0A12&PID_1337&REV_2520] -Version = 1.2 - -[DeviceInstanceId=USB\VID_0A12&PID_4004] -Plugin = csr -Name = H60 -Summary = Bluetooth Headphones -Icon = audio-headphones -Vendor = AIAIAI diff -Nru fwupd-1.4.5/plugins/csr/data/lsusb.txt fwupd-1.5.8/plugins/csr/data/lsusb.txt --- fwupd-1.4.5/plugins/csr/data/lsusb.txt 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/csr/data/lsusb.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -Bus 001 Device 040: ID 0a12:1337 Cambridge Silicon Radio, Ltd -Device Descriptor: - bLength 18 - bDescriptorType 1 - bcdUSB 2.00 - bDeviceClass 0 - bDeviceSubClass 0 - bDeviceProtocol 0 - bMaxPacketSize0 64 - idVendor 0x0a12 Cambridge Silicon Radio, Ltd - idProduct 0x1337 - bcdDevice 25.20 - iManufacturer 0 - iProduct 2 AIAIAI H05 in - iSerial 3 ABCDEF0123456789 - bNumConfigurations 1 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 34 - bNumInterfaces 1 - bConfigurationValue 1 - iConfiguration 0 - bmAttributes 0x80 - (Bus Powered) - MaxPower 500mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 1 - bInterfaceClass 3 Human Interface Device - bInterfaceSubClass 0 - bInterfaceProtocol 0 - iInterface 0 - HID Device Descriptor: - bLength 9 - bDescriptorType 33 - bcdHID 1.00 - bCountryCode 0 Not supported - bNumDescriptors 1 - bDescriptorType 34 Report - wDescriptorLength 40 - Report Descriptors: - ** UNAVAILABLE ** - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x81 EP 1 IN - bmAttributes 3 - Transfer Type Interrupt - Synch Type None - Usage Type Data - wMaxPacketSize 0x0040 1x 64 bytes - bInterval 1 -Device Status: 0x0000 - (Bus Powered) Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/csr/data/upgrade.tdc.gz and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/csr/data/upgrade.tdc.gz differ diff -Nru fwupd-1.4.5/plugins/csr/fu-csr-device.c fwupd-1.5.8/plugins/csr/fu-csr-device.c --- fwupd-1.4.5/plugins/csr/fu-csr-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/csr/fu-csr-device.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,442 +0,0 @@ -/* - * Copyright (C) 2017-2018 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include - -#include "fu-chunk.h" -#include "fu-csr-device.h" -#include "fu-dfu-firmware.h" - -#include "dfu-common.h" - -/** - * FU_CSR_DEVICE_QUIRK_FLAG_REQUIRE_DELAY: - * - * Respect the write timeout value when performing actions. This is sometimes - * set to a huge amount of time, and so is not used by default. - * - * Since: 1.0.3 - */ -#define FU_CSR_DEVICE_FLAG_REQUIRE_DELAY "require-delay" - -typedef enum { - FU_CSR_DEVICE_QUIRK_NONE = 0, - FU_CSR_DEVICE_QUIRK_REQUIRE_DELAY = (1 << 0), - FU_CSR_DEVICE_QUIRK_LAST -} FuCsrDeviceQuirks; - -struct _FuCsrDevice -{ - FuHidDevice parent_instance; - FuCsrDeviceQuirks quirks; - DfuState dfu_state; - guint32 dnload_timeout; -}; - -G_DEFINE_TYPE (FuCsrDevice, fu_csr_device, FU_TYPE_HID_DEVICE) - -#define FU_CSR_REPORT_ID_COMMAND 0x01 -#define FU_CSR_REPORT_ID_STATUS 0x02 -#define FU_CSR_REPORT_ID_CONTROL 0x03 - -#define FU_CSR_COMMAND_HEADER_SIZE 6 /* bytes */ -#define FU_CSR_COMMAND_UPGRADE 0x01 - -#define FU_CSR_STATUS_HEADER_SIZE 7 - -#define FU_CSR_CONTROL_HEADER_SIZE 2 /* bytes */ -#define FU_CSR_CONTROL_CLEAR_STATUS 0x04 -#define FU_CSR_CONTROL_RESET 0xff - -/* maximum firmware packet, including the command header */ -#define FU_CSR_PACKET_DATA_SIZE 1023 /* bytes */ - -#define FU_CSR_DEVICE_TIMEOUT 5000 /* ms */ - -static void -fu_csr_device_to_string (FuDevice *device, guint idt, GString *str) -{ - FuCsrDevice *self = FU_CSR_DEVICE (device); - fu_common_string_append_kv (str, idt, "State", dfu_state_to_string (self->dfu_state)); - fu_common_string_append_ku (str, idt, "DownloadTimeout", self->dnload_timeout); -} - -static gboolean -fu_csr_device_attach (FuDevice *device, GError **error) -{ - guint8 buf[] = { FU_CSR_REPORT_ID_CONTROL, FU_CSR_CONTROL_RESET }; - if (!fu_hid_device_set_report (FU_HID_DEVICE (device), - FU_CSR_REPORT_ID_CONTROL, - buf, sizeof(buf), - FU_CSR_DEVICE_TIMEOUT, - FU_HID_DEVICE_FLAG_IS_FEATURE, - error)) { - g_prefix_error (error, "failed to attach: "); - return FALSE; - } - return TRUE; -} - -static gboolean -fu_csr_device_get_status (FuCsrDevice *self, GError **error) -{ - guint8 buf[64] = {0}; - - /* hit hardware */ - if (!fu_hid_device_get_report (FU_HID_DEVICE (self), - FU_CSR_REPORT_ID_STATUS, - buf, sizeof(buf), - FU_CSR_DEVICE_TIMEOUT, - FU_HID_DEVICE_FLAG_ALLOW_TRUNC | - FU_HID_DEVICE_FLAG_IS_FEATURE, - error)) { - g_prefix_error (error, "failed to GetStatus: "); - return FALSE; - } - - /* check packet */ - if (buf[0] != FU_CSR_REPORT_ID_STATUS) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "GetStatus packet-id was %i expected %i", - buf[0], FU_CSR_REPORT_ID_STATUS); - return FALSE; - } - - self->dfu_state = buf[5]; - self->dnload_timeout = buf[2] + (((guint32) buf[3]) << 8) + (((guint32) buf[4]) << 16); - g_debug ("timeout=%" G_GUINT32_FORMAT, self->dnload_timeout); - g_debug ("state=%s", dfu_state_to_string (self->dfu_state)); - g_debug ("status=%s", dfu_status_to_string (buf[6])); - return TRUE; -} - - -static gboolean -fu_csr_device_clear_status (FuCsrDevice *self, GError **error) -{ - guint8 buf[] = { FU_CSR_REPORT_ID_CONTROL, - FU_CSR_CONTROL_CLEAR_STATUS }; - - /* only clear the status if the state is error */ - if (!fu_csr_device_get_status (self, error)) - return FALSE; - if (self->dfu_state != DFU_STATE_DFU_ERROR) - return TRUE; - - /* hit hardware */ - if (!fu_hid_device_set_report (FU_HID_DEVICE (self), - FU_CSR_REPORT_ID_CONTROL, - buf, sizeof(buf), - FU_CSR_DEVICE_TIMEOUT, - FU_HID_DEVICE_FLAG_IS_FEATURE, - error)) { - g_prefix_error (error, "failed to ClearStatus: "); - return FALSE; - } - - /* check the hardware again */ - return fu_csr_device_get_status (self, error); -} - -static GBytes * -fu_csr_device_upload_chunk (FuCsrDevice *self, GError **error) -{ - guint16 data_sz; - guint8 buf[64] = {0}; - - /* hit hardware */ - if (!fu_hid_device_get_report (FU_HID_DEVICE (self), - FU_CSR_REPORT_ID_COMMAND, - buf, sizeof(buf), - FU_CSR_DEVICE_TIMEOUT, - FU_HID_DEVICE_FLAG_ALLOW_TRUNC | - FU_HID_DEVICE_FLAG_IS_FEATURE, - error)) { - g_prefix_error (error, "failed to ReadFirmware: "); - return NULL; - } - - /* check command byte */ - if (buf[0] != FU_CSR_REPORT_ID_COMMAND) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "wrong report ID %u", buf[0]); - return NULL; - } - - /* check the length */ - data_sz = fu_common_read_uint16 (&buf[1], G_LITTLE_ENDIAN); - if (data_sz + FU_CSR_COMMAND_HEADER_SIZE != (guint16) sizeof(buf)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "wrong data length %" G_GUINT16_FORMAT, - data_sz); - return NULL; - } - - /* return as bytes */ - return g_bytes_new (buf + FU_CSR_COMMAND_HEADER_SIZE, - sizeof(buf) - FU_CSR_COMMAND_HEADER_SIZE); -} - -static FuFirmware * -fu_csr_device_upload (FuDevice *device, GError **error) -{ - FuCsrDevice *self = FU_CSR_DEVICE (device); - g_autoptr(GPtrArray) chunks = NULL; - g_autoptr(GBytes) fw = NULL; - guint32 total_sz = 0; - gsize done_sz = 0; - - /* notify UI */ - fu_device_set_status (device, FWUPD_STATUS_DEVICE_READ); - - chunks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref); - for (guint32 i = 0; i < 0x3ffffff; i++) { - g_autoptr(GBytes) chunk = NULL; - gsize chunk_sz; - - /* hit hardware */ - chunk = fu_csr_device_upload_chunk (self, error); - if (chunk == NULL) - return NULL; - chunk_sz = g_bytes_get_size (chunk); - - /* get the total size using the CSR header */ - if (i == 0 && chunk_sz >= 10) { - const guint8 *buf = g_bytes_get_data (chunk, NULL); - if (memcmp (buf, "CSR-dfu", 7) == 0) { - guint16 hdr_ver; - guint16 hdr_len; - hdr_ver = fu_common_read_uint16 (buf + 8, G_LITTLE_ENDIAN); - if (hdr_ver != 0x03) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "CSR header version is " - "invalid %" G_GUINT16_FORMAT, - hdr_ver); - return NULL; - } - total_sz = fu_common_read_uint32 (buf + 10, G_LITTLE_ENDIAN); - if (total_sz == 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "CSR header data length " - "invalid %" G_GUINT32_FORMAT, - total_sz); - return NULL; - } - hdr_len = fu_common_read_uint16 (buf + 14, G_LITTLE_ENDIAN); - g_debug ("CSR header length: %" G_GUINT16_FORMAT, hdr_len); - } - } - - /* add to chunk array */ - done_sz += chunk_sz; - g_ptr_array_add (chunks, g_steal_pointer (&chunk)); - fu_device_set_progress_full (device, done_sz, (gsize) total_sz); - - /* we're done */ - if (chunk_sz < 64 - FU_CSR_COMMAND_HEADER_SIZE) - break; - } - - /* notify UI */ - fw = dfu_utils_bytes_join_array (chunks); - return fu_firmware_new_from_bytes (fw); -} - -static gboolean -fu_csr_device_download_chunk (FuCsrDevice *self, guint16 idx, GBytes *chunk, GError **error) -{ - const guint8 *chunk_data; - gsize chunk_sz = 0; - guint8 buf[FU_CSR_PACKET_DATA_SIZE] = {0}; - - /* too large? */ - chunk_data = g_bytes_get_data (chunk, &chunk_sz); - if (chunk_sz + FU_CSR_COMMAND_HEADER_SIZE > FU_CSR_PACKET_DATA_SIZE) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "packet was too large: %" G_GSIZE_FORMAT, chunk_sz); - return FALSE; - } - g_debug ("writing %" G_GSIZE_FORMAT " bytes of data", chunk_sz); - - /* create packet */ - buf[0] = FU_CSR_REPORT_ID_COMMAND; - buf[1] = FU_CSR_COMMAND_UPGRADE; - fu_common_write_uint16 (&buf[2], idx, G_LITTLE_ENDIAN); - fu_common_write_uint16 (&buf[4], chunk_sz, G_LITTLE_ENDIAN); - if (!fu_memcpy_safe (buf, sizeof(buf), FU_CSR_COMMAND_HEADER_SIZE, /* dst */ - chunk_data, chunk_sz, 0x0, /* src */ - chunk_sz, error)) - return FALSE; - - /* hit hardware */ - if (!fu_hid_device_set_report (FU_HID_DEVICE (self), - FU_CSR_REPORT_ID_COMMAND, - buf, sizeof(buf), - FU_CSR_DEVICE_TIMEOUT, - FU_HID_DEVICE_FLAG_IS_FEATURE, - error)) { - g_prefix_error (error, "failed to Upgrade: "); - return FALSE; - } - - /* wait for hardware */ - if (self->quirks & FU_CSR_DEVICE_QUIRK_REQUIRE_DELAY) { - g_debug ("sleeping for %ums", self->dnload_timeout); - g_usleep (self->dnload_timeout * 1000); - } - - /* get status */ - if (!fu_csr_device_get_status (self, error)) - return FALSE; - - /* is still busy */ - if (self->dfu_state == DFU_STATE_DFU_DNBUSY) { - g_debug ("busy, so sleeping a bit longer"); - g_usleep (G_USEC_PER_SEC); - if (!fu_csr_device_get_status (self, error)) - return FALSE; - } - - /* not correct */ - if (self->dfu_state != DFU_STATE_DFU_DNLOAD_IDLE && - self->dfu_state != DFU_STATE_DFU_IDLE) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "device did not return to IDLE"); - return FALSE; - } - - /* success */ - return TRUE; -} - -static FuFirmware * -fu_csr_device_prepare_firmware (FuDevice *device, - GBytes *fw, - FwupdInstallFlags flags, - GError **error) -{ - g_autoptr(FuFirmware) firmware = fu_dfu_firmware_new (); - - /* parse the file */ - if (!fu_firmware_parse (firmware, fw, flags, error)) - return NULL; - if (g_getenv ("FWUPD_CSR_VERBOSE") != NULL) { - g_autofree gchar *fw_str = NULL; - fw_str = fu_firmware_to_string (firmware); - g_debug ("%s", fw_str); - } - - /* success */ - return g_steal_pointer (&firmware); -} - -static gboolean -fu_csr_device_download (FuDevice *device, - FuFirmware *firmware, - FwupdInstallFlags flags, - GError **error) -{ - FuCsrDevice *self = FU_CSR_DEVICE (device); - guint16 idx; - g_autoptr(GBytes) blob_empty = NULL; - g_autoptr(GBytes) blob = NULL; - g_autoptr(GPtrArray) chunks = NULL; - - /* get default image */ - blob = fu_firmware_get_image_default_bytes (firmware, error); - if (blob == NULL) - return FALSE; - - /* notify UI */ - fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); - - /* create chunks */ - chunks = fu_chunk_array_new_from_bytes (blob, 0x0, 0x0, - FU_CSR_PACKET_DATA_SIZE - FU_CSR_COMMAND_HEADER_SIZE); - - /* send to hardware */ - for (idx = 0; idx < chunks->len; idx++) { - FuChunk *chk = g_ptr_array_index (chunks, idx); - g_autoptr(GBytes) blob_tmp = g_bytes_new_static (chk->data, chk->data_sz); - - /* send packet */ - if (!fu_csr_device_download_chunk (self, idx, blob_tmp, error)) - return FALSE; - - /* update progress */ - fu_device_set_progress_full (device, - (gsize) idx, (gsize) chunks->len); - } - - /* all done */ - blob_empty = g_bytes_new (NULL, 0); - return fu_csr_device_download_chunk (self, idx, blob_empty, error); -} - -static gboolean -fu_csr_device_probe (FuUsbDevice *device, GError **error) -{ - FuCsrDevice *self = FU_CSR_DEVICE (device); - - /* devices have to be whitelisted */ - if (fu_device_has_custom_flag (FU_DEVICE (device), - FU_CSR_DEVICE_FLAG_REQUIRE_DELAY)) - self->quirks = FU_CSR_DEVICE_QUIRK_REQUIRE_DELAY; - - /* hardcoded */ - fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_UPDATABLE); - - /* success */ - return TRUE; -} - -static gboolean -fu_csr_device_setup (FuDevice *device, GError **error) -{ - FuCsrDevice *self = FU_CSR_DEVICE (device); - - if (!fu_csr_device_clear_status (self, error)) - return FALSE; - - /* success */ - return TRUE; -} - -static void -fu_csr_device_init (FuCsrDevice *self) -{ - fu_device_set_protocol (FU_DEVICE (self), "com.qualcomm.dfu"); -} - -static void -fu_csr_device_class_init (FuCsrDeviceClass *klass) -{ - FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); - klass_device->to_string = fu_csr_device_to_string; - klass_device->write_firmware = fu_csr_device_download; - klass_device->read_firmware = fu_csr_device_upload; - klass_device->prepare_firmware = fu_csr_device_prepare_firmware; - klass_device->attach = fu_csr_device_attach; - klass_device->setup = fu_csr_device_setup; - klass_usb_device->probe = fu_csr_device_probe; -} diff -Nru fwupd-1.4.5/plugins/csr/fu-csr-device.h fwupd-1.5.8/plugins/csr/fu-csr-device.h --- fwupd-1.4.5/plugins/csr/fu-csr-device.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/csr/fu-csr-device.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -/* - * Copyright (C) 2017-2018 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include "fu-hid-device.h" -#include "fu-plugin.h" - -#define FU_TYPE_CSR_DEVICE (fu_csr_device_get_type ()) -G_DECLARE_FINAL_TYPE (FuCsrDevice, fu_csr_device, FU, CSR_DEVICE, FuHidDevice) diff -Nru fwupd-1.4.5/plugins/csr/fu-plugin-csr.c fwupd-1.5.8/plugins/csr/fu-plugin-csr.c --- fwupd-1.4.5/plugins/csr/fu-plugin-csr.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/csr/fu-plugin-csr.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2017 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include "fu-plugin-vfuncs.h" -#include "fu-hash.h" - -#include "fu-csr-device.h" - -void -fu_plugin_init (FuPlugin *plugin) -{ - fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); - fu_plugin_set_device_gtype (plugin, FU_TYPE_CSR_DEVICE); -} diff -Nru fwupd-1.4.5/plugins/csr/meson.build fwupd-1.5.8/plugins/csr/meson.build --- fwupd-1.4.5/plugins/csr/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/csr/meson.build 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -cargs = ['-DG_LOG_DOMAIN="FuPluginCsr"'] - -install_data(['csr-aiaiai.quirk'], - install_dir: join_paths(datadir, 'fwupd', 'quirks.d') -) - -shared_module('fu_plugin_csr', - fu_hash, - sources : [ - 'fu-csr-device.c', - 'fu-plugin-csr.c', - ], - include_directories : [ - root_incdir, - fwupd_incdir, - fwupdplugin_incdir, - plugindfu_incdir, - ], - install : true, - install_dir: plugin_dir, - c_args : cargs, - dependencies : [ - plugin_deps, - ], - link_with : [ - fwupdplugin, - dfu, - ], -) diff -Nru fwupd-1.4.5/plugins/csr/README.md fwupd-1.5.8/plugins/csr/README.md --- fwupd-1.4.5/plugins/csr/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/csr/README.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -CSR Support -=========== - -Introduction ------------- - -CSR is often called “driverless DFU” and is used only by BlueCore chips from -Cambridge Silicon Radio (now owned by Qualcomm). The driverless just means that -it's DFU like, and is routed over HID. - -CSR is a ODM that makes most of the Bluetooth audio chips in vendor hardware. -The hardware vendor can enable or disable features on the CSR microcontroller -depending on licensing options (for instance echo cancellation), and there’s -even a little virtual machine to do simple vendor-specific things. - -All the CSR chips are updatable in-field, and most vendors issue updates to fix -sound quality issues or to add support for new protocols or devices. - -Firmware Format ---------------- - -The daemon will decompress the cabinet archive and extract a firmware blob in -DFU file format. - -This plugin supports the following protocol ID: - - * com.qualcomm.dfu - -GUID Generation ---------------- - -These devices use the standard USB DeviceInstanceId values, e.g. - - * `USB\VID_0A12&PID_1337&REV_2520` - * `USB\VID_0A12&PID_1337` - * `USB\VID_0A12` - -Vendor ID Security ------------------- - -The vendor ID is set from the USB vendor, in this instance set to `USB:0x0A12` diff -Nru fwupd-1.4.5/plugins/dell/dell.quirk fwupd-1.5.8/plugins/dell/dell.quirk --- fwupd-1.4.5/plugins/dell/dell.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dell/dell.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,34 +1,34 @@ # Realtek NIC in Dell docks -[DeviceInstanceId=USB\VID_0BDA&PID_8153] +[USB\VID_0BDA&PID_8153] Plugin = dell # Dell TB16/TB18 cable -[Guid=TBT-00d4b051] +[TBT-00d4b051] Plugin = thunderbolt ParentGuid = e7ca1f36-bf73-4574-afe6-a4ccacabf479 # Dell TB16/TB18 dock -[Guid=TBT-00d4b054] +[TBT-00d4b054] Plugin = thunderbolt ParentGuid = e7ca1f36-bf73-4574-afe6-a4ccacabf479 # Dell WD15 dock -[Guid=MST-wd15-vmm3332-274] +[MST-wd15-vmm3332-274] Plugin = synaptics_mst ParentGuid = e7ca1f36-bf73-4574-afe6-a4ccacabf479 # Dell TB16 dock -[Guid=MST-tb16-vmm3320-274] +[MST-tb16-vmm3320-274] Plugin = synaptics_mst ParentGuid = e7ca1f36-bf73-4574-afe6-a4ccacabf479 -[Guid=MST-tb16-vmm3330-274] +[MST-tb16-vmm3330-274] Plugin = synaptics_mst ParentGuid = e7ca1f36-bf73-4574-afe6-a4ccacabf479 #Dell TB18 dock -[Guid=MST-tb18-vmm3320-274] +[MST-tb18-vmm3320-274] Plugin = synaptics_mst ParentGuid = e7ca1f36-bf73-4574-afe6-a4ccacabf479 -[Guid=MST-tb18-vmm3330-274] +[MST-tb18-vmm3330-274] Plugin = synaptics_mst ParentGuid = e7ca1f36-bf73-4574-afe6-a4ccacabf479 diff -Nru fwupd-1.4.5/plugins/dell/fu-dell-smi.c fwupd-1.5.8/plugins/dell/fu-dell-smi.c --- fwupd-1.4.5/plugins/dell/fu-dell-smi.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dell/fu-dell-smi.c 2021-03-31 20:08:32.000000000 +0000 @@ -23,13 +23,6 @@ guint32 reserved; }; -/* This is used for host flash GUIDs */ -typedef union _ADDR_UNION{ - uint8_t *buf; - efi_guid_t *guid; -} ADDR_UNION; -#pragma pack() - static void _dell_smi_obj_free (FuDellSmiObj *obj) { @@ -229,37 +222,4 @@ return FALSE; } return TRUE; -} - -gboolean -fu_dell_toggle_host_mode (FuDellSmiObj *smi_obj, const efi_guid_t guid, int mode) -{ - gint ret; - ADDR_UNION buf; - - dell_smi_obj_set_class (smi_obj->smi, DACI_FLASH_INTERFACE_CLASS); - dell_smi_obj_set_select (smi_obj->smi, DACI_FLASH_INTERFACE_SELECT); - dell_smi_obj_set_arg (smi_obj->smi, cbARG1, DACI_FLASH_ARG_FLASH_MODE); - dell_smi_obj_set_arg (smi_obj->smi, cbARG4, mode); - /* needs to be padded with an empty GUID */ - buf.buf = dell_smi_obj_make_buffer_frombios_withoutheader(smi_obj->smi, - cbARG2, - sizeof(efi_guid_t) * 2); - if (!buf.buf) { - g_debug ("Failed to initialize SMI buffer"); - return FALSE; - } - *buf.guid = guid; - ret = dell_smi_obj_execute(smi_obj->smi); - if (ret != SMI_SUCCESS){ - g_debug ("failed to execute SMI: %d", ret); - return FALSE; - } - - ret = dell_smi_obj_get_res(smi_obj->smi, cbRES1); - if (ret != SMI_SUCCESS) { - g_debug ("SMI execution returned error: %d", ret); - return FALSE; - } - return TRUE; } diff -Nru fwupd-1.4.5/plugins/dell/fu-dell-smi.h fwupd-1.5.8/plugins/dell/fu-dell-smi.h --- fwupd-1.4.5/plugins/dell/fu-dell-smi.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dell/fu-dell-smi.h 2021-03-31 20:08:32.000000000 +0000 @@ -9,7 +9,6 @@ #include "fu-device.h" #include #include -#include typedef struct { struct dell_smi_obj *smi; @@ -95,9 +94,6 @@ fu_dell_toggle_dock_mode (FuDellSmiObj *smi_obj, guint32 new_mode, guint32 dock_location, GError **error); -gboolean -fu_dell_toggle_host_mode (FuDellSmiObj *smi_obj, const efi_guid_t guid, int mode); - /* SMI return values used */ #define SMI_SUCCESS 0 #define SMI_INVALID_BUFFER -6 diff -Nru fwupd-1.4.5/plugins/dell/fu-plugin-dell.c fwupd-1.5.8/plugins/dell/fu-plugin-dell.c --- fwupd-1.4.5/plugins/dell/fu-plugin-dell.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dell/fu-plugin-dell.c 2021-03-31 20:08:32.000000000 +0000 @@ -20,7 +20,6 @@ #include "fwupd-common.h" #include "fu-plugin-dell.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #include "fu-device-metadata.h" /* These are used to indicate the status of a previous DELL flash */ @@ -93,7 +92,7 @@ /** * Devices that should allow modeswitching */ -static guint16 tpm_switch_whitelist[] = {0x06F2, 0x06F3, 0x06DD, 0x06DE, 0x06DF, +static guint16 tpm_switch_allowlist[] = {0x06F2, 0x06F3, 0x06DD, 0x06DE, 0x06DF, 0x06DB, 0x06DC, 0x06BB, 0x06C6, 0x06BA, 0x06B9, 0x05CA, 0x06C7, 0x06B7, 0x06E0, 0x06E5, 0x06D9, 0x06DA, 0x06E4, 0x0704, @@ -106,7 +105,7 @@ /** * Dell device types to run */ -static guint8 enclosure_whitelist [] = { 0x03, /* desktop */ +static guint8 enclosure_allowlist [] = { 0x03, /* desktop */ 0x04, /* low profile desktop */ 0x06, /* mini tower */ 0x07, /* tower */ @@ -180,8 +179,8 @@ value = g_bytes_get_data (enclosure, &len); if (len == 0) return FALSE; - for (guint i = 0; i < G_N_ELEMENTS (enclosure_whitelist); i++) { - if (enclosure_whitelist[i] == value[0]) + for (guint i = 0; i < G_N_ELEMENTS (enclosure_allowlist); i++) { + if (enclosure_allowlist[i] == value[0]) return TRUE; } @@ -269,7 +268,7 @@ dock_name = g_strdup_printf ("Dell %s", dock_type); } fu_device_set_vendor (dev, "Dell Inc."); - fu_device_set_vendor_id (dev, "PCI:0x1028"); + fu_device_add_vendor_id (dev, "PCI:0x1028"); fu_device_set_name (dev, dock_name); fu_device_set_metadata (dev, FU_DEVICE_METADATA_UEFI_DEVICE_KIND, "device-firmware"); if (type == DOCK_TYPE_TB16) { @@ -286,9 +285,6 @@ if (fu_plugin_dell_capsule_supported (plugin)) { fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_REBOOT); - } else { - fu_device_set_update_error (dev, - "UEFI capsule updates turned off in BIOS setup"); } } @@ -297,9 +293,9 @@ } gboolean -fu_plugin_usb_device_added (FuPlugin *plugin, - FuUsbDevice *device, - GError **error) +fu_plugin_backend_device_added (FuPlugin *plugin, + FuDevice *device, + GError **error) { FuPluginData *data = fu_plugin_get_data (plugin); FwupdVersionFormat version_format = FWUPD_VERSION_FORMAT_DELL_BIOS; @@ -314,11 +310,20 @@ gboolean old_ec = FALSE; g_autofree gchar *flash_ver_str = NULL; + /* not interesting */ + if (!FU_IS_USB_DEVICE (device)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "not a USB device"); + return FALSE; + } + /* don't look up immediately if a dock is connected as that would mean a SMI on every USB device that showed up on the system */ if (!data->smi_obj->fake_smbios) { - vid = fu_usb_device_get_vid (device); - pid = fu_usb_device_get_pid (device); + vid = fu_usb_device_get_vid (FU_USB_DEVICE (device)); + pid = fu_usb_device_get_pid (FU_USB_DEVICE (device)); platform = fu_device_get_physical_id (FU_DEVICE (device)); } else { vid = data->fake_vid; @@ -608,6 +613,7 @@ "failed to read TPM vendor string"); return FALSE; } + fu_device_set_metadata (dev, "TpmFamily", family); /* these are not guaranteed by spec and may be NULL */ vendor2 = fu_plugin_dell_get_tpm_capability (ctx, TPM2_PT_VENDOR_STRING_2); @@ -693,8 +699,8 @@ else if (system_id == 0) return FALSE; - for (guint i = 0; i < G_N_ELEMENTS (tpm_switch_whitelist); i++) { - if (tpm_switch_whitelist[i] == system_id) { + for (guint i = 0; i < G_N_ELEMENTS (tpm_switch_allowlist); i++) { + if (tpm_switch_allowlist[i] == system_id) { can_switch_modes = TRUE; } } @@ -721,7 +727,7 @@ fu_device_add_instance_id (dev, tpm_guid_raw); fu_device_add_instance_id (dev, "system-tpm"); fu_device_set_vendor (dev, "Dell Inc."); - fu_device_set_vendor_id (dev, "PCI:0x1028"); + fu_device_add_vendor_id (dev, "PCI:0x1028"); fu_device_set_name (dev, pretty_tpm_name); fu_device_set_summary (dev, "Platform TPM device"); fu_device_set_version_format (dev, FWUPD_VERSION_FORMAT_QUAD); @@ -734,9 +740,6 @@ if (fu_plugin_dell_capsule_supported (plugin)) { fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_REBOOT); - } else { - fu_device_set_update_error (dev, - "UEFI capsule updates turned off in BIOS setup"); } fu_device_set_flashes_left (dev, out->flashes_left); } else { @@ -750,6 +753,8 @@ if (!fu_device_setup (dev, error)) return FALSE; fu_plugin_device_register (plugin, dev); + fu_plugin_add_report_metadata (plugin, "TpmFamily", + fu_device_get_metadata (dev, "TpmFamily")); /* build alternate device node */ if (can_switch_modes) { @@ -757,7 +762,7 @@ fu_device_set_id (dev_alt, tpm_id_alt); fu_device_add_instance_id (dev_alt, tpm_guid_raw_alt); fu_device_set_vendor (dev, "Dell Inc."); - fu_device_set_vendor_id (dev, "PCI:0x1028"); + fu_device_add_vendor_id (dev, "PCI:0x1028"); fu_device_set_name (dev_alt, pretty_tpm_name_alt); fu_device_set_summary (dev_alt, "Alternate mode for platform TPM device"); fu_device_add_flag (dev_alt, FWUPD_DEVICE_FLAG_INTERNAL); @@ -808,7 +813,7 @@ /* the kernel returns lowercase in sysfs, need to match it */ device_id = g_strdup_printf ("TBT-%04x%04x", 0x00d4u, (unsigned) system_id); - fu_device_set_vendor_id (device, vendor_id); + fu_device_add_vendor_id (device, vendor_id); fu_device_add_instance_id (device, device_id); fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); } @@ -840,7 +845,7 @@ data->smi_obj->fake_smbios = TRUE; /* make sure that UEFI plugin is ready to receive devices */ - fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_AFTER, "uefi"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_AFTER, "uefi_capsule"); /* our TPM device is upgradable! */ fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_BETTER_THAN, "tpm"); @@ -892,10 +897,14 @@ */ sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); esrtdir = g_build_filename (sysfsfwdir, "efi", "esrt", NULL); - if (g_file_test (esrtdir, G_FILE_TEST_EXISTS)) { + if (g_file_test (esrtdir, G_FILE_TEST_EXISTS)) data->capsule_supported = TRUE; - } else { - g_debug ("UEFI capsule firmware updating not supported"); + + /* capsules not supported */ + if (!fu_plugin_dell_capsule_supported (plugin)) { + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_USER_WARNING); + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE); + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_CAPSULES_UNSUPPORTED); } return TRUE; diff -Nru fwupd-1.4.5/plugins/dell/fu-self-test.c fwupd-1.5.8/plugins/dell/fu-self-test.c --- fwupd-1.4.5/plugins/dell/fu-self-test.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dell/fu-self-test.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2017 Richard Hughes + * Copyright (C) 2015 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -14,7 +14,11 @@ #include "fu-plugin-private.h" #include "fu-plugin-dell.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" + +typedef struct { + FuPlugin *plugin_uefi_capsule; + FuPlugin *plugin_dell; +} FuTest; static FuDevice * _find_device_by_id (GPtrArray *devices, const gchar *device_id) @@ -55,78 +59,58 @@ FuDevice *device, gpointer user_data) { - FuPlugin *plugin_uefi = FU_PLUGIN (user_data); + FuPlugin *plugin_uefi_capsule = FU_PLUGIN (user_data); g_autofree gchar *dbg = fu_device_to_string (device); g_debug ("registering device: %s", dbg); - fu_plugin_runner_device_register (plugin_uefi, device); + fu_plugin_runner_device_register (plugin_uefi_capsule, device); } static void -fu_plugin_dell_tpm_func (void) +fu_plugin_dell_tpm_func (gconstpointer user_data) { + FuTest *self = (FuTest *) user_data; FuDevice *device_v12; FuDevice *device_v20; const guint8 fw[30] = { 'F', 'W', 0x00 }; gboolean ret; + gulong added_id; + gulong register_id; struct tpm_status tpm_out; const gchar *tpm_server_running = g_getenv ("TPM_SERVER_RUNNING"); - g_autofree gchar *pluginfn_uefi = NULL; - g_autofree gchar *pluginfn_dell = NULL; - g_autoptr(FuPlugin) plugin_dell = NULL; - g_autoptr(FuPlugin) plugin_uefi = NULL; g_autoptr(GBytes) blob_fw = g_bytes_new_static (fw, sizeof(fw)); g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) devices = NULL; - pluginfn_uefi = g_build_filename (PLUGINBUILDDIR, "..", "uefi", - "libfu_plugin_uefi." G_MODULE_SUFFIX, - NULL); - pluginfn_dell = g_build_filename (PLUGINBUILDDIR, - "libfu_plugin_dell." G_MODULE_SUFFIX, - NULL); +#ifdef HAVE_GETUID + if (tpm_server_running == NULL && + (getuid () != 0 || geteuid () != 0)) { + g_test_skip ("TPM tests require simulated TPM2.0 running or need root access with physical TPM"); + return; + } +#endif memset (&tpm_out, 0x0, sizeof(tpm_out)); - plugin_uefi = fu_plugin_new (); - ret = fu_plugin_open (plugin_uefi, pluginfn_uefi, &error); - g_assert_no_error (error); - g_assert (ret); - ret = fu_plugin_runner_startup (plugin_uefi, &error); - g_assert_no_error (error); - g_assert (ret); devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - g_signal_connect (plugin_uefi, "device-added", + added_id = + g_signal_connect (self->plugin_uefi_capsule, "device-added", G_CALLBACK (_plugin_device_added_cb), devices); - plugin_dell = fu_plugin_new (); - ret = fu_plugin_open (plugin_dell, pluginfn_dell, &error); - g_assert_no_error (error); - g_assert (ret); - ret = fu_plugin_runner_startup (plugin_dell, &error); - g_assert_no_error (error); - g_assert (ret); - g_signal_connect (plugin_dell, "device-register", + register_id = + g_signal_connect (self->plugin_dell, "device-register", G_CALLBACK (fu_engine_plugin_device_register_cb), - plugin_uefi); - ret = fu_plugin_runner_coldplug (plugin_dell, &error); + self->plugin_uefi_capsule); + ret = fu_plugin_runner_coldplug (self->plugin_dell, &error); g_assert_no_error (error); g_assert (ret); -#ifdef HAVE_GETUID - if (tpm_server_running == NULL && - (getuid () != 0 || geteuid () != 0)) { - g_test_skip ("TPM tests require simulated TPM2.0 running or need root access with physical TPM"); - return; - } -#endif - /* inject fake data (no TPM) */ tpm_out.ret = -2; - fu_plugin_dell_inject_fake_data (plugin_dell, + fu_plugin_dell_inject_fake_data (self->plugin_dell, (guint32 *) &tpm_out, 0, 0, NULL, FALSE); - ret = fu_plugin_dell_detect_tpm (plugin_dell, &error); + ret = fu_plugin_dell_detect_tpm (self->plugin_dell, &error); g_assert_no_error (error); g_assert_false (ret); g_assert_cmpint (devices->len, ==, 0); @@ -141,10 +125,10 @@ tpm_out.fw_version = 0; tpm_out.status = TPM_EN_MASK | (TPM_1_2_MODE << 8); tpm_out.flashes_left = 0; - fu_plugin_dell_inject_fake_data (plugin_dell, + fu_plugin_dell_inject_fake_data (self->plugin_dell, (guint32 *) &tpm_out, 0, 0, NULL, TRUE); - ret = fu_plugin_dell_detect_tpm (plugin_dell, &error); + ret = fu_plugin_dell_detect_tpm (self->plugin_dell, &error); g_assert_true (ret); g_assert_cmpint (devices->len, ==, 2); @@ -159,7 +143,7 @@ g_assert_false (fu_device_has_flag (device_v12, FWUPD_DEVICE_FLAG_UPDATABLE)); /* try to unlock 2.0 */ - ret = fu_plugin_runner_unlock (plugin_uefi, device_v20, &error); + ret = fu_plugin_runner_unlock (self->plugin_uefi_capsule, device_v20, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED); g_assert_false (ret); g_clear_error (&error); @@ -175,10 +159,10 @@ */ tpm_out.status = TPM_EN_MASK | TPM_OWN_MASK | (TPM_1_2_MODE << 8); tpm_out.flashes_left = 125; - fu_plugin_dell_inject_fake_data (plugin_dell, + fu_plugin_dell_inject_fake_data (self->plugin_dell, (guint32 *) &tpm_out, 0, 0, NULL, TRUE); - ret = fu_plugin_dell_detect_tpm (plugin_dell, &error); + ret = fu_plugin_dell_detect_tpm (self->plugin_dell, &error); g_assert_no_error (error); g_assert (ret); @@ -190,7 +174,7 @@ /* try to unlock 2.0 */ device_v20 = _find_device_by_name (devices, "TPM 2.0"); g_assert_nonnull (device_v20); - ret = fu_plugin_runner_unlock (plugin_uefi, device_v20, &error); + ret = fu_plugin_runner_unlock (self->plugin_uefi_capsule, device_v20, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED); g_assert_false (ret); g_clear_error (&error); @@ -206,10 +190,10 @@ */ tpm_out.status = TPM_EN_MASK | (TPM_1_2_MODE << 8); tpm_out.flashes_left = 125; - fu_plugin_dell_inject_fake_data (plugin_dell, + fu_plugin_dell_inject_fake_data (self->plugin_dell, (guint32 *) &tpm_out, 0, 0, NULL, TRUE); - ret = fu_plugin_dell_detect_tpm (plugin_dell, &error); + ret = fu_plugin_dell_detect_tpm (self->plugin_dell, &error); g_assert_no_error (error); g_assert (ret); @@ -222,7 +206,7 @@ g_assert_false (fu_device_has_flag (device_v20, FWUPD_DEVICE_FLAG_UPDATABLE)); /* try to unlock 2.0 */ - ret = fu_plugin_runner_unlock (plugin_uefi, device_v20, &error); + ret = fu_plugin_runner_unlock (self->plugin_uefi_capsule, device_v20, &error); g_assert_no_error (error); g_assert (ret); @@ -241,10 +225,10 @@ */ tpm_out.status = TPM_EN_MASK | (TPM_2_0_MODE << 8); tpm_out.flashes_left = 1; - fu_plugin_dell_inject_fake_data (plugin_dell, + fu_plugin_dell_inject_fake_data (self->plugin_dell, (guint32 *) &tpm_out, 0, 0, NULL, TRUE); - ret = fu_plugin_dell_detect_tpm (plugin_dell, &error); + ret = fu_plugin_dell_detect_tpm (self->plugin_dell, &error); g_assert_no_error (error); g_assert (ret); @@ -257,68 +241,54 @@ g_assert_false (fu_device_has_flag (device_v12, FWUPD_DEVICE_FLAG_UPDATABLE)); /* With one flash left we need an override */ - ret = fu_plugin_runner_update (plugin_uefi, device_v20, blob_fw, + ret = fu_plugin_runner_update (self->plugin_uefi_capsule, device_v20, blob_fw, FWUPD_INSTALL_FLAG_NONE, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED); g_assert_false (ret); g_clear_error (&error); /* test override */ - ret = fu_plugin_runner_update (plugin_uefi, device_v20, blob_fw, + ret = fu_plugin_runner_update (self->plugin_uefi_capsule, device_v20, blob_fw, FWUPD_INSTALL_FLAG_FORCE, &error); g_assert_no_error (error); g_assert (ret); + + /* all */ + g_signal_handler_disconnect (self->plugin_uefi_capsule, added_id); + g_signal_handler_disconnect (self->plugin_dell, register_id); } static void -fu_plugin_dell_dock_func (void) +fu_plugin_dell_dock_func (gconstpointer user_data) { + FuTest *self = (FuTest *) user_data; gboolean ret; guint32 out[4] = { 0x0, 0x0, 0x0, 0x0 }; DOCK_UNION buf; DOCK_INFO *dock_info; - g_autofree gchar *pluginfn_uefi = NULL; - g_autofree gchar *pluginfn_dell = NULL; g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) devices = NULL; - g_autoptr(FuPlugin) plugin_uefi = fu_plugin_new (); - g_autoptr(FuPlugin) plugin_dell = fu_plugin_new (); + g_autoptr(FuUsbDevice) fake_usb_device = fu_usb_device_new (NULL); + gulong added_id; + gulong register_id; - pluginfn_uefi = g_build_filename (PLUGINBUILDDIR, "..", "uefi", - "libfu_plugin_uefi." G_MODULE_SUFFIX, - NULL); - pluginfn_dell = g_build_filename (PLUGINBUILDDIR, - "libfu_plugin_dell." G_MODULE_SUFFIX, - NULL); - - ret = fu_plugin_open (plugin_uefi, pluginfn_uefi, &error); - g_assert_no_error (error); - g_assert (ret); - ret = fu_plugin_runner_startup (plugin_uefi, &error); - g_assert_no_error (error); - g_assert (ret); devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - g_signal_connect (plugin_uefi, "device-added", + added_id = + g_signal_connect (self->plugin_uefi_capsule, "device-added", G_CALLBACK (_plugin_device_added_cb), devices); - ret = fu_plugin_open (plugin_dell, pluginfn_dell, &error); - g_assert_no_error (error); - g_assert (ret); - ret = fu_plugin_runner_startup (plugin_dell, &error); - g_assert_no_error (error); - g_assert (ret); - g_signal_connect (plugin_dell, "device-register", + register_id = + g_signal_connect (self->plugin_dell, "device-register", G_CALLBACK (fu_engine_plugin_device_register_cb), - plugin_uefi); - ret = fu_plugin_runner_coldplug (plugin_dell, &error); - g_assert_no_error (error); - g_assert (ret); + self->plugin_uefi_capsule); /* make sure bad device doesn't trigger this */ - fu_plugin_dell_inject_fake_data (plugin_dell, + fu_plugin_dell_inject_fake_data (self->plugin_dell, (guint32 *) &out, 0x1234, 0x4321, NULL, FALSE); - ret = fu_plugin_usb_device_added (plugin_dell, NULL, &error); + ret = fu_plugin_backend_device_added (self->plugin_dell, + FU_DEVICE (fake_usb_device), + &error); g_assert_false (ret); g_clear_error (&error); g_assert_cmpint (devices->len, ==, 0); @@ -326,11 +296,13 @@ /* inject a USB dongle matching correct VID/PID */ out[0] = 0; out[1] = 0; - fu_plugin_dell_inject_fake_data (plugin_dell, + fu_plugin_dell_inject_fake_data (self->plugin_dell, (guint32 *) &out, DOCK_NIC_VID, DOCK_NIC_PID, NULL, FALSE); - ret = fu_plugin_usb_device_added (plugin_dell, NULL, &error); + ret = fu_plugin_backend_device_added (self->plugin_dell, + FU_DEVICE (fake_usb_device), + &error); g_assert_true (ret); g_clear_error (&error); g_assert_cmpint (devices->len, ==, 0); @@ -360,11 +332,13 @@ "Dock1,Cable,Cyp,TBT_Cable,0 :Query 2 2 2 3 0", 44); out[0] = 0; out[1] = 1; - fu_plugin_dell_inject_fake_data (plugin_dell, + fu_plugin_dell_inject_fake_data (self->plugin_dell, (guint32 *) &out, DOCK_NIC_VID, DOCK_NIC_PID, buf.buf, FALSE); - ret = fu_plugin_usb_device_added (plugin_dell, NULL, NULL); + ret = fu_plugin_backend_device_added (self->plugin_dell, + FU_DEVICE (fake_usb_device), + NULL); g_assert (ret); g_assert_cmpint (devices->len, ==, 4); g_ptr_array_set_size (devices, 0); @@ -395,11 +369,13 @@ "Dock1,Cable,Cyp,TBT_Cable,0 :Query 2 2 2 3 0", 44); out[0] = 0; out[1] = 1; - fu_plugin_dell_inject_fake_data (plugin_dell, + fu_plugin_dell_inject_fake_data (self->plugin_dell, (guint32 *) &out, DOCK_NIC_VID, DOCK_NIC_PID, buf.buf, FALSE); - ret = fu_plugin_usb_device_added (plugin_dell, NULL, NULL); + ret = fu_plugin_backend_device_added (self->plugin_dell, + FU_DEVICE (fake_usb_device), + NULL); g_assert (ret); g_assert_cmpint (devices->len, ==, 3); g_ptr_array_set_size (devices, 0); @@ -427,11 +403,13 @@ "Dock1,Cable,Cyp,IE_Cable,0 :Query 2 2 2 1 0", 43); out[0] = 0; out[1] = 1; - fu_plugin_dell_inject_fake_data (plugin_dell, + fu_plugin_dell_inject_fake_data (self->plugin_dell, (guint32 *) &out, DOCK_NIC_VID, DOCK_NIC_PID, buf.buf, FALSE); - ret = fu_plugin_usb_device_added (plugin_dell, NULL, &error); + ret = fu_plugin_backend_device_added (self->plugin_dell, + FU_DEVICE (fake_usb_device), + &error); g_assert (ret); g_assert_no_error (error); g_assert_cmpint (devices->len, ==, 3); @@ -460,11 +438,13 @@ "Dock1,Cable,Cyp,IE_Cable,0 :Query 2 2 2 1 0", 43); out[0] = 0; out[1] = 1; - fu_plugin_dell_inject_fake_data (plugin_dell, + fu_plugin_dell_inject_fake_data (self->plugin_dell, (guint32 *) &out, DOCK_NIC_VID, DOCK_NIC_PID, buf.buf, FALSE); - ret = fu_plugin_usb_device_added (plugin_dell, NULL, &error); + ret = fu_plugin_backend_device_added (self->plugin_dell, + FU_DEVICE (fake_usb_device), + &error); g_assert (ret); g_assert_no_error (error); g_assert_cmpint (devices->len, ==, 2); @@ -487,26 +467,80 @@ "Dock1,EC,MIPS32,FUT_Dock,0 :Query 2 0 2 2 0", 43); out[0] = 0; out[1] = 1; - fu_plugin_dell_inject_fake_data (plugin_dell, + fu_plugin_dell_inject_fake_data (self->plugin_dell, (guint32 *) &out, DOCK_NIC_VID, DOCK_NIC_PID, buf.buf, FALSE); - ret = fu_plugin_usb_device_added (plugin_dell, NULL, &error); + ret = fu_plugin_backend_device_added (self->plugin_dell, + FU_DEVICE (fake_usb_device), + &error); g_assert_false (ret); g_assert_cmpint (devices->len, ==, 0); g_free (buf.record); + + /* all */ + g_signal_handler_disconnect (self->plugin_uefi_capsule, added_id); + g_signal_handler_disconnect (self->plugin_dell, register_id); +} + +static void +fu_test_self_init (FuTest *self) +{ + gboolean ret; + g_autoptr(GError) error = NULL; + g_autofree gchar *pluginfn_uefi = NULL; + g_autofree gchar *pluginfn_dell = NULL; + + self->plugin_uefi_capsule = fu_plugin_new (); + pluginfn_uefi = g_build_filename (PLUGINBUILDDIR, "..", "uefi-capsule", + "libfu_plugin_uefi_capsule." G_MODULE_SUFFIX, + NULL); + ret = fu_plugin_open (self->plugin_uefi_capsule, pluginfn_uefi, &error); + g_assert_no_error (error); + g_assert (ret); + ret = fu_plugin_runner_startup (self->plugin_uefi_capsule, &error); + g_assert_no_error (error); + g_assert (ret); + + self->plugin_dell = fu_plugin_new (); + pluginfn_dell = g_build_filename (PLUGINBUILDDIR, + "libfu_plugin_dell." G_MODULE_SUFFIX, + NULL); + ret = fu_plugin_open (self->plugin_dell, pluginfn_dell, &error); + g_assert_no_error (error); + g_assert (ret); + ret = fu_plugin_runner_startup (self->plugin_dell, &error); + g_assert_no_error (error); + g_assert (ret); } +static void +fu_test_self_free (FuTest *self) +{ + if (self->plugin_uefi_capsule != NULL) + g_object_unref (self->plugin_uefi_capsule); + if (self->plugin_dell != NULL) + g_object_unref (self->plugin_dell); + g_free (self); +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuTest, fu_test_self_free) +#pragma clang diagnostic pop + int main (int argc, char **argv) { g_autofree gchar *sysfsdir = NULL; + g_autoptr(FuTest) self = g_new0 (FuTest, 1); + g_test_init (&argc, &argv, NULL); /* change path */ g_setenv ("FWUPD_SYSFSFWDIR", TESTDATADIR, TRUE); - /* change behaviour */ + /* change behavior */ sysfsdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); g_setenv ("FWUPD_UEFI_ESP_PATH", sysfsdir, TRUE); g_setenv ("FWUPD_UEFI_TEST", "1", TRUE); @@ -518,7 +552,8 @@ g_assert_cmpint (g_mkdir_with_parents ("/tmp/fwupd-self-test/var/lib/fwupd", 0755), ==, 0); /* tests go here */ - g_test_add_func ("/fwupd/plugin{dell:tpm}", fu_plugin_dell_tpm_func); - g_test_add_func ("/fwupd/plugin{dell:dock}", fu_plugin_dell_dock_func); + fu_test_self_init (self); + g_test_add_data_func ("/fwupd/plugin{dell:tpm}", self, fu_plugin_dell_tpm_func); + g_test_add_data_func ("/fwupd/plugin{dell:dock}", self, fu_plugin_dell_dock_func); return g_test_run (); } diff -Nru fwupd-1.4.5/plugins/dell/meson.build fwupd-1.5.8/plugins/dell/meson.build --- fwupd-1.4.5/plugins/dell/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dell/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,4 @@ +if get_option('plugin_dell') cargs = ['-DG_LOG_DOMAIN="FuPluginDell"'] install_data(['dell.quirk'], @@ -26,7 +27,6 @@ ], dependencies : [ plugin_deps, - efivar, libsmbios_c, tpm2tss, ], @@ -51,7 +51,6 @@ ], dependencies : [ plugin_deps, - efivar, sqlite, libsmbios_c, valgrind, @@ -67,3 +66,4 @@ ) test('dell-self-test', e) endif +endif diff -Nru fwupd-1.4.5/plugins/dell/README.md fwupd-1.5.8/plugins/dell/README.md --- fwupd-1.4.5/plugins/dell/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dell/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -181,3 +181,7 @@ Some components are updatable via other plugins in fwupd such as multi stream transport hub (MST) and thunderbolt NVM. + +External interface access +------------------------- +This plugin requires read/write access to `/dev/wmi/dell-smbios` and `/sys/bus/platform/devices/dcdbas`. diff -Nru fwupd-1.4.5/plugins/dell-dock/dell-dock.quirk fwupd-1.5.8/plugins/dell-dock/dell-dock.quirk --- fwupd-1.4.5/plugins/dell-dock/dell-dock.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dell-dock/dell-dock.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -14,15 +14,15 @@ # # Used to make plugin probe the devices -[DeviceInstanceId=USB\VID_413C&PID_B06F] +[USB\VID_413C&PID_B06F] Name = Unprobed Dell accessory endpoint Plugin = dell_dock -[DeviceInstanceId=USB\VID_413C&PID_B06E] +[USB\VID_413C&PID_B06E] Name = Unprobed Dell accessory endpoint Plugin = dell_dock # USB hub1 -[DeviceInstanceId=USB\VID_413C&PID_B06F&hub] +[USB\VID_413C&PID_B06F&hub] Name = RTS5413 in Dell dock Summary = USB 3.1 Generation 1 Hub ParentGuid = USB\VID_413C&PID_B06E&hub&embedded @@ -37,7 +37,7 @@ InstallDuration = 14 # USB hub2 -[DeviceInstanceId=USB\VID_413C&PID_B06E&hub] +[USB\VID_413C&PID_B06E&hub] Name = RTS5487 in Dell dock Summary = USB 3.1 Generation 2 Hub ParentGuid = USB\VID_413C&PID_B06E&hub&embedded @@ -53,7 +53,7 @@ # Embedded Controller # Name is intentionally not set (it's queried by dock) -[Guid=USB\VID_413C&PID_B06E&hub&embedded] +[USB\VID_413C&PID_B06E&hub&embedded] Name = Dell dock Summary = High performance dock Plugin = dell_dock @@ -71,7 +71,7 @@ InstallDuration = 60 # Representation of overall dock update -[DeviceInstanceId=USB\VID_413C&PID_B06E&hub&status] +[USB\VID_413C&PID_B06E&hub&status] Name = Package level of Dell dock Summary = A representation of dock update status Plugin = dell_dock @@ -82,7 +82,7 @@ DellDockBlobVersionOffset = 0x14 # MST Hub -[Guid=MST-panamera-vmm5331-259] +[MST-panamera-vmm5331-259] Name = VMM5331 in Dell dock Summary = Multi Stream Transport controller Vendor = Dell Inc. @@ -99,7 +99,7 @@ Icon = video-display # Thunderbolt controller -[Guid=TBT-00d4b070] +[TBT-00d4b070] Name = Thunderbolt controller in Dell dock Summary = Thunderbolt controller Vendor = Dell Inc. diff -Nru fwupd-1.4.5/plugins/dell-dock/fu-dell-dock-hid.c fwupd-1.5.8/plugins/dell-dock/fu-dell-dock-hid.c --- fwupd-1.4.5/plugins/dell-dock/fu-dell-dock-hid.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dell-dock/fu-dell-dock-hid.c 2021-03-31 20:08:32.000000000 +0000 @@ -65,7 +65,7 @@ typedef struct __attribute__ ((packed)) { guint8 cmd; guint8 ext; - guint8 i2cslaveaddr; + guint8 i2ctargetaddr; guint8 i2cspeed; union { guint32 startaddress; @@ -129,7 +129,7 @@ .cmd_data2 = 0, .cmd_data3 = 0, .bufferlen = GUINT16_TO_LE (12), - .parameters = {.i2cslaveaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, + .parameters = {.i2ctargetaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, .extended_cmdarea[0 ... 52] = 0, }; @@ -164,7 +164,7 @@ .cmd_data2 = 0, .cmd_data3 = 0, .bufferlen = 0, - .parameters = {.i2cslaveaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, + .parameters = {.i2ctargetaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, .extended_cmdarea[0 ... 52] = 0, }; @@ -193,7 +193,7 @@ .cmd_data2 = 0, .cmd_data3 = 0, .bufferlen = GUINT16_TO_LE (27), - .parameters = {.i2cslaveaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, + .parameters = {.i2ctargetaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, .extended_cmdarea[0 ... 52] = 0, }; @@ -224,7 +224,7 @@ .cmd_data2 = 0, .cmd_data3 = 0, .bufferlen = 0, - .parameters = {.i2cslaveaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, + .parameters = {.i2ctargetaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, .extended_cmdarea[0 ... 52] = 0, }; @@ -249,7 +249,7 @@ .ext = HUB_EXT_WRITEFLASH, .dwregaddr = GUINT32_TO_LE (dwAddr), .bufferlen = GUINT16_TO_LE (write_size), - .parameters = {.i2cslaveaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, + .parameters = {.i2ctargetaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, .extended_cmdarea[0 ... 52] = 0, }; @@ -280,7 +280,7 @@ .cmd_data2 = 0, .cmd_data3 = 0, .bufferlen = GUINT16_TO_LE (1), - .parameters = {.i2cslaveaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, + .parameters = {.i2ctargetaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, .extended_cmdarea[0 ... 52] = 0, }; @@ -310,7 +310,7 @@ .ext = HUB_EXT_I2C_WRITE, .dwregaddr = 0, .bufferlen = GUINT16_TO_LE (write_size), - .parameters = {.i2cslaveaddr = parameters->i2cslaveaddr, + .parameters = {.i2ctargetaddr = parameters->i2ctargetaddr, .regaddrlen = 0, .i2cspeed = parameters->i2cspeed | 0x80}, .extended_cmdarea[0 ... 52] = 0, @@ -336,7 +336,7 @@ .ext = HUB_EXT_I2C_READ, .dwregaddr = GUINT32_TO_LE (cmd), .bufferlen = GUINT16_TO_LE (read_size), - .parameters = {.i2cslaveaddr = parameters->i2cslaveaddr, + .parameters = {.i2ctargetaddr = parameters->i2ctargetaddr, .regaddrlen = parameters->regaddrlen, .i2cspeed = parameters->i2cspeed | 0x80}, .extended_cmdarea[0 ... 52] = 0, @@ -365,7 +365,7 @@ FuTbtCmdBuffer cmd_buffer = { .cmd = HUB_CMD_READ_DATA, /* special write command that reads status result */ .ext = HUB_EXT_WRITE_TBT_FLASH, - .i2cslaveaddr = parameters->i2cslaveaddr, + .i2ctargetaddr = parameters->i2ctargetaddr, .i2cspeed = parameters->i2cspeed, /* unlike other commands doesn't need | 0x80 */ .tbt_command = TBT_COMMAND_WAKEUP, .bufferlen = 0, @@ -408,7 +408,7 @@ FuTbtCmdBuffer cmd_buffer = { .cmd = HUB_CMD_READ_DATA, /* It's a special write command that reads status result */ .ext = HUB_EXT_WRITE_TBT_FLASH, - .i2cslaveaddr = parameters->i2cslaveaddr, + .i2ctargetaddr = parameters->i2ctargetaddr, .i2cspeed = parameters->i2cspeed, /* unlike other commands doesn't need | 0x80 */ .startaddress = GUINT32_TO_LE (start_addr), .bufferlen = write_size, @@ -454,7 +454,7 @@ FuTbtCmdBuffer cmd_buffer = { .cmd = HUB_CMD_READ_DATA, /* It's a special write command that reads status result */ .ext = HUB_EXT_WRITE_TBT_FLASH, - .i2cslaveaddr = parameters->i2cslaveaddr, + .i2ctargetaddr = parameters->i2ctargetaddr, .i2cspeed = parameters->i2cspeed, /* unlike other commands doesn't need | 0x80 */ .tbt_command = GUINT32_TO_LE (TBT_COMMAND_AUTHENTICATE), .bufferlen = 0, diff -Nru fwupd-1.4.5/plugins/dell-dock/fu-dell-dock-hid.h fwupd-1.5.8/plugins/dell-dock/fu-dell-dock-hid.h --- fwupd-1.4.5/plugins/dell-dock/fu-dell-dock-hid.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dell-dock/fu-dell-dock-hid.h 2021-03-31 20:08:32.000000000 +0000 @@ -23,7 +23,7 @@ #include "fu-device.h" typedef struct __attribute__ ((packed)) { - guint8 i2cslaveaddr; + guint8 i2ctargetaddr; guint8 regaddrlen; guint8 i2cspeed; } FuHIDI2CParameters; diff -Nru fwupd-1.4.5/plugins/dell-dock/fu-dell-dock-hub.c fwupd-1.5.8/plugins/dell-dock/fu-dell-dock-hub.c --- fwupd-1.4.5/plugins/dell-dock/fu-dell-dock-hub.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dell-dock/fu-dell-dock-hub.c 2021-03-31 20:08:32.000000000 +0000 @@ -40,7 +40,7 @@ fu_device_set_logical_id (device, "hub"); fu_device_add_instance_id (device, devid); - fu_device_set_protocol (device, "com.dell.dock"); + fu_device_add_protocol (device, "com.dell.dock"); return TRUE; } diff -Nru fwupd-1.4.5/plugins/dell-dock/fu-dell-dock-i2c-ec.c fwupd-1.5.8/plugins/dell-dock/fu-dell-dock-i2c-ec.c --- fwupd-1.4.5/plugins/dell-dock/fu-dell-dock-i2c-ec.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dell-dock/fu-dell-dock-i2c-ec.c 2021-03-31 20:08:32.000000000 +0000 @@ -31,12 +31,11 @@ #define EC_CMD_GET_DOCK_TYPE 0x05 #define EC_CMD_MODIFY_LOCK 0x0a #define EC_CMD_RESET 0x0b -#define EC_CMD_REBOOT 0x0c #define EC_CMD_PASSIVE 0x0d #define EC_GET_FW_UPDATE_STATUS 0x0f #define EXPECTED_DOCK_INFO_SIZE 0xb7 -#define EXPECTED_DOCK_TYPE 0x04 +#define WD19_BASE 0x04 #define TBT_MODE_MASK 0x01 @@ -54,7 +53,7 @@ } FuDellDockECFWUpdateStatus; const FuHIDI2CParameters ec_base_settings = { - .i2cslaveaddr = I2C_EC_ADDRESS, + .i2ctargetaddr = I2C_EC_ADDRESS, .regaddrlen = 1, .i2cspeed = I2C_SPEED_250K, }; @@ -137,6 +136,7 @@ FuDevice parent_instance; FuDellDockDockDataStructure *data; FuDellDockDockPackageFWVersion *raw_versions; + guint8 base_type; gchar *ec_version; gchar *mst_version; gchar *tbt_version; @@ -301,8 +301,10 @@ static gboolean fu_dell_dock_is_valid_dock (FuDevice *device, GError **error) { - g_autoptr(GBytes) data = NULL; + FuDellDockEc *self = FU_DELL_DOCK_EC (device); const guint8 *result = NULL; + gsize sz = 0; + g_autoptr(GBytes) data = NULL; g_return_val_if_fail (device != NULL, FALSE); @@ -310,14 +312,26 @@ g_prefix_error (error, "Failed to query dock type: "); return FALSE; } - result = g_bytes_get_data (data, NULL); - - if (result == NULL || *result != EXPECTED_DOCK_TYPE) { - g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, + result = g_bytes_get_data (data, &sz); + if (sz != 1) { + g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "No valid dock was found"); return FALSE; } - return TRUE; + self->base_type = result[0]; + + /* this will trigger setting up all the quirks */ + if (self->base_type == WD19_BASE) { + fu_device_add_instance_id (device, DELL_DOCK_EC_INSTANCE_ID); + return TRUE; + } + + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Invalid dock type: %x", + self->base_type); + return FALSE; } static gboolean @@ -461,14 +475,14 @@ /* Determine if the passive flow should be used when flashing */ hub_version = fu_device_get_version (fu_device_get_proxy (device)); - if (fu_common_vercmp_full (hub_version, "1.42", FWUPD_VERSION_FORMAT_PAIR) >= 0) { - g_debug ("using passive flow"); - self->passive_flow = PASSIVE_REBOOT_MASK; - fu_device_add_flag (device, FWUPD_DEVICE_FLAG_SKIPS_RESTART); - } else { - g_debug ("not using passive flow (EC: %s Hub2: %s)", - self->ec_version, hub_version); + if (fu_common_vercmp_full (hub_version, "1.42", FWUPD_VERSION_FORMAT_PAIR) < 0) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, + "dock containing hub2 version %s is not supported", + hub_version); + return FALSE; } + self->passive_flow = PASSIVE_REBOOT_MASK; + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_SKIPS_RESTART); return TRUE; } @@ -556,6 +570,7 @@ FuDellDockEc *self = FU_DELL_DOCK_EC (device); gchar service_tag[8] = {0x00}; + fu_common_string_append_ku (str, idt, "BaseType", self->base_type); fu_common_string_append_ku (str, idt, "BoardId", self->data->board_id); fu_common_string_append_ku (str, idt, "PowerSupply", self->data->power_supply_wattage); fu_common_string_append_kx (str, idt, "StatusPort0", self->data->port0_dock_status); @@ -643,24 +658,16 @@ fu_dell_dock_ec_reboot_dock (FuDevice *device, GError **error) { FuDellDockEc *self = FU_DELL_DOCK_EC (device); + guint32 cmd = EC_CMD_PASSIVE | /* cmd */ + 1 << 8 | /* length of data arguments */ + self->passive_flow << 16; g_return_val_if_fail (device != NULL, FALSE); - if (self->passive_flow > 0) { - guint32 cmd = EC_CMD_PASSIVE | /* cmd */ - 1 << 8 | /* length of data arguments */ - self->passive_flow << 16; - g_debug ("activating passive flow (%x) for %s", - self->passive_flow, - fu_device_get_name (device)); - return fu_dell_dock_ec_write (device, 3, (guint8 *) &cmd, error); - } else { - guint16 cmd = EC_CMD_REBOOT; - g_debug ("rebooting %s", fu_device_get_name (device)); - return fu_dell_dock_ec_write (device, 2, (guint8 *) &cmd, error); - } - - return TRUE; + g_debug ("activating passive flow (%x) for %s", + self->passive_flow, + fu_device_get_name (device)); + return fu_dell_dock_ec_write (device, 3, (guint8 *) &cmd, error); } static gboolean @@ -758,8 +765,6 @@ GError **error) { FuDellDockEc *self = FU_DELL_DOCK_EC (device); - FuDellDockECFWUpdateStatus status = FW_UPDATE_IN_PROGRESS; - guint8 progress1 = 0, progress0 = 0; gsize fw_size = 0; const guint8 *data; gsize write_size = 0; @@ -816,53 +821,8 @@ fu_device_set_version (device, dynamic_version); /* activate passive behavior */ - if (self->passive_flow) - self->passive_flow |= PASSIVE_RESET_MASK; - - if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_SKIPS_RESTART)) { - g_debug ("Skipping EC reset per quirk request"); - fu_device_add_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION); - return TRUE; - } - - if (!fu_dell_dock_ec_reset (device, error)) - return FALSE; - - /* notify daemon that this device will need to replug */ - fu_dell_dock_will_replug (device); - - /* poll for completion status */ - fu_device_set_status (device, FWUPD_STATUS_DEVICE_BUSY); - while (status != FW_UPDATE_COMPLETE) { - g_autoptr(GError) error_local = NULL; - - if (!fu_dell_dock_hid_get_ec_status (fu_device_get_proxy (device), &progress1, - &progress0, error)) { - g_prefix_error (error, "Failed to read scratch: "); - return FALSE; - } - g_debug ("Read %u and %u from scratch", progress1, progress0); - if (progress0 > 100) - progress0 = 100; - fu_device_set_progress_full (device, progress0, 100); - - /* This is expected to fail until update is done */ - if (!fu_dell_dock_get_ec_status (device, &status, - &error_local)) { - g_debug ("Flash EC Received result: %s (status %u)", - error_local->message, status); - return TRUE; - } - if (status == FW_UPDATE_AUTHENTICATION_FAILED) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "invalid EC firmware image"); - return FALSE; - } - } - - fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + self->passive_flow |= PASSIVE_RESET_MASK; + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION); return TRUE; } @@ -920,15 +880,6 @@ } static gboolean -fu_dell_dock_ec_probe (FuDevice *device, GError **error) -{ - /* this will trigger setting up all the quirks */ - fu_device_add_instance_id (device, DELL_DOCK_EC_INSTANCE_ID); - - return TRUE; -} - -static gboolean fu_dell_dock_ec_query (FuDevice *device, GError **error) { if (!fu_dell_dock_ec_get_dock_data (device, error)) @@ -976,10 +927,13 @@ static gboolean fu_dell_dock_ec_open (FuDevice *device, GError **error) { + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + if (!fu_device_open (fu_device_get_proxy (device), error)) return FALSE; - - return fu_dell_dock_is_valid_dock (device, error); + if (!self->data->dock_type) + return fu_dell_dock_is_valid_dock (device, error); + return TRUE; } static gboolean @@ -1006,7 +960,7 @@ { self->data = g_new0 (FuDellDockDockDataStructure, 1); self->raw_versions = g_new0 (FuDellDockDockPackageFWVersion, 1); - fu_device_set_protocol (FU_DEVICE (self), "com.dell.dock"); + fu_device_add_protocol (FU_DEVICE (self), "com.dell.dock"); } static void @@ -1017,7 +971,6 @@ object_class->finalize = fu_dell_dock_ec_finalize; klass_device->activate = fu_dell_dock_ec_activate; klass_device->to_string = fu_dell_dock_ec_to_string; - klass_device->probe = fu_dell_dock_ec_probe; klass_device->setup = fu_dell_dock_ec_setup; klass_device->open = fu_dell_dock_ec_open; klass_device->close = fu_dell_dock_ec_close; diff -Nru fwupd-1.4.5/plugins/dell-dock/fu-dell-dock-i2c-ec.h fwupd-1.5.8/plugins/dell-dock/fu-dell-dock-i2c-ec.h --- fwupd-1.4.5/plugins/dell-dock/fu-dell-dock-i2c-ec.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dell-dock/fu-dell-dock-i2c-ec.h 2021-03-31 20:08:32.000000000 +0000 @@ -17,8 +17,6 @@ #include "config.h" -#include - #include "fu-device.h" #define FU_TYPE_DELL_DOCK_EC (fu_dell_dock_ec_get_type ()) diff -Nru fwupd-1.4.5/plugins/dell-dock/fu-dell-dock-i2c-mst.c fwupd-1.5.8/plugins/dell-dock/fu-dell-dock-i2c-mst.c --- fwupd-1.4.5/plugins/dell-dock/fu-dell-dock-i2c-mst.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dell-dock/fu-dell-dock-i2c-mst.c 2021-03-31 20:08:32.000000000 +0000 @@ -96,7 +96,7 @@ }; FuHIDI2CParameters mst_base_settings = { - .i2cslaveaddr = I2C_MST_ADDRESS, + .i2ctargetaddr = I2C_MST_ADDRESS, .regaddrlen = 0, .i2cspeed = I2C_SPEED_400K, }; @@ -965,7 +965,7 @@ static void fu_dell_dock_mst_init (FuDellDockMst *self) { - fu_device_set_protocol (FU_DEVICE (self), "com.synaptics.mst"); + fu_device_add_protocol (FU_DEVICE (self), "com.synaptics.mst"); } static void diff -Nru fwupd-1.4.5/plugins/dell-dock/fu-dell-dock-i2c-tbt.c fwupd-1.5.8/plugins/dell-dock/fu-dell-dock-i2c-tbt.c --- fwupd-1.4.5/plugins/dell-dock/fu-dell-dock-i2c-tbt.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dell-dock/fu-dell-dock-i2c-tbt.c 2021-03-31 20:08:32.000000000 +0000 @@ -28,7 +28,7 @@ #define I2C_TBT_ADDRESS 0xa2 const FuHIDI2CParameters tbt_base_settings = { - .i2cslaveaddr = I2C_TBT_ADDRESS, + .i2ctargetaddr = I2C_TBT_ADDRESS, .regaddrlen = 1, .i2cspeed = I2C_SPEED_400K, }; @@ -276,7 +276,7 @@ static void fu_dell_dock_tbt_init (FuDellDockTbt *self) { - fu_device_set_protocol (FU_DEVICE (self), "com.intel.thunderbolt"); + fu_device_add_protocol (FU_DEVICE (self), "com.intel.thunderbolt"); } static void diff -Nru fwupd-1.4.5/plugins/dell-dock/fu-dell-dock-status.c fwupd-1.5.8/plugins/dell-dock/fu-dell-dock-status.c --- fwupd-1.4.5/plugins/dell-dock/fu-dell-dock-status.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dell-dock/fu-dell-dock-status.c 2021-03-31 20:08:32.000000000 +0000 @@ -144,7 +144,7 @@ static void fu_dell_dock_status_init (FuDellDockStatus *self) { - fu_device_set_protocol (FU_DEVICE (self), "com.dell.dock"); + fu_device_add_protocol (FU_DEVICE (self), "com.dell.dock"); } static void diff -Nru fwupd-1.4.5/plugins/dell-dock/fu-plugin-dell-dock.c fwupd-1.5.8/plugins/dell-dock/fu-plugin-dell-dock.c --- fwupd-1.4.5/plugins/dell-dock/fu-plugin-dell-dock.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dell-dock/fu-plugin-dell-dock.c 2021-03-31 20:08:32.000000000 +0000 @@ -18,7 +18,6 @@ #include "fu-device.h" #include "fwupd-error.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #include "fu-dell-dock-common.h" @@ -26,6 +25,15 @@ fu_plugin_init (FuPlugin *plugin) { fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_possible_quirk_key (plugin, "DellDockBlobBuildOffset"); + fu_plugin_add_possible_quirk_key (plugin, "DellDockBlobMajorOffset"); + fu_plugin_add_possible_quirk_key (plugin, "DellDockBlobMinorOffset"); + fu_plugin_add_possible_quirk_key (plugin, "DellDockBlobVersionOffset"); + fu_plugin_add_possible_quirk_key (plugin, "DellDockBoardMin"); + fu_plugin_add_possible_quirk_key (plugin, "DellDockHubVersionLowest"); + fu_plugin_add_possible_quirk_key (plugin, "DellDockInstallDurationI2C"); + fu_plugin_add_possible_quirk_key (plugin, "DellDockUnlockTarget"); + fu_plugin_add_possible_quirk_key (plugin, "DellDockVersionLowest"); /* allow these to be built by quirks */ g_type_ensure (FU_TYPE_DELL_DOCK_STATUS); @@ -80,34 +88,38 @@ } gboolean -fu_plugin_usb_device_added (FuPlugin *plugin, - FuUsbDevice *device, - GError **error) +fu_plugin_backend_device_added (FuPlugin *plugin, + FuDevice *device, + GError **error) { g_autoptr(FuDeviceLocker) locker = NULL; - g_autoptr(FuDellDockHub) hub = fu_dell_dock_hub_new (device); - FuDevice *fu_device = FU_DEVICE (hub); + g_autoptr(FuDellDockHub) hub = NULL; const gchar *key = NULL; - locker = fu_device_locker_new (fu_device, error); + /* not interesting */ + if (!FU_IS_USB_DEVICE (device)) + return TRUE; + + hub = fu_dell_dock_hub_new (FU_USB_DEVICE (device)); + locker = fu_device_locker_new (FU_DEVICE (hub), error); if (locker == NULL) return FALSE; - fu_plugin_device_add (plugin, fu_device); + fu_plugin_device_add (plugin, FU_DEVICE (hub)); - if (fu_device_has_custom_flag (fu_device, "has-bridge")) { + if (fu_device_has_custom_flag (FU_DEVICE (hub), "has-bridge")) { g_autoptr(GError) error_local = NULL; /* only add the device with parent to cache */ - key = fu_device_get_id (fu_device); + key = fu_device_get_id (FU_DEVICE (hub)); if (fu_plugin_cache_lookup (plugin, key) != NULL) { g_debug ("Ignoring already added device %s", key); return TRUE; } - fu_plugin_cache_add (plugin, key, fu_device); + fu_plugin_cache_add (plugin, key, FU_DEVICE (hub)); /* probe for extended devices */ if (!fu_plugin_dell_dock_probe (plugin, - fu_device, + FU_DEVICE (hub), &error_local)) { g_warning ("Failed to probe bridged devices for %s: %s", key, @@ -116,13 +128,24 @@ } /* clear updatable flag if parent doesn't have it */ - fu_dell_dock_clone_updatable (fu_device); + fu_dell_dock_clone_updatable (FU_DEVICE (hub)); return TRUE; } +void +fu_plugin_device_registered (FuPlugin *plugin, FuDevice *device) +{ + /* thunderbolt plugin */ + if (g_strcmp0 (fu_device_get_plugin (device), "thunderbolt") != 0 || + fu_device_has_flag (device, FWUPD_DEVICE_FLAG_INTERNAL)) + return; + /* clone updatable flag to leave in needs activation state */ + fu_dell_dock_clone_updatable (device); +} + gboolean -fu_plugin_device_removed (FuPlugin *plugin, FuDevice *device, GError **error) +fu_plugin_backend_device_removed (FuPlugin *plugin, FuDevice *device, GError **error) { const gchar *device_key = fu_device_get_id (device); FuDevice *dev; diff -Nru fwupd-1.4.5/plugins/dell-dock/README.md fwupd-1.5.8/plugins/dell-dock/README.md --- fwupd-1.4.5/plugins/dell-dock/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dell-dock/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -48,6 +48,11 @@ * MST Hub: `MST-panamera-vmm5331-259` * Thunderbolt Controller: `TBT-00d4b070` +Update Behavior +--------------- + +All devices will be updated the next time the usb-c plug from the dock is unplugged from the host. + Vendor ID Security ------------------ @@ -68,3 +73,7 @@ | `DellDockVersionLowest` | The minimum component version required to safely operate the plugin | 1.1.3 | | `DellDockBoard*` | The board description of a board revision | 1.1.3 | | `DellDockInstallDurationI2C` | The duration of time required to install a payload via I2C. | 1.1.3 | + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff -Nru fwupd-1.4.5/plugins/dell-esrt/fu-plugin-dell-esrt.c fwupd-1.5.8/plugins/dell-esrt/fu-plugin-dell-esrt.c --- fwupd-1.4.5/plugins/dell-esrt/fu-plugin-dell-esrt.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dell-esrt/fu-plugin-dell-esrt.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,6 +1,6 @@ /* * Copyright (C) 2018 Richard Hughes - * Copyright (C) 2017-2018 Dell, Inc. + * Copyright (C) 2017 Dell, Inc. * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -15,13 +15,12 @@ #include #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" -/* Whitelisted smbios class/select commands */ +/* allowed smbios class/select commands */ #define CLASS_ADMIN_PROP 10 #define SELECT_ADMIN_PROP 3 -/* whitelisted tokens */ +/* allowed tokens */ #define CAPSULE_EN_TOKEN 0x0461 #define CAPSULE_DIS_TOKEN 0x0462 @@ -87,7 +86,7 @@ fu_plugin_init (FuPlugin *plugin) { fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); - fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_BETTER_THAN, "uefi"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_BETTER_THAN, "bios"); } gboolean @@ -163,7 +162,7 @@ fu_device_set_id (dev, "UEFI-dummy"); fu_device_set_name (dev, "Dell UEFI updates"); fu_device_set_summary (dev, "Enable UEFI Update Functionality"); - fu_device_set_vendor_id (dev, "PCI:0x1028"); + fu_device_add_vendor_id (dev, "PCI:0x1028"); fu_device_add_instance_id (dev, "main-system-firmware"); fu_device_add_guid (dev, "2d47f29b-83a2-4f31-a2e8-63474f4d4c2e"); fu_device_set_version_format (dev, FWUPD_VERSION_FORMAT_NUMBER); @@ -172,6 +171,8 @@ fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_LOCKED); fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_REBOOT); fu_device_set_update_error (dev, "Firmware updates disabled; run 'fwupdmgr unlock' to enable"); + if (!fu_device_setup (dev, error)) + return FALSE; fu_plugin_device_add (plugin, dev); return TRUE; } diff -Nru fwupd-1.4.5/plugins/dell-esrt/meson.build fwupd-1.5.8/plugins/dell-esrt/meson.build --- fwupd-1.4.5/plugins/dell-esrt/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dell-esrt/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,4 @@ +if get_option('plugin_dell') cargs = ['-DG_LOG_DOMAIN="FuPluginDellEsrt"'] install_data(['metadata.xml'], @@ -39,3 +40,4 @@ install: true, install_dir: join_paths(sysconfdir, 'fwupd', 'remotes.d'), ) +endif diff -Nru fwupd-1.4.5/plugins/dell-esrt/README.md fwupd-1.5.8/plugins/dell-esrt/README.md --- fwupd-1.4.5/plugins/dell-esrt/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dell-esrt/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -45,3 +45,9 @@ Version: 0 Created: 2018-06-25 ``` + +External interface access +------------------------- +This plugin requires: +* read/write access to `/dev/wmi/dell-smbios` and `/sys/bus/platform/devices/dcdbas`. +* read access to `/sys/firmware/efi/esrt`. diff -Nru fwupd-1.4.5/plugins/dfu/dfu-common.c fwupd-1.5.8/plugins/dfu/dfu-common.c --- fwupd-1.4.5/plugins/dfu/dfu-common.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/dfu-common.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,158 +0,0 @@ -/* - * Copyright (C) 2015 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -/** - * SECTION:dfu-common - * @short_description: Common functions for DFU - * - * These helper objects allow converting from enum values to strings. - */ - -#include "config.h" - -#include - -#include "dfu-common.h" - -/** - * dfu_state_to_string: - * @state: a #DfuState, e.g. %DFU_STATE_DFU_MANIFEST - * - * Converts an enumerated value to a string. - * - * Return value: a string - **/ -const gchar * -dfu_state_to_string (DfuState state) -{ - if (state == DFU_STATE_APP_IDLE) - return "appIDLE"; - if (state == DFU_STATE_APP_DETACH) - return "appDETACH"; - if (state == DFU_STATE_DFU_IDLE) - return "dfuIDLE"; - if (state == DFU_STATE_DFU_DNLOAD_SYNC) - return "dfuDNLOAD-SYNC"; - if (state == DFU_STATE_DFU_DNBUSY) - return "dfuDNBUSY"; - if (state == DFU_STATE_DFU_DNLOAD_IDLE) - return "dfuDNLOAD-IDLE"; - if (state == DFU_STATE_DFU_MANIFEST_SYNC) - return "dfuMANIFEST-SYNC"; - if (state == DFU_STATE_DFU_MANIFEST) - return "dfuMANIFEST"; - if (state == DFU_STATE_DFU_MANIFEST_WAIT_RESET) - return "dfuMANIFEST-WAIT-RESET"; - if (state == DFU_STATE_DFU_UPLOAD_IDLE) - return "dfuUPLOAD-IDLE"; - if (state == DFU_STATE_DFU_ERROR) - return "dfuERROR"; - return NULL; -} - -/** - * dfu_status_to_string: - * @status: a #DfuStatus, e.g. %DFU_STATUS_ERR_ERASE - * - * Converts an enumerated value to a string. - * - * Return value: a string - **/ -const gchar * -dfu_status_to_string (DfuStatus status) -{ - if (status == DFU_STATUS_OK) - return "OK"; - if (status == DFU_STATUS_ERR_TARGET) - return "errTARGET"; - if (status == DFU_STATUS_ERR_FILE) - return "errFILE"; - if (status == DFU_STATUS_ERR_WRITE) - return "errwrite"; - if (status == DFU_STATUS_ERR_ERASE) - return "errERASE"; - if (status == DFU_STATUS_ERR_CHECK_ERASED) - return "errCHECK_ERASED"; - if (status == DFU_STATUS_ERR_PROG) - return "errPROG"; - if (status == DFU_STATUS_ERR_VERIFY) - return "errVERIFY"; - if (status == DFU_STATUS_ERR_ADDRESS) - return "errADDRESS"; - if (status == DFU_STATUS_ERR_NOTDONE) - return "errNOTDONE"; - if (status == DFU_STATUS_ERR_FIRMWARE) - return "errFIRMWARE"; - if (status == DFU_STATUS_ERR_VENDOR) - return "errVENDOR"; - if (status == DFU_STATUS_ERR_USBR) - return "errUSBR"; - if (status == DFU_STATUS_ERR_POR) - return "errPOR"; - if (status == DFU_STATUS_ERR_UNKNOWN) - return "errUNKNOWN"; - if (status == DFU_STATUS_ERR_STALLDPKT) - return "errSTALLDPKT"; - return NULL; -} - -/** - * dfu_version_to_string: - * @version: a #DfuVersion, e.g. %DFU_VERSION_DFU_1_1 - * - * Converts an enumerated value to a string. - * - * Return value: a string - **/ -const gchar * -dfu_version_to_string (DfuVersion version) -{ - if (version == DFU_VERSION_DFU_1_0) - return "1.0"; - if (version == DFU_VERSION_DFU_1_1) - return "1.1"; - if (version == DFU_VERSION_DFUSE) - return "DfuSe"; - if (version == DFU_VERSION_ATMEL_AVR) - return "AtmelAVR"; - return NULL; -} - -/** - * dfu_utils_bytes_join_array: - * @chunks: (element-kind GBytes): bytes - * - * Creates a monolithic block of memory from an array of #GBytes. - * - * Return value: (transfer full): a new GBytes - **/ -GBytes * -dfu_utils_bytes_join_array (GPtrArray *chunks) -{ - gsize total_size = 0; - guint32 offset = 0; - guint8 *buffer; - - /* get the size of all the chunks */ - for (guint i = 0; i < chunks->len; i++) { - GBytes *chunk_tmp = g_ptr_array_index (chunks, i); - total_size += g_bytes_get_size (chunk_tmp); - } - - /* copy them into a buffer */ - buffer = g_malloc0 (total_size); - for (guint i = 0; i < chunks->len; i++) { - const guint8 *chunk_data; - gsize chunk_size = 0; - GBytes *chunk_tmp = g_ptr_array_index (chunks, i); - chunk_data = g_bytes_get_data (chunk_tmp, &chunk_size); - if (chunk_size == 0) - continue; - memcpy (buffer + offset, chunk_data, chunk_size); - offset += chunk_size; - } - return g_bytes_new_take (buffer, total_size); -} diff -Nru fwupd-1.4.5/plugins/dfu/dfu-common.h fwupd-1.5.8/plugins/dfu/dfu-common.h --- fwupd-1.4.5/plugins/dfu/dfu-common.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/dfu-common.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,135 +0,0 @@ -/* - * Copyright (C) 2015 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include -#include - -/** - * DfuRequest: - * @DFU_REQUEST_DETACH: Detach - * @DFU_REQUEST_DNLOAD: Download host-to-device - * @DFU_REQUEST_UPLOAD: Upload device-to-host - * @DFU_REQUEST_GETSTATUS: Get the device status - * @DFU_REQUEST_CLRSTATUS: Clear the device status - * @DFU_REQUEST_GETSTATE: Get the last set state - * @DFU_REQUEST_ABORT: Abort the current transfer - * - * The DFU request kinds. - **/ -typedef enum { - DFU_REQUEST_DETACH = 0x00, - DFU_REQUEST_DNLOAD = 0x01, - DFU_REQUEST_UPLOAD = 0x02, - DFU_REQUEST_GETSTATUS = 0x03, - DFU_REQUEST_CLRSTATUS = 0x04, - DFU_REQUEST_GETSTATE = 0x05, - DFU_REQUEST_ABORT = 0x06, - /*< private >*/ - DFU_REQUEST_LAST -} DfuRequest; - -/** - * DfuStatus: - * @DFU_STATUS_OK: No error condition is present - * @DFU_STATUS_ERR_TARGET: File is not targeted for use by this device - * @DFU_STATUS_ERR_FILE: File is for this device but fails a verification test - * @DFU_STATUS_ERR_WRITE: Device is unable to write memory - * @DFU_STATUS_ERR_ERASE: Memory erase function failed - * @DFU_STATUS_ERR_CHECK_ERASED: Memory erase check failed - * @DFU_STATUS_ERR_PROG: Program memory function failed - * @DFU_STATUS_ERR_VERIFY: Programmed memory failed verification - * @DFU_STATUS_ERR_ADDRESS: Cannot program memory due to received address that isout of range - * @DFU_STATUS_ERR_NOTDONE: Received DFU_DNLOAD with wLength = 0 but data is incomplete - * @DFU_STATUS_ERR_FIRMWARE: Device firmware is corrupt - * @DFU_STATUS_ERR_VENDOR: iString indicates a vendor-specific error - * @DFU_STATUS_ERR_USBR: Device detected unexpected USB reset signaling - * @DFU_STATUS_ERR_POR: Device detected unexpected power on reset - * @DFU_STATUS_ERR_UNKNOWN: Something unexpected went wrong - * @DFU_STATUS_ERR_STALLDPKT: Device stalled an unexpected request - * - * The status enumerated kind. - **/ -typedef enum { - DFU_STATUS_OK = 0x00, - DFU_STATUS_ERR_TARGET = 0x01, - DFU_STATUS_ERR_FILE = 0x02, - DFU_STATUS_ERR_WRITE = 0x03, - DFU_STATUS_ERR_ERASE = 0x04, - DFU_STATUS_ERR_CHECK_ERASED = 0x05, - DFU_STATUS_ERR_PROG = 0x06, - DFU_STATUS_ERR_VERIFY = 0x07, - DFU_STATUS_ERR_ADDRESS = 0x08, - DFU_STATUS_ERR_NOTDONE = 0x09, - DFU_STATUS_ERR_FIRMWARE = 0x0a, - DFU_STATUS_ERR_VENDOR = 0x0b, - DFU_STATUS_ERR_USBR = 0x0c, - DFU_STATUS_ERR_POR = 0x0d, - DFU_STATUS_ERR_UNKNOWN = 0x0e, - DFU_STATUS_ERR_STALLDPKT = 0x0f, - /*< private >*/ - DFU_STATUS_LAST -} DfuStatus; - -/** - * DfuState: - * @DFU_STATE_APP_IDLE: State 0 - * @DFU_STATE_APP_DETACH: State 1 - * @DFU_STATE_DFU_IDLE: State 2 - * @DFU_STATE_DFU_DNLOAD_SYNC: State 3 - * @DFU_STATE_DFU_DNBUSY: State 4 - * @DFU_STATE_DFU_DNLOAD_IDLE: State 5 - * @DFU_STATE_DFU_MANIFEST_SYNC: State 6 - * @DFU_STATE_DFU_MANIFEST: State 7 - * @DFU_STATE_DFU_MANIFEST_WAIT_RESET: State 8 - * @DFU_STATE_DFU_UPLOAD_IDLE: State 9 - * @DFU_STATE_DFU_ERROR: State 10 - * - * The state enumerated kind. - **/ -typedef enum { - DFU_STATE_APP_IDLE = 0x00, - DFU_STATE_APP_DETACH = 0x01, - DFU_STATE_DFU_IDLE = 0x02, - DFU_STATE_DFU_DNLOAD_SYNC = 0x03, - DFU_STATE_DFU_DNBUSY = 0x04, - DFU_STATE_DFU_DNLOAD_IDLE = 0x05, - DFU_STATE_DFU_MANIFEST_SYNC = 0x06, - DFU_STATE_DFU_MANIFEST = 0x07, - DFU_STATE_DFU_MANIFEST_WAIT_RESET = 0x08, - DFU_STATE_DFU_UPLOAD_IDLE = 0x09, - DFU_STATE_DFU_ERROR = 0x0a, - /*< private >*/ - DFU_STATE_LAST -} DfuState; - -/** - * DfuVersion: - * @DFU_VERSION_UNKNOWN: Format unknown - * @DFU_VERSION_DFU_1_0: DFU 1.0 - * @DFU_VERSION_DFU_1_1: DFU 1.1 - * @DFU_VERSION_DFUSE: DfuSe - * @DFU_VERSION_ATMEL_AVR: Atmel AVR - * - * The known versions of the DFU standard in BCD format. - **/ -typedef enum { - DFU_VERSION_UNKNOWN = 0, - DFU_VERSION_DFU_1_0 = 0x0100, - DFU_VERSION_DFU_1_1 = 0x0110, - DFU_VERSION_DFUSE = 0x011a, /* defined by ST */ - DFU_VERSION_ATMEL_AVR = 0xff01, /* made up */ - /*< private >*/ - DFU_VERSION_LAST -} DfuVersion; - -const gchar *dfu_state_to_string (DfuState state); -const gchar *dfu_status_to_string (DfuStatus status); -const gchar *dfu_version_to_string (DfuVersion version); - -/* helpers */ -GBytes *dfu_utils_bytes_join_array (GPtrArray *chunks); diff -Nru fwupd-1.4.5/plugins/dfu/dfu-device.c fwupd-1.5.8/plugins/dfu/dfu-device.c --- fwupd-1.4.5/plugins/dfu/dfu-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/dfu-device.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1851 +0,0 @@ -/* - * Copyright (C) 2015-2017 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -/** - * SECTION:dfu-device - * @short_description: Object representing a DFU-capable device - * - * This object allows two things: - * - * - Downloading from the host to the device, optionally with - * verification using a DFU or DfuSe firmware file. - * - * - Uploading from the device to the host to a DFU or DfuSe firmware - * file. The file format is chosen automatically, with DfuSe being - * chosen if the device contains more than one target. - * - * See also: #DfuTarget, #DfuFirmware - */ - -/** - * FU_QUIRKS_DFU_FLAGS: - * @key: the USB device ID, e.g. `USB\VID_0763&PID_2806` - * @value: a string, separated using `|`, e.g. `ignore-polltimeout|no-pid-change` - * - * Assigns optional quirks to use for a DFU device which does not follow the - * DFU 1.0 or 1.1 specification. The list of supported quirks is thus: - * - * * `none`: No device quirks - * * `attach-extra-reset`: Device needs resetting twice for attach - * * `attach-upload-download`: An upload or download is required for attach - * * `force-dfu-mode`: Force DFU mode - * * `ignore-polltimeout`: Ignore the device download timeout - * * `ignore-runtime`: Device has broken DFU runtime support - * * `ignore-upload`: Uploading from the device is broken - * * `no-dfu-runtime`: No DFU runtime interface is provided - * * `no-get-status-upload`: Do not do GetStatus when uploading - * * `no-pid-change`: Accept the same VID:PID when changing modes - * * `use-any-interface`: Use any interface for DFU - * * `use-atmel-avr`: Device uses the ATMEL bootloader - * * `use-protocol-zero`: Fix up the protocol number - * * `legacy-protocol`: Use a legacy protocol version - * * `detach-for-attach`: Requires a DFU_REQUEST_DETACH to attach - * * `absent-sector-size`: In absence of sector size, assume byte - * - * Default value: `none` - * - * Since: 1.0.1 - */ -#define FU_QUIRKS_DFU_FLAGS "Flags" - -/** - * FU_QUIRKS_DFU_FORCE_VERSION: - * @key: the USB device ID, e.g. `USB\VID_0763&PID_2806` - * @value: the uint16_t DFU version, encoded in base 16, e.g. `0110` - * - * Forces a specific DFU version for the hardware device. This is required - * if the device does not set, or sets incorrectly, items in the DFU functional - * descriptor. - * - * Since: 1.0.1 - */ -#define FU_QUIRKS_DFU_FORCE_VERSION "DfuForceVersion" - -#include "config.h" - -#include - -#include "dfu-common.h" -#include "dfu-device.h" -#include "dfu-target-avr.h" -#include "dfu-target-private.h" -#include "dfu-target-stm.h" - -#include "fu-device-locker.h" -#include "fu-firmware-common.h" - -#include "fwupd-error.h" - -static void dfu_device_finalize (GObject *object); - -typedef struct { - DfuDeviceAttributes attributes; - DfuState state; - DfuStatus status; - GPtrArray *targets; - gboolean done_upload_or_download; - gboolean claimed_interface; - gchar *chip_id; - guint16 version; - guint16 force_version; - guint16 runtime_pid; - guint16 runtime_vid; - guint16 runtime_release; - guint16 transfer_size; - guint8 iface_number; - guint dnload_timeout; - guint timeout_ms; -} DfuDevicePrivate; - -G_DEFINE_TYPE_WITH_PRIVATE (DfuDevice, dfu_device, FU_TYPE_USB_DEVICE) -#define GET_PRIVATE(o) (dfu_device_get_instance_private (o)) - -static void dfu_device_set_state (DfuDevice *device, DfuState state); - -static void -dfu_device_to_string (FuDevice *device, guint idt, GString *str) -{ - DfuDevice *self = DFU_DEVICE (device); - DfuDevicePrivate *priv = GET_PRIVATE (self); - fu_common_string_append_kv (str, idt, "State", dfu_state_to_string (priv->state)); - fu_common_string_append_kv (str, idt, "Status", dfu_status_to_string (priv->status)); - fu_common_string_append_kb (str, idt, "DoneUploadOrDownload", priv->done_upload_or_download); - fu_common_string_append_kb (str, idt, "ClaimedInterface", priv->claimed_interface); - if (priv->chip_id != NULL) - fu_common_string_append_kv (str, idt, "ChipId", priv->chip_id); - fu_common_string_append_kx (str, idt, "Version", priv->version); - fu_common_string_append_kx (str, idt, "ForceVersion", priv->force_version); - fu_common_string_append_kx (str, idt, "RuntimePid", priv->runtime_pid); - fu_common_string_append_kx (str, idt, "RuntimeVid", priv->runtime_vid); - fu_common_string_append_kx (str, idt, "RuntimeRelease", priv->runtime_release); - fu_common_string_append_kx (str, idt, "TransferSize", priv->transfer_size); - fu_common_string_append_kx (str, idt, "IfaceNumber", priv->iface_number); - fu_common_string_append_kx (str, idt, "DnloadTimeout", priv->dnload_timeout); - fu_common_string_append_kx (str, idt, "TimeoutMs", priv->timeout_ms); -} - -/** - * dfu_device_get_transfer_size: - * @device: a #GUsbDevice - * - * Gets the transfer size in bytes. - * - * Return value: packet size, or 0 for unknown - **/ -guint16 -dfu_device_get_transfer_size (DfuDevice *device) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - g_return_val_if_fail (DFU_IS_DEVICE (device), 0xffff); - return priv->transfer_size; -} - -/** - * dfu_device_get_version: - * @device: a #GUsbDevice - * - * Gets the DFU specification version supported by the device. - * - * Return value: integer, or 0 for unknown, e.g. %DFU_VERSION_DFU_1_1 - **/ -guint16 -dfu_device_get_version (DfuDevice *device) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - g_return_val_if_fail (DFU_IS_DEVICE (device), 0xffff); - return priv->version; -} - -/** - * dfu_device_get_download_timeout: - * @device: a #GUsbDevice - * - * Gets the download timeout in ms. - * - * Return value: delay, or 0 for unknown - **/ -guint -dfu_device_get_download_timeout (DfuDevice *device) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - g_return_val_if_fail (DFU_IS_DEVICE (device), 0); - return priv->dnload_timeout; -} - -/** - * dfu_device_set_transfer_size: - * @device: a #GUsbDevice - * @transfer_size: maximum packet size - * - * Sets the transfer size in bytes. - **/ -void -dfu_device_set_transfer_size (DfuDevice *device, guint16 transfer_size) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - g_return_if_fail (DFU_IS_DEVICE (device)); - priv->transfer_size = transfer_size; -} - -typedef struct __attribute__((packed)) { - guint8 bLength; - guint8 bDescriptorType; - guint8 bmAttributes; - guint16 wDetachTimeOut; - guint16 wTransferSize; - guint16 bcdDFUVersion; -} DfuFuncDescriptor; - -static gboolean -dfu_device_parse_iface_data (DfuDevice *device, GBytes *iface_data, GError **error) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - DfuFuncDescriptor desc = { 0x0 }; - const guint8 *buf; - gsize sz; - - /* parse the functional descriptor */ - buf = g_bytes_get_data (iface_data, &sz); - if (sz == sizeof(DfuFuncDescriptor)) { - memcpy (&desc, buf, sz); - } else if (sz > sizeof(DfuFuncDescriptor)) { - g_debug ("DFU interface with %" G_GSIZE_FORMAT " bytes vendor data", - sz - sizeof(DfuFuncDescriptor)); - memcpy (&desc, buf, sizeof(DfuFuncDescriptor)); - } else if (sz == sizeof(DfuFuncDescriptor) - 2) { - g_warning ("truncated DFU interface data, no bcdDFUVersion"); - memcpy (&desc, buf, sz); - desc.bcdDFUVersion = DFU_VERSION_DFU_1_1; - } else { - g_autoptr(GString) bufstr = g_string_new (NULL); - for (gsize i = 0; i < sz; i++) - g_string_append_printf (bufstr, "%02x ", buf[i]); - if (bufstr->len > 0) - g_string_truncate (bufstr, bufstr->len - 1); - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "interface found, but not the correct length for " - "functional data: %" G_GSIZE_FORMAT " bytes: %s", - sz, bufstr->str); - return FALSE; - } - - /* get transfer size and version */ - priv->transfer_size = GUINT16_FROM_LE (desc.wTransferSize); - priv->version = GUINT16_FROM_LE (desc.bcdDFUVersion); - - /* ST-specific */ - if (priv->version == DFU_VERSION_DFUSE && - desc.bmAttributes & DFU_DEVICE_ATTRIBUTE_CAN_ACCELERATE) - priv->transfer_size = 0x1000; - - /* get attributes about the DFU operation */ - priv->attributes = desc.bmAttributes; - return TRUE; -} - -static void -dfu_device_guess_state_from_iface (DfuDevice *device, GUsbInterface *iface) -{ - /* some devices use the wrong interface */ - if (fu_device_has_custom_flag (FU_DEVICE (device), "force-dfu-mode")) { - g_debug ("quirking device into DFU mode"); - dfu_device_set_state (device, DFU_STATE_DFU_IDLE); - return; - } - - /* runtime */ - if (g_usb_interface_get_protocol (iface) == 0x01) { - dfu_device_set_state (device, DFU_STATE_APP_IDLE); - return; - } - - /* DFU */ - if (g_usb_interface_get_protocol (iface) == 0x02) { - dfu_device_set_state (device, DFU_STATE_DFU_IDLE); - return; - } - g_warning ("unable to guess initial device state from interface %u", - g_usb_interface_get_protocol (iface)); -} - -static gboolean -dfu_device_add_targets (DfuDevice *device, GError **error) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); - g_autoptr(GPtrArray) ifaces = NULL; - - /* add all DFU-capable targets */ - ifaces = g_usb_device_get_interfaces (usb_device, error); - if (ifaces == NULL) - return FALSE; - g_ptr_array_set_size (priv->targets, 0); - for (guint i = 0; i < ifaces->len; i++) { - GBytes *iface_data = NULL; - DfuTarget *target; - g_autoptr(GError) error_local = NULL; - - GUsbInterface *iface = g_ptr_array_index (ifaces, i); - - /* some devices don't use the right class and subclass */ - if (!fu_device_has_custom_flag (FU_DEVICE (device), "use-any-interface")) { - if (g_usb_interface_get_class (iface) != G_USB_DEVICE_CLASS_APPLICATION_SPECIFIC) - continue; - if (g_usb_interface_get_subclass (iface) != 0x01) - continue; - } - /* parse any interface data */ - iface_data = g_usb_interface_get_extra (iface); - if (g_bytes_get_size (iface_data) > 0) { - if (!dfu_device_parse_iface_data (device, iface_data, &error_local)) { - g_warning ("failed to parse interface data for %04x:%04x: %s", - g_usb_device_get_vid (usb_device), - g_usb_device_get_pid (usb_device), - error_local->message); - continue; - } - } else { - priv->attributes |= DFU_DEVICE_ATTRIBUTE_CAN_DOWNLOAD | - DFU_DEVICE_ATTRIBUTE_CAN_UPLOAD; - } - - /* fix up the version */ - if (priv->force_version > 0) - priv->version = priv->force_version; - if (priv->version == DFU_VERSION_DFU_1_0 || - priv->version == DFU_VERSION_DFU_1_1) { - g_debug ("DFU v1.1"); - } else if (priv->version == DFU_VERSION_ATMEL_AVR) { - g_debug ("AVR-DFU support"); - priv->version = DFU_VERSION_ATMEL_AVR; - } else if (priv->version == DFU_VERSION_DFUSE) { - g_debug ("STM-DFU support"); - } else if (priv->version == 0x0101) { - g_debug ("DFU v1.1 assumed"); - priv->version = DFU_VERSION_DFU_1_1; - } else { - g_warning ("DFU version 0x%04x invalid, v1.1 assumed", priv->version); - priv->version = DFU_VERSION_DFU_1_1; - } - - /* set expected protocol */ - if (priv->version == DFU_VERSION_DFUSE) { - fu_device_set_protocol (FU_DEVICE (device), "com.st.dfuse"); - } else { - fu_device_set_protocol (FU_DEVICE (device), "org.usb.dfu"); - } - - /* fix up the transfer size */ - if (priv->transfer_size == 0xffff) { - priv->transfer_size = 0x0400; - g_debug ("DFU transfer size unspecified, guessing"); - } - if (priv->transfer_size > 0x0000) { - g_debug ("using DFU transfer size 0x%04x bytes", priv->transfer_size); - } else { - g_warning ("DFU transfer size invalid, using default"); - priv->transfer_size = 64; - } - - /* create a target of the required type */ - switch (priv->version) { - case DFU_VERSION_DFUSE: - target = dfu_target_stm_new (); - break; - case DFU_VERSION_ATMEL_AVR: - target = dfu_target_avr_new (); - break; - default: - target = dfu_target_new (); - break; - } - dfu_target_set_device (target, device); - dfu_target_set_alt_idx (target, g_usb_interface_get_index (iface)); - dfu_target_set_alt_setting (target, g_usb_interface_get_alternate (iface)); - - /* add target */ - priv->iface_number = g_usb_interface_get_number (iface); - g_ptr_array_add (priv->targets, target); - dfu_device_guess_state_from_iface (device, iface); - } - - /* save for reset */ - if (priv->state == DFU_STATE_APP_IDLE || - fu_device_has_custom_flag (FU_DEVICE (device), "no-pid-change")) { - priv->runtime_vid = g_usb_device_get_vid (usb_device); - priv->runtime_pid = g_usb_device_get_pid (usb_device); - priv->runtime_release = g_usb_device_get_release (usb_device); - } - - /* the device has no DFU runtime, so cheat */ - if (priv->targets->len == 0 && - fu_device_has_custom_flag (FU_DEVICE (device), "no-dfu-runtime")) { - g_debug ("no DFU runtime, so faking device"); - dfu_device_set_state (device, DFU_STATE_APP_IDLE); - priv->iface_number = 0xff; - priv->runtime_vid = g_usb_device_get_vid (usb_device); - priv->runtime_pid = g_usb_device_get_pid (usb_device); - priv->runtime_release = g_usb_device_get_release (usb_device); - priv->attributes = DFU_DEVICE_ATTRIBUTE_CAN_DOWNLOAD | - DFU_DEVICE_ATTRIBUTE_CAN_UPLOAD; - return TRUE; - } - - /* no targets */ - if (priv->targets->len == 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "no DFU interfaces"); - return FALSE; - } - - /* the device upload is broken */ - if (fu_device_has_custom_flag (FU_DEVICE (device), "ignore-upload")) - priv->attributes &= ~DFU_DEVICE_ATTRIBUTE_CAN_UPLOAD; - - return TRUE; -} - -/** - * dfu_device_can_upload: - * @device: a #GUsbDevice - * - * Gets if the device can upload. - * - * Return value: %TRUE if the device can upload from device to host - **/ -gboolean -dfu_device_can_upload (DfuDevice *device) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - g_return_val_if_fail (DFU_IS_DEVICE (device), FALSE); - return (priv->attributes & DFU_DEVICE_ATTRIBUTE_CAN_UPLOAD) > 0; -} - -/** - * dfu_device_can_download: - * @device: a #GUsbDevice - * - * Gets if the device can download. - * - * Return value: %TRUE if the device can download from host to device - **/ -gboolean -dfu_device_can_download (DfuDevice *device) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - g_return_val_if_fail (DFU_IS_DEVICE (device), FALSE); - return (priv->attributes & DFU_DEVICE_ATTRIBUTE_CAN_DOWNLOAD) > 0; -} - -/** - * dfu_device_set_timeout: - * @device: a #DfuDevice - * @timeout_ms: the timeout in ms - * - * Sets the USB timeout to use when contacting the USB device. - **/ -void -dfu_device_set_timeout (DfuDevice *device, guint timeout_ms) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - g_return_if_fail (DFU_IS_DEVICE (device)); - priv->timeout_ms = timeout_ms; -} - -/** - * dfu_device_get_timeout: - * @device: a #GUsbDevice - * - * Gets the device timeout. - * - * Return value: enumerated timeout in ms - **/ -guint -dfu_device_get_timeout (DfuDevice *device) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - g_return_val_if_fail (DFU_IS_DEVICE (device), 0); - return priv->timeout_ms; -} - -/** - * dfu_device_get_state: - * @device: a #GUsbDevice - * - * Gets the device state. - * - * Return value: enumerated state, e.g. %DFU_STATE_DFU_UPLOAD_IDLE - **/ -DfuState -dfu_device_get_state (DfuDevice *device) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - g_return_val_if_fail (DFU_IS_DEVICE (device), 0); - return priv->state; -} - -/** - * dfu_device_get_status: - * @device: a #GUsbDevice - * - * Gets the device status. - * - * Return value: enumerated status, e.g. %DFU_STATUS_ERR_ADDRESS - **/ -DfuStatus -dfu_device_get_status (DfuDevice *device) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - g_return_val_if_fail (DFU_IS_DEVICE (device), 0); - return priv->status; -} - -/** - * dfu_device_has_attribute: (skip) - * @device: A #DfuDevice - * @attribute: A #DfuDeviceAttributes, e.g. %DFU_DEVICE_ATTRIBUTE_CAN_DOWNLOAD - * - * Returns if an attribute set for the device. - * - * Return value: %TRUE if the attribute is set - **/ -gboolean -dfu_device_has_attribute (DfuDevice *device, DfuDeviceAttributes attribute) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - g_return_val_if_fail (DFU_IS_DEVICE (device), 0x0); - return (priv->attributes & attribute) > 0; -} - -/** - * dfu_device_remove_attribute: (skip) - * @device: A #DfuDevice - * @attribute: A #DfuDeviceAttributes, e.g. %DFU_DEVICE_ATTRIBUTE_CAN_DOWNLOAD - * - * Removes an attribute from the device. - **/ -void -dfu_device_remove_attribute (DfuDevice *device, DfuDeviceAttributes attribute) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - g_return_if_fail (DFU_IS_DEVICE (device)); - priv->attributes &= ~attribute; -} - -/** - * dfu_device_new: - * - * Creates a new DFU device object. - * - * Return value: a new #DfuDevice - **/ -DfuDevice * -dfu_device_new (GUsbDevice *usb_device) -{ - DfuDevice *device; - device = g_object_new (DFU_TYPE_DEVICE, - "usb-device", usb_device, - NULL); - return device; -} - -/** - * dfu_device_get_targets: - * @device: a #DfuDevice - * - * Gets all the targets for this device. - * - * Return value: (transfer none) (element-type DfuTarget): #DfuTarget, or %NULL - **/ -GPtrArray * -dfu_device_get_targets (DfuDevice *device) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - g_return_val_if_fail (DFU_IS_DEVICE (device), NULL); - return priv->targets; -} - -/** - * dfu_device_get_target_by_alt_setting: - * @device: a #DfuDevice - * @alt_setting: the setting used to find - * @error: a #GError, or %NULL - * - * Gets a target with a specific alternative setting. - * - * Return value: (transfer full): a #DfuTarget, or %NULL - **/ -DfuTarget * -dfu_device_get_target_by_alt_setting (DfuDevice *device, - guint8 alt_setting, - GError **error) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - - g_return_val_if_fail (DFU_IS_DEVICE (device), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - /* find by ID */ - for (guint i = 0; i < priv->targets->len; i++) { - DfuTarget *target = g_ptr_array_index (priv->targets, i); - if (dfu_target_get_alt_setting (target) == alt_setting) - return g_object_ref (target); - } - - /* failed */ - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "No target with alt-setting %i", - alt_setting); - return NULL; -} - -/** - * dfu_device_get_target_by_alt_name: - * @device: a #DfuDevice - * @alt_name: the name used to find - * @error: a #GError, or %NULL - * - * Gets a target with a specific alternative name. - * - * Return value: (transfer full): a #DfuTarget, or %NULL - **/ -DfuTarget * -dfu_device_get_target_by_alt_name (DfuDevice *device, - const gchar *alt_name, - GError **error) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - - g_return_val_if_fail (DFU_IS_DEVICE (device), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - /* find by ID */ - for (guint i = 0; i < priv->targets->len; i++) { - DfuTarget *target = g_ptr_array_index (priv->targets, i); - if (g_strcmp0 (dfu_target_get_alt_name (target, NULL), alt_name) == 0) - return g_object_ref (target); - } - - /* failed */ - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "No target with alt-name %s", - alt_name); - return NULL; -} - -/** - * dfu_device_get_platform_id: - * @device: a #DfuDevice - * - * Gets the platform ID which normally corresponds to the port in some way. - * - * Return value: string or %NULL - **/ -const gchar * -dfu_device_get_platform_id (DfuDevice *device) -{ - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); - g_return_val_if_fail (DFU_IS_DEVICE (device), NULL); - return g_usb_device_get_platform_id (usb_device); -} - -/** - * dfu_device_get_runtime_vid: - * @device: a #DfuDevice - * - * Gets the runtime vendor ID. - * - * Return value: vendor ID, or 0xffff for unknown - **/ -guint16 -dfu_device_get_runtime_vid (DfuDevice *device) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - g_return_val_if_fail (DFU_IS_DEVICE (device), 0xffff); - return priv->runtime_vid; -} - -/** - * dfu_device_get_runtime_pid: - * @device: a #DfuDevice - * - * Gets the runtime product ID. - * - * Return value: product ID, or 0xffff for unknown - **/ -guint16 -dfu_device_get_runtime_pid (DfuDevice *device) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - g_return_val_if_fail (DFU_IS_DEVICE (device), 0xffff); - return priv->runtime_pid; -} - -/** - * dfu_device_get_runtime_release: - * @device: a #DfuDevice - * - * Gets the runtime release number in BCD format. - * - * Return value: release number, or 0xffff for unknown - **/ -guint16 -dfu_device_get_runtime_release (DfuDevice *device) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - g_return_val_if_fail (DFU_IS_DEVICE (device), 0xffff); - return priv->runtime_release; -} - -const gchar * -dfu_device_get_chip_id (DfuDevice *device) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - g_return_val_if_fail (DFU_IS_DEVICE (device), NULL); - return priv->chip_id; -} - -void -dfu_device_set_chip_id (DfuDevice *device, const gchar *chip_id) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - g_return_if_fail (DFU_IS_DEVICE (device)); - g_debug ("chip ID set to: %s", chip_id); - priv->chip_id = g_strdup (chip_id); -} - -static void -dfu_device_set_state (DfuDevice *device, DfuState state) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - if (priv->state == state) - return; - priv->state = state; - - /* set bootloader status */ - if (state == DFU_STATE_APP_IDLE || - state == DFU_STATE_APP_DETACH) { - fu_device_remove_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); - } else { - fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); - } - - switch (state) { - case DFU_STATE_DFU_UPLOAD_IDLE: - fu_device_set_status (FU_DEVICE (device), FWUPD_STATUS_DEVICE_VERIFY); - break; - case DFU_STATE_DFU_DNLOAD_IDLE: - fu_device_set_status (FU_DEVICE (device), FWUPD_STATUS_DEVICE_WRITE); - break; - default: - break; - } -} - -static void -dfu_device_set_status (DfuDevice *device, DfuStatus status) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - if (priv->status == status) - return; - priv->status = status; -} - -gboolean -dfu_device_ensure_interface (DfuDevice *device, GError **error) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); - g_autoptr(GError) error_local = NULL; - - /* already done */ - if (priv->claimed_interface) - return TRUE; - - /* nothing set */ - if (priv->iface_number == 0xff) - return TRUE; - - /* claim, without detaching kernel driver */ - if (!g_usb_device_claim_interface (usb_device, - (gint) priv->iface_number, - G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, - &error_local)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "cannot claim interface %i: %s", - priv->iface_number, error_local->message); - return FALSE; - } - - /* success */ - priv->claimed_interface = TRUE; - return TRUE; -} - -/** - * dfu_device_refresh_and_clear: - * @device: a #DfuDevice - * @error: a #GError, or %NULL - * - * Refreshes the cached properties on the DFU device. If there are any transers - * in progress they are cancelled, and if there are any pending errors they are - * cancelled. - * - * Return value: %TRUE for success - **/ -gboolean -dfu_device_refresh_and_clear (DfuDevice *device, GError **error) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - if (!dfu_device_refresh (device, error)) - return FALSE; - switch (priv->state) { - case DFU_STATE_DFU_UPLOAD_IDLE: - case DFU_STATE_DFU_DNLOAD_IDLE: - case DFU_STATE_DFU_DNLOAD_SYNC: - g_debug ("aborting transfer %s", dfu_status_to_string (priv->status)); - if (!dfu_device_abort (device, error)) - return FALSE; - break; - case DFU_STATE_DFU_ERROR: - g_debug ("clearing error %s", dfu_status_to_string (priv->status)); - if (!dfu_device_clear_status (device, error)) - return FALSE; - break; - default: - break; - } - return TRUE; -} - -/** - * dfu_device_refresh: - * @device: a #DfuDevice - * @error: a #GError, or %NULL - * - * Refreshes the cached properties on the DFU device. - * - * Return value: %TRUE for success - **/ -gboolean -dfu_device_refresh (DfuDevice *device, GError **error) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); - gsize actual_length = 0; - guint8 buf[6]; - g_autoptr(GError) error_local = NULL; - - g_return_val_if_fail (DFU_IS_DEVICE (device), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* no backing USB device */ - if (usb_device == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "failed to refresh: no GUsbDevice for %s", - dfu_device_get_platform_id (device)); - return FALSE; - } - - /* the device has no DFU runtime, so cheat */ - if (priv->state == DFU_STATE_APP_IDLE && - fu_device_has_custom_flag (FU_DEVICE (device), "no-dfu-runtime")) - return TRUE; - - /* ensure interface is claimed */ - if (!dfu_device_ensure_interface (device, error)) - return FALSE; - - /* Device that cannot communicate via the USB after the - * Manifestation phase indicated this limitation to the - * host by clearing bmAttributes bit bitManifestationTolerant. - * so we assume the operation was successful */ - if (priv->state == DFU_STATE_DFU_MANIFEST && - !(priv->attributes & DFU_DEVICE_ATTRIBUTE_MANIFEST_TOL)) - return TRUE; - - if (!g_usb_device_control_transfer (usb_device, - G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, - G_USB_DEVICE_REQUEST_TYPE_CLASS, - G_USB_DEVICE_RECIPIENT_INTERFACE, - DFU_REQUEST_GETSTATUS, - 0, - priv->iface_number, - buf, sizeof(buf), &actual_length, - priv->timeout_ms, - NULL, /* cancellable */ - &error_local)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "cannot get device state: %s", - error_local->message); - return FALSE; - } - if (actual_length != 6) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "cannot get device status, invalid size: %04x", - (guint) actual_length); - return FALSE; - } - - /* some devices use the wrong state value */ - if (fu_device_has_custom_flag (FU_DEVICE (device), "force-dfu-mode") && - dfu_device_get_state (device) != DFU_STATE_DFU_IDLE) { - g_debug ("quirking device into DFU mode"); - dfu_device_set_state (device, DFU_STATE_DFU_IDLE); - } else { - dfu_device_set_state (device, buf[4]); - } - - /* status or state changed */ - dfu_device_set_status (device, buf[0]); - if (fu_device_has_custom_flag (FU_DEVICE (device), "ignore-polltimeout")) { - priv->dnload_timeout = 5; - } else { - priv->dnload_timeout = buf[1] + - (((guint32) buf[2]) << 8) + - (((guint32) buf[3]) << 16); - } - g_debug ("refreshed status=%s and state=%s (dnload=%u)", - dfu_status_to_string (priv->status), - dfu_state_to_string (priv->state), - priv->dnload_timeout); - return TRUE; -} - -static gboolean -dfu_device_request_detach (DfuDevice *self, GError **error) -{ - DfuDevicePrivate *priv = GET_PRIVATE (self); - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); - const guint16 timeout_reset_ms = 1000; - g_autoptr(GError) error_local = NULL; - - if (!g_usb_device_control_transfer (usb_device, - G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, - G_USB_DEVICE_REQUEST_TYPE_CLASS, - G_USB_DEVICE_RECIPIENT_INTERFACE, - DFU_REQUEST_DETACH, - timeout_reset_ms, - priv->iface_number, - NULL, 0, NULL, - priv->timeout_ms, - NULL, /* cancellable */ - &error_local)) { - /* some devices just reboot and stall the endpoint :/ */ - if (g_error_matches (error_local, - G_USB_DEVICE_ERROR, - G_USB_DEVICE_ERROR_NOT_SUPPORTED) || - g_error_matches (error_local, - G_USB_DEVICE_ERROR, - G_USB_DEVICE_ERROR_FAILED)) { - g_debug ("ignoring while detaching: %s", error_local->message); - } else { - /* refresh the error code */ - dfu_device_error_fixup (self, &error_local); - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "cannot detach device: %s", - error_local->message); - return FALSE; - } - } - return TRUE; -} - -static gboolean -dfu_device_reload (FuDevice *device, GError **error) -{ - DfuDevice *self = DFU_DEVICE (device); - return dfu_device_refresh_and_clear (self, error); -} - -static gboolean -dfu_device_detach (FuDevice *device, GError **error) -{ - DfuDevice *self = DFU_DEVICE (device); - DfuDevicePrivate *priv = GET_PRIVATE (self); - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); - - g_return_val_if_fail (DFU_IS_DEVICE (self), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* already in DFU mode */ - if (!dfu_device_refresh_and_clear (self, error)) - return FALSE; - if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) - return TRUE; - - /* no backing USB device */ - if (usb_device == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "failed to detach: no GUsbDevice for %s", - dfu_device_get_platform_id (self)); - return FALSE; - } - - /* the device has no DFU runtime, so cheat */ - if (priv->state == DFU_STATE_APP_IDLE && - fu_device_has_custom_flag (FU_DEVICE (self), "no-dfu-runtime")) - return TRUE; - - /* ensure interface is claimed */ - if (!dfu_device_ensure_interface (self, error)) - return FALSE; - - /* inform UI there's going to be a detach:attach */ - fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); - if (!dfu_device_request_detach (self, error)) - return FALSE; - - /* do a host reset */ - if ((priv->attributes & DFU_DEVICE_ATTRIBUTE_WILL_DETACH) == 0) { - g_debug ("doing device reset as host will not self-reset"); - if (!dfu_device_reset (self, error)) - return FALSE; - } - - /* success */ - priv->force_version = 0x0; - fu_device_set_status (device, FWUPD_STATUS_IDLE); - fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); - return TRUE; -} - -/** - * dfu_device_abort: - * @device: a #DfuDevice - * @error: a #GError, or %NULL - * - * Aborts any upload or download in progress. - * - * Return value: %TRUE for success - **/ -gboolean -dfu_device_abort (DfuDevice *device, GError **error) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); - g_autoptr(GError) error_local = NULL; - - g_return_val_if_fail (DFU_IS_DEVICE (device), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* no backing USB device */ - if (usb_device == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "failed to abort: no GUsbDevice for %s", - dfu_device_get_platform_id (device)); - return FALSE; - } - - /* the device has no DFU runtime, so cheat */ - if (priv->state == DFU_STATE_APP_IDLE && - fu_device_has_custom_flag (FU_DEVICE (device), "no-dfu-runtime")) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "not supported as no DFU runtime"); - return FALSE; - } - - /* ensure interface is claimed */ - if (!dfu_device_ensure_interface (device, error)) - return FALSE; - - if (!g_usb_device_control_transfer (usb_device, - G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, - G_USB_DEVICE_REQUEST_TYPE_CLASS, - G_USB_DEVICE_RECIPIENT_INTERFACE, - DFU_REQUEST_ABORT, - 0, - priv->iface_number, - NULL, 0, NULL, - priv->timeout_ms, - NULL, /* cancellable */ - &error_local)) { - /* refresh the error code */ - dfu_device_error_fixup (device, &error_local); - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "cannot abort device: %s", - error_local->message); - return FALSE; - } - - return TRUE; -} - -/** - * dfu_device_clear_status: - * @device: a #DfuDevice - * @error: a #GError, or %NULL - * - * Clears any error status on the DFU device. - * - * Return value: %TRUE for success - **/ -gboolean -dfu_device_clear_status (DfuDevice *device, GError **error) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); - g_autoptr(GError) error_local = NULL; - - g_return_val_if_fail (DFU_IS_DEVICE (device), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* no backing USB device */ - if (usb_device == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "failed to clear status: no GUsbDevice for %s", - dfu_device_get_platform_id (device)); - return FALSE; - } - - /* the device has no DFU runtime, so cheat */ - if (priv->state == DFU_STATE_APP_IDLE && - fu_device_has_custom_flag (FU_DEVICE (device), "no-dfu-runtime")) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "not supported as no DFU runtime"); - return FALSE; - } - - /* ensure interface is claimed */ - if (!dfu_device_ensure_interface (device, error)) - return FALSE; - - if (!g_usb_device_control_transfer (usb_device, - G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, - G_USB_DEVICE_REQUEST_TYPE_CLASS, - G_USB_DEVICE_RECIPIENT_INTERFACE, - DFU_REQUEST_CLRSTATUS, - 0, - priv->iface_number, - NULL, 0, NULL, - priv->timeout_ms, - NULL, /* cancellable */ - &error_local)) { - /* refresh the error code */ - dfu_device_error_fixup (device, &error_local); - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "cannot clear status on the device: %s", - error_local->message); - return FALSE; - } - return TRUE; -} - -/** - * dfu_device_get_interface: - * @device: a #DfuDevice - * - * Gets the interface number. - **/ -guint8 -dfu_device_get_interface (DfuDevice *device) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - g_return_val_if_fail (DFU_IS_DEVICE (device), 0xff); - return priv->iface_number; -} - -/** - * dfu_device_open: - * @device: a #DfuDevice - * @error: a #GError, or %NULL - * - * Opens a DFU-capable device. - * - * Return value: %TRUE for success - **/ -static gboolean -dfu_device_open (FuUsbDevice *device, GError **error) -{ - DfuDevice *self = DFU_DEVICE (device); - DfuDevicePrivate *priv = GET_PRIVATE (self); - GPtrArray *targets = dfu_device_get_targets (self); - - g_return_val_if_fail (DFU_IS_DEVICE (device), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* the device has no DFU runtime, so cheat */ - if (priv->state == DFU_STATE_APP_IDLE && - fu_device_has_custom_flag (FU_DEVICE (self), "no-dfu-runtime")) { - dfu_device_set_state (self, DFU_STATE_APP_IDLE); - priv->status = DFU_STATUS_OK; - } - - /* set up target ready for use */ - for (guint j = 0; j < targets->len; j++) { - DfuTarget *target = g_ptr_array_index (targets, j); - if (!dfu_target_setup (target, error)) - return FALSE; - } - - /* success */ - return TRUE; -} - -/** - * dfu_device_close: - * @device: a #DfuDevice - * @error: a #GError, or %NULL - * - * Closes a DFU device. - * - * Return value: %TRUE for success - **/ -static gboolean -dfu_device_close (FuUsbDevice *device, GError **error) -{ - DfuDevice *self = DFU_DEVICE (device); - DfuDevicePrivate *priv = GET_PRIVATE (self); - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); - - /* release interface */ - if (priv->claimed_interface) { - g_usb_device_release_interface (usb_device, - (gint) priv->iface_number, - 0, NULL); - priv->claimed_interface = FALSE; - } - - return TRUE; -} - -static gboolean -dfu_device_probe (FuUsbDevice *device, GError **error) -{ - DfuDevice *self = DFU_DEVICE (device); - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); - - /* add all the targets */ - if (!dfu_device_add_targets (self, error)) { - g_prefix_error (error, "%04x:%04x is not supported: ", - g_usb_device_get_vid (usb_device), - g_usb_device_get_pid (usb_device)); - return FALSE; - } - - /* check capabilities */ - if (!dfu_device_can_download (self)) { - g_warning ("%04x:%04x is missing download capability", - g_usb_device_get_vid (usb_device), - g_usb_device_get_pid (usb_device)); - } - - /* hardware rom Jabra literally reboots if you try to retry a failed - * write -- there's no way to avoid blocking the daemon like this... */ - if (fu_device_has_custom_flag (FU_DEVICE (device), "attach-extra-reset")) - g_usleep (10 * G_USEC_PER_SEC); - - /* success */ - return TRUE; -} - -/** - * dfu_device_reset: - * @device: a #DfuDevice - * @error: a #GError, or %NULL - * - * Resets the USB device. - * - * Return value: %TRUE for success - **/ -gboolean -dfu_device_reset (DfuDevice *device, GError **error) -{ - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); - g_autoptr(GError) error_local = NULL; - g_autoptr(GTimer) timer = g_timer_new (); - - g_return_val_if_fail (DFU_IS_DEVICE (device), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* no backing USB device */ - if (usb_device == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "failed to reset: no GUsbDevice for %s", - dfu_device_get_platform_id (device)); - return FALSE; - } - - if (!g_usb_device_reset (usb_device, &error_local)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "cannot reset USB device: %s [%i]", - error_local->message, - error_local->code); - return FALSE; - } - g_debug ("reset took %.2lfms", g_timer_elapsed (timer, NULL) * 1000); - return TRUE; -} - -static gboolean -dfu_device_attach (FuDevice *device, GError **error) -{ - DfuDevice *self = DFU_DEVICE (device); - DfuDevicePrivate *priv = GET_PRIVATE (self); - g_autoptr(DfuTarget) target = NULL; - - g_return_val_if_fail (DFU_IS_DEVICE (device), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* already in runtime mode */ - if (!dfu_device_refresh_and_clear (self, error)) - return FALSE; - if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) - return TRUE; - - /* inform UI there's going to be a re-attach */ - fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); - - /* handle weirdness */ - if (fu_device_has_custom_flag (device, "detach-for-attach")) { - if (!dfu_device_request_detach (self, error)) - return FALSE; - fu_device_set_status (device, FWUPD_STATUS_IDLE); - fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); - return TRUE; - } - - /* handle m-stack DFU bootloaders */ - if (!priv->done_upload_or_download && - fu_device_has_custom_flag (FU_DEVICE (self), "attach-upload-download")) { - g_autoptr(GBytes) chunk = NULL; - g_autoptr(DfuTarget) target_zero = NULL; - g_debug ("doing dummy upload to work around m-stack quirk"); - target_zero = dfu_device_get_target_by_alt_setting (self, 0, error); - if (target_zero == NULL) - return FALSE; - chunk = dfu_target_upload_chunk (target_zero, 0, 0, error); - if (chunk == NULL) - return FALSE; - } - - /* get default target */ - target = dfu_device_get_target_by_alt_setting (self, 0, error); - if (target == NULL) - return FALSE; - - /* normal DFU mode just needs a bus reset */ - if (!dfu_target_attach (target, error)) - return FALSE; - - /* success */ - priv->force_version = 0x0; - fu_device_set_status (device, FWUPD_STATUS_IDLE); - fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); - return TRUE; -} - -static void -dfu_device_percentage_cb (DfuTarget *target, guint percentage, DfuDevice *device) -{ - fu_device_set_progress (FU_DEVICE (device), percentage); -} - -static void -dfu_device_action_cb (DfuTarget *target, FwupdStatus action, DfuDevice *device) -{ - fu_device_set_status (FU_DEVICE (device), action); -} - -/** - * dfu_device_upload: - * @device: a #DfuDevice - * @flags: flags to use, e.g. %DFU_TARGET_TRANSFER_FLAG_VERIFY - * @error: a #GError, or %NULL - * - * Uploads firmware from the target to the host. - * - * Return value: (transfer full): the uploaded firmware, or %NULL for error - **/ -DfuFirmware * -dfu_device_upload (DfuDevice *device, - DfuTargetTransferFlags flags, - GError **error) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); - g_autoptr(DfuFirmware) firmware = NULL; - - /* no backing USB device */ - if (usb_device == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "failed to upload: no GUsbDevice for %s", - dfu_device_get_platform_id (device)); - return NULL; - } - - /* ensure interface is claimed */ - if (!dfu_device_ensure_interface (device, error)) - return NULL; - - /* create ahead of time */ - firmware = dfu_firmware_new (); - fu_dfu_firmware_set_vid (FU_DFU_FIRMWARE (firmware), priv->runtime_vid); - fu_dfu_firmware_set_pid (FU_DFU_FIRMWARE (firmware), priv->runtime_pid); - fu_dfu_firmware_set_release (FU_DFU_FIRMWARE (firmware), 0xffff); - - /* upload from each target */ - for (guint i = 0; i < priv->targets->len; i++) { - DfuTarget *target; - const gchar *alt_name; - gulong id1; - gulong id2; - g_autoptr(DfuImage) image = NULL; - - /* upload to target and proxy signals */ - target = g_ptr_array_index (priv->targets, i); - - /* ignore some target types */ - alt_name = dfu_target_get_alt_name_for_display (target, NULL); - if (g_strcmp0 (alt_name, "Option Bytes") == 0) { - g_debug ("ignoring target %s", alt_name); - continue; - } - - id1 = g_signal_connect (target, "percentage-changed", - G_CALLBACK (dfu_device_percentage_cb), device); - id2 = g_signal_connect (target, "action-changed", - G_CALLBACK (dfu_device_action_cb), device); - image = dfu_target_upload (target, - DFU_TARGET_TRANSFER_FLAG_NONE, - error); - g_signal_handler_disconnect (target, id1); - g_signal_handler_disconnect (target, id2); - if (image == NULL) - return NULL; - fu_firmware_add_image (FU_FIRMWARE (firmware), FU_FIRMWARE_IMAGE (image)); - } - - /* do not do the dummy upload for quirked devices */ - priv->done_upload_or_download = TRUE; - - /* choose the most appropriate type */ - if (priv->targets->len > 1) { - g_debug ("switching to DefuSe automatically"); - dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_DFUSE); - } else { - dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_DFU); - } - - /* success */ - fu_device_set_status (FU_DEVICE (device), FWUPD_STATUS_IDLE); - return g_object_ref (firmware); -} - -static gboolean -dfu_device_id_compatible (guint16 id_file, guint16 id_runtime, guint16 id_dev) -{ - /* file doesn't specify */ - if (id_file == 0xffff) - return TRUE; - - /* runtime matches */ - if (id_runtime != 0xffff && id_file == id_runtime) - return TRUE; - - /* bootloader matches */ - if (id_dev != 0xffff && id_file == id_dev) - return TRUE; - - /* nothing */ - return FALSE; -} - -static gboolean -dfu_device_download (DfuDevice *device, - DfuFirmware *firmware, - DfuTargetTransferFlags flags, - GError **error) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); - gboolean ret; - g_autoptr(GPtrArray) images = NULL; - - /* no backing USB device */ - if (usb_device == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "failed to download: no GUsbDevice for %s", - dfu_device_get_platform_id (device)); - return FALSE; - } - - /* ensure interface is claimed */ - if (!dfu_device_ensure_interface (device, error)) - return FALSE; - - /* do we allow wildcard VID:PID matches */ - if ((flags & DFU_TARGET_TRANSFER_FLAG_WILDCARD_VID) == 0) { - if (fu_dfu_firmware_get_vid (FU_DFU_FIRMWARE (firmware)) == 0xffff) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "firmware vendor ID not specified"); - return FALSE; - } - } - if ((flags & DFU_TARGET_TRANSFER_FLAG_WILDCARD_PID) == 0) { - if (fu_dfu_firmware_get_pid (FU_DFU_FIRMWARE (firmware)) == 0xffff) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "firmware product ID not specified"); - return FALSE; - } - } - - /* check vendor matches */ - if (priv->runtime_vid != 0xffff) { - if (!dfu_device_id_compatible (fu_dfu_firmware_get_vid (FU_DFU_FIRMWARE (firmware)), - priv->runtime_vid, - fu_usb_device_get_vid (FU_USB_DEVICE (device)))) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "vendor ID incorrect, expected 0x%04x " - "got 0x%04x and 0x%04x\n", - fu_dfu_firmware_get_vid (FU_DFU_FIRMWARE (firmware)), - priv->runtime_vid, - fu_usb_device_get_vid (FU_USB_DEVICE (device))); - return FALSE; - } - } - - /* check product matches */ - if (priv->runtime_pid != 0xffff) { - if (!dfu_device_id_compatible (fu_dfu_firmware_get_pid (FU_DFU_FIRMWARE (firmware)), - priv->runtime_pid, - fu_usb_device_get_pid (FU_USB_DEVICE (device)))) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "product ID incorrect, expected 0x%04x " - "got 0x%04x and 0x%04x", - fu_dfu_firmware_get_pid (FU_DFU_FIRMWARE (firmware)), - priv->runtime_pid, - fu_usb_device_get_pid (FU_USB_DEVICE (device))); - return FALSE; - } - } - - /* download each target */ - images = fu_firmware_get_images (FU_FIRMWARE (firmware)); - if (images->len == 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "no images in firmware file"); - return FALSE; - } - for (guint i = 0; i < images->len; i++) { - DfuImage *image; - DfuTargetTransferFlags flags_local = DFU_TARGET_TRANSFER_FLAG_NONE; - const gchar *alt_name; - gulong id1; - gulong id2; - g_autoptr(DfuTarget) target_tmp = NULL; - g_autoptr(GError) error_local = NULL; - - image = g_ptr_array_index (images, i); - target_tmp = dfu_device_get_target_by_alt_setting (device, - dfu_image_get_alt_setting (image), - error); - if (target_tmp == NULL) - return FALSE; - - /* we don't actually need to print this */ - alt_name = dfu_target_get_alt_name (target_tmp, &error_local); - if (alt_name == NULL) { - if (g_error_matches (error_local, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND)) { - alt_name = "unknown"; - } else { - g_propagate_error (error, g_steal_pointer (&error_local)); - return FALSE; - } - } - g_debug ("downloading to target: %s", alt_name); - - /* download onto target */ - if (flags & DFU_TARGET_TRANSFER_FLAG_VERIFY) - flags_local = DFU_TARGET_TRANSFER_FLAG_VERIFY; - if (dfu_firmware_get_format (firmware) == DFU_FIRMWARE_FORMAT_RAW) - flags_local |= DFU_TARGET_TRANSFER_FLAG_ADDR_HEURISTIC; - id1 = g_signal_connect (target_tmp, "percentage-changed", - G_CALLBACK (dfu_device_percentage_cb), device); - id2 = g_signal_connect (target_tmp, "action-changed", - G_CALLBACK (dfu_device_action_cb), device); - ret = dfu_target_download (target_tmp, - image, - flags_local, - error); - g_signal_handler_disconnect (target_tmp, id1); - g_signal_handler_disconnect (target_tmp, id2); - if (!ret) - return FALSE; - } - - /* do not do the dummy upload for quirked devices */ - priv->done_upload_or_download = TRUE; - - /* success */ - fu_device_set_status (FU_DEVICE (device), FWUPD_STATUS_IDLE); - return TRUE; -} - -void -dfu_device_error_fixup (DfuDevice *device, GError **error) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - - /* sad panda */ - if (error == NULL) - return; - - /* not the right error to query */ - if (!g_error_matches (*error, - G_USB_DEVICE_ERROR, - G_USB_DEVICE_ERROR_NOT_SUPPORTED)) - return; - - /* get the status */ - if (!dfu_device_refresh (device, NULL)) - return; - - /* not in an error state */ - if (priv->state != DFU_STATE_DFU_ERROR) - return; - - /* prefix the error */ - switch (priv->status) { - case DFU_STATUS_OK: - /* ignore */ - break; - case DFU_STATUS_ERR_VENDOR: - g_prefix_error (error, "read protection is active: "); - break; - default: - g_prefix_error (error, "[%s,%s]: ", - dfu_state_to_string (priv->state), - dfu_status_to_string (priv->status)); - break; - } -} - -static FuFirmware * -dfu_device_read_firmware (FuDevice *device, GError **error) -{ - DfuDevice *self = DFU_DEVICE (device); - g_autoptr(DfuFirmware) dfu_firmware = NULL; - g_autoptr(GBytes) fw = NULL; - - /* get data from hardware */ - g_debug ("uploading from device->host"); - if (!dfu_device_refresh_and_clear (self, error)) - return NULL; - dfu_firmware = dfu_device_upload (self, - DFU_TARGET_TRANSFER_FLAG_NONE, - error); - if (dfu_firmware == NULL) - return NULL; - - /* get the checksum */ - fw = dfu_firmware_write_data (dfu_firmware, error); - return fu_firmware_new_from_bytes (fw); -} - -static gboolean -dfu_device_write_firmware (FuDevice *device, - FuFirmware *firmware, - FwupdInstallFlags flags, - GError **error) -{ - DfuDevice *self = DFU_DEVICE (device); - DfuTargetTransferFlags transfer_flags = DFU_TARGET_TRANSFER_FLAG_VERIFY; - g_autoptr(DfuFirmware) dfu_firmware = NULL; - g_autoptr(GBytes) blob_fw = NULL; - - /* open it */ - blob_fw = fu_firmware_get_image_default_bytes (firmware, error); - if (blob_fw == NULL) - return FALSE; - if (!dfu_device_refresh_and_clear (self, error)) - return FALSE; - - if (flags & FWUPD_INSTALL_FLAG_FORCE) { - transfer_flags |= DFU_TARGET_TRANSFER_FLAG_WILDCARD_VID; - transfer_flags |= DFU_TARGET_TRANSFER_FLAG_WILDCARD_PID; - } - - /* hit hardware */ - dfu_firmware = dfu_firmware_new (); - if (!dfu_firmware_parse_data (dfu_firmware, blob_fw, - FWUPD_INSTALL_FLAG_NONE, error)) - return FALSE; - return dfu_device_download (self, dfu_firmware, transfer_flags, error); -} - -static gboolean -dfu_device_set_quirk_kv (FuDevice *device, - const gchar *key, - const gchar *value, - GError **error) -{ - DfuDevice *self = DFU_DEVICE (device); - DfuDevicePrivate *priv = GET_PRIVATE (self); - - if (g_strcmp0 (key, FU_QUIRKS_DFU_FORCE_VERSION) == 0) { - if (value != NULL && strlen (value) == 4) { - priv->force_version = fu_firmware_strparse_uint16 (value); - return TRUE; - } - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "invalid DFU version"); - return FALSE; - } - if (g_strcmp0 (key, "DfuForceTimeout") == 0) { - guint64 tmp = fu_common_strtoull (value); - if (tmp < G_MAXUINT) { - priv->timeout_ms = tmp; - return TRUE; - } - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "invalid DFU timeout"); - return FALSE; - } - - /* failed */ - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - "quirk key not supported"); - return FALSE; -} - -/** - * dfu_device_get_attributes_as_string: (skip) - * @device: a #DfuDevice - * - * Gets a string describing the attributes for a device. - * - * Return value: a string, possibly empty - **/ -gchar * -dfu_device_get_attributes_as_string (DfuDevice *device) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - GString *str; - - /* just append to a string */ - str = g_string_new (""); - if (priv->attributes & DFU_DEVICE_ATTRIBUTE_CAN_DOWNLOAD) - g_string_append_printf (str, "can-download|"); - if (priv->attributes & DFU_DEVICE_ATTRIBUTE_CAN_UPLOAD) - g_string_append_printf (str, "can-upload|"); - if (priv->attributes & DFU_DEVICE_ATTRIBUTE_MANIFEST_TOL) - g_string_append_printf (str, "manifest-tol|"); - if (priv->attributes & DFU_DEVICE_ATTRIBUTE_WILL_DETACH) - g_string_append_printf (str, "will-detach|"); - if (priv->attributes & DFU_DEVICE_ATTRIBUTE_CAN_ACCELERATE) - g_string_append_printf (str, "can-accelerate|"); - - /* remove trailing pipe */ - g_string_truncate (str, str->len - 1); - return g_string_free (str, FALSE); -} - -static void -dfu_device_finalize (GObject *object) -{ - DfuDevice *device = DFU_DEVICE (object); - DfuDevicePrivate *priv = GET_PRIVATE (device); - - g_free (priv->chip_id); - g_ptr_array_unref (priv->targets); - - G_OBJECT_CLASS (dfu_device_parent_class)->finalize (object); -} - -static void -dfu_device_class_init (DfuDeviceClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); - klass_device->set_quirk_kv = dfu_device_set_quirk_kv; - klass_device->to_string = dfu_device_to_string; - klass_device->read_firmware = dfu_device_read_firmware; - klass_device->write_firmware = dfu_device_write_firmware; - klass_device->attach = dfu_device_attach; - klass_device->detach = dfu_device_detach; - klass_device->reload = dfu_device_reload; - klass_usb_device->open = dfu_device_open; - klass_usb_device->close = dfu_device_close; - klass_usb_device->probe = dfu_device_probe; - object_class->finalize = dfu_device_finalize; -} - -static void -dfu_device_init (DfuDevice *device) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - priv->iface_number = 0xff; - priv->runtime_pid = 0xffff; - priv->runtime_vid = 0xffff; - priv->runtime_release = 0xffff; - priv->state = DFU_STATE_APP_IDLE; - priv->status = DFU_STATUS_OK; - priv->targets = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - priv->timeout_ms = 1500; - priv->transfer_size = 64; - fu_device_add_icon (FU_DEVICE (device), "drive-harddisk-usb"); - fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_UPDATABLE); - fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_ADD_COUNTERPART_GUIDS); - fu_device_set_remove_delay (FU_DEVICE (device), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); -} diff -Nru fwupd-1.4.5/plugins/dfu/dfu-device.h fwupd-1.5.8/plugins/dfu/dfu-device.h --- fwupd-1.4.5/plugins/dfu/dfu-device.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/dfu-device.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2015-2017 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include -#include -#include - -#include "fu-usb-device.h" - -#include "dfu-common.h" -#include "dfu-target.h" -#include "dfu-firmware.h" - -#define DFU_TYPE_DEVICE (dfu_device_get_type ()) -G_DECLARE_DERIVABLE_TYPE (DfuDevice, dfu_device, DFU, DEVICE, FuUsbDevice) - -/** - * DfuDeviceAttributes: - * @DFU_DEVICE_ATTRIBUTE_NONE: No attributes set - * @DFU_DEVICE_ATTRIBUTE_CAN_DOWNLOAD: Can download from host->device - * @DFU_DEVICE_ATTRIBUTE_CAN_UPLOAD: Can upload from device->host - * @DFU_DEVICE_ATTRIBUTE_MANIFEST_TOL: Can answer GetStatus in manifest - * @DFU_DEVICE_ATTRIBUTE_WILL_DETACH: Will self-detach - * @DFU_DEVICE_ATTRIBUTE_CAN_ACCELERATE: Use a larger transfer size for speed - * - * The device DFU attributes. - **/ -typedef enum { - DFU_DEVICE_ATTRIBUTE_NONE = 0, - DFU_DEVICE_ATTRIBUTE_CAN_DOWNLOAD = (1 << 0), - DFU_DEVICE_ATTRIBUTE_CAN_UPLOAD = (1 << 1), - DFU_DEVICE_ATTRIBUTE_MANIFEST_TOL = (1 << 2), - DFU_DEVICE_ATTRIBUTE_WILL_DETACH = (1 << 3), - DFU_DEVICE_ATTRIBUTE_CAN_ACCELERATE = (1 << 7), - /*< private >*/ - DFU_DEVICE_ATTRIBUTE_LAST -} DfuDeviceAttributes; - -struct _DfuDeviceClass -{ - FuUsbDeviceClass parent_class; -}; - -DfuDevice *dfu_device_new (GUsbDevice *usb_device); -const gchar *dfu_device_get_platform_id (DfuDevice *device); -GPtrArray *dfu_device_get_targets (DfuDevice *device); -DfuTarget *dfu_device_get_target_by_alt_setting (DfuDevice *device, - guint8 alt_setting, - GError **error); -DfuTarget *dfu_device_get_target_by_alt_name (DfuDevice *device, - const gchar *alt_name, - GError **error); -const gchar *dfu_device_get_chip_id (DfuDevice *device); -void dfu_device_set_chip_id (DfuDevice *device, - const gchar *chip_id); -guint16 dfu_device_get_runtime_vid (DfuDevice *device); -guint16 dfu_device_get_runtime_pid (DfuDevice *device); -guint16 dfu_device_get_runtime_release (DfuDevice *device); -gboolean dfu_device_reset (DfuDevice *device, - GError **error); -DfuFirmware *dfu_device_upload (DfuDevice *device, - DfuTargetTransferFlags flags, - GError **error); -gboolean dfu_device_refresh (DfuDevice *device, - GError **error); -gboolean dfu_device_refresh_and_clear (DfuDevice *device, - GError **error); -gboolean dfu_device_abort (DfuDevice *device, - GError **error); -gboolean dfu_device_clear_status (DfuDevice *device, - GError **error); - -guint8 dfu_device_get_interface (DfuDevice *device); -DfuState dfu_device_get_state (DfuDevice *device); -DfuStatus dfu_device_get_status (DfuDevice *device); -guint16 dfu_device_get_transfer_size (DfuDevice *device); -guint16 dfu_device_get_version (DfuDevice *device); -guint dfu_device_get_timeout (DfuDevice *device); -gboolean dfu_device_can_upload (DfuDevice *device); -gboolean dfu_device_can_download (DfuDevice *device); - -gboolean dfu_device_has_attribute (DfuDevice *device, - DfuDeviceAttributes attribute); -void dfu_device_remove_attribute (DfuDevice *device, - DfuDeviceAttributes attribute); - -void dfu_device_set_transfer_size (DfuDevice *device, - guint16 transfer_size); -void dfu_device_set_timeout (DfuDevice *device, - guint timeout_ms); -void dfu_device_error_fixup (DfuDevice *device, - GError **error); -guint dfu_device_get_download_timeout (DfuDevice *device); -gchar *dfu_device_get_attributes_as_string (DfuDevice *device); -gboolean dfu_device_ensure_interface (DfuDevice *device, - GError **error); diff -Nru fwupd-1.4.5/plugins/dfu/dfu-element.c fwupd-1.5.8/plugins/dfu/dfu-element.c --- fwupd-1.4.5/plugins/dfu/dfu-element.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/dfu-element.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,170 +0,0 @@ -/* - * Copyright (C) 2015 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -/** - * SECTION:dfu-element - * @short_description: Object representing a binary element - * - * This object represents an binary blob of data at a specific address. - * - * This allows relocatable data segments to be stored in different - * locations on the device itself. - * - * See also: #DfuImage, #DfuFirmware - */ - -#include "config.h" - -#include -#include - -#include "dfu-common.h" -#include "dfu-element.h" - -#include "fwupd-error.h" - -static void dfu_element_finalize (GObject *object); - -typedef struct { - GBytes *contents; - guint32 address; -} DfuElementPrivate; - -G_DEFINE_TYPE_WITH_PRIVATE (DfuElement, dfu_element, G_TYPE_OBJECT) -#define GET_PRIVATE(o) (dfu_element_get_instance_private (o)) - -static void -dfu_element_class_init (DfuElementClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - object_class->finalize = dfu_element_finalize; -} - -static void -dfu_element_init (DfuElement *element) -{ -} - -static void -dfu_element_finalize (GObject *object) -{ - DfuElement *element = DFU_ELEMENT (object); - DfuElementPrivate *priv = GET_PRIVATE (element); - - if (priv->contents != NULL) - g_bytes_unref (priv->contents); - - G_OBJECT_CLASS (dfu_element_parent_class)->finalize (object); -} - -/** - * dfu_element_new: - * - * Creates a new DFU element object. - * - * Return value: a new #DfuElement - **/ -DfuElement * -dfu_element_new (void) -{ - DfuElement *element; - element = g_object_new (DFU_TYPE_ELEMENT, NULL); - return element; -} - -/** - * dfu_element_get_contents: - * @element: a #DfuElement - * - * Gets the element data. - * - * Return value: (transfer none): element data - **/ -GBytes * -dfu_element_get_contents (DfuElement *element) -{ - DfuElementPrivate *priv = GET_PRIVATE (element); - g_return_val_if_fail (DFU_IS_ELEMENT (element), NULL); - return priv->contents; -} - -/** - * dfu_element_get_address: - * @element: a #DfuElement - * - * Gets the offset address of the element. - * - * Return value: memory offset value, or 0x00 for unset - **/ -guint32 -dfu_element_get_address (DfuElement *element) -{ - DfuElementPrivate *priv = GET_PRIVATE (element); - g_return_val_if_fail (DFU_IS_ELEMENT (element), 0x00); - return priv->address; -} - -/** - * dfu_element_set_contents: - * @element: a #DfuElement - * @contents: element data - * - * Sets the element data. - **/ -void -dfu_element_set_contents (DfuElement *element, GBytes *contents) -{ - DfuElementPrivate *priv = GET_PRIVATE (element); - g_return_if_fail (DFU_IS_ELEMENT (element)); - g_return_if_fail (contents != NULL); - if (priv->contents == contents) - return; - if (priv->contents != NULL) - g_bytes_unref (priv->contents); - priv->contents = g_bytes_ref (contents); -} - -/** - * dfu_element_set_address: - * @element: a #DfuElement - * @address: memory offset value - * - * Sets the offset address of the element. - **/ -void -dfu_element_set_address (DfuElement *element, guint32 address) -{ - DfuElementPrivate *priv = GET_PRIVATE (element); - g_return_if_fail (DFU_IS_ELEMENT (element)); - priv->address = address; -} - -/** - * dfu_element_to_string: - * @element: a #DfuElement - * - * Returns a string representation of the object. - * - * Return value: NULL terminated string, or %NULL for invalid - **/ -gchar * -dfu_element_to_string (DfuElement *element) -{ - DfuElementPrivate *priv = GET_PRIVATE (element); - GString *str; - - g_return_val_if_fail (DFU_IS_ELEMENT (element), NULL); - - str = g_string_new (""); - g_string_append_printf (str, "address: 0x%02x\n", priv->address); - if (priv->contents != NULL) { - g_string_append_printf (str, "contents: 0x%04x\n", - (guint32) g_bytes_get_size (priv->contents)); - } - - g_string_truncate (str, str->len - 1); - return g_string_free (str, FALSE); -} diff -Nru fwupd-1.4.5/plugins/dfu/dfu-element.h fwupd-1.5.8/plugins/dfu/dfu-element.h --- fwupd-1.4.5/plugins/dfu/dfu-element.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/dfu-element.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2015 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include -#include - -#define DFU_TYPE_ELEMENT (dfu_element_get_type ()) -G_DECLARE_DERIVABLE_TYPE (DfuElement, dfu_element, DFU, ELEMENT, GObject) - -struct _DfuElementClass -{ - GObjectClass parent_class; -}; - -DfuElement *dfu_element_new (void); - -GBytes *dfu_element_get_contents (DfuElement *element); -guint32 dfu_element_get_address (DfuElement *element); -void dfu_element_set_contents (DfuElement *element, - GBytes *contents); -void dfu_element_set_address (DfuElement *element, - guint32 address); -gchar *dfu_element_to_string (DfuElement *element); diff -Nru fwupd-1.4.5/plugins/dfu/dfu-firmware.c fwupd-1.5.8/plugins/dfu/dfu-firmware.c --- fwupd-1.4.5/plugins/dfu/dfu-firmware.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/dfu-firmware.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,352 +0,0 @@ -/* - * Copyright (C) 2015-2018 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -/** - * SECTION:dfu-firmware - * @short_description: Object representing a DFU or DfuSe firmware file - * - * This object allows reading and writing firmware files either in - * raw, DFU or DfuSe formats. - * - * A #DfuFirmware can be made up of several #DfuImages, although - * typically there is only one. - * - * See also: #DfuImage - */ - -#include "config.h" - -#include -#include - -#include "fu-common-version.h" -#include "fu-firmware.h" - -#include "dfu-common.h" -#include "dfu-firmware.h" -#include "dfu-format-dfu.h" -#include "dfu-format-raw.h" -#include "dfu-image.h" - -#include "fwupd-error.h" - -typedef struct { - DfuFirmwareFormat format; -} DfuFirmwarePrivate; - -G_DEFINE_TYPE_WITH_PRIVATE (DfuFirmware, dfu_firmware, FU_TYPE_DFU_FIRMWARE) -#define GET_PRIVATE(o) (dfu_firmware_get_instance_private (o)) - -static void -dfu_firmware_init (DfuFirmware *firmware) -{ -} - -static void -dfu_firmware_finalize (GObject *object) -{ - G_OBJECT_CLASS (dfu_firmware_parent_class)->finalize (object); -} - -/** - * dfu_firmware_new: - * - * Creates a new DFU firmware object. - * - * Return value: a new #DfuFirmware - **/ -DfuFirmware * -dfu_firmware_new (void) -{ - DfuFirmware *firmware; - firmware = g_object_new (DFU_TYPE_FIRMWARE, NULL); - return firmware; -} - -/** - * dfu_firmware_get_size: - * @firmware: a #DfuFirmware - * - * Gets the size of all the images in the firmware. - * - * This only returns actual data that would be sent to the device and - * does not include any padding. - * - * Return value: a integer value, or 0 if there are no images. - **/ -guint32 -dfu_firmware_get_size (DfuFirmware *firmware) -{ - guint32 length = 0; - g_autoptr(GPtrArray) images = fu_firmware_get_images (FU_FIRMWARE (firmware)); - g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), 0); - for (guint i = 0; i < images->len; i++) { - DfuImage *image = g_ptr_array_index (images, i); - length += dfu_image_get_size (image); - } - return length; -} - -/** - * dfu_firmware_get_format: - * @firmware: a #DfuFirmware - * - * Gets the DFU version. - * - * Return value: a version, or 0x0 for unset - **/ -guint16 -dfu_firmware_get_format (DfuFirmware *firmware) -{ - DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); - g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), 0xffff); - return priv->format; -} - -/** - * dfu_firmware_set_format: - * @firmware: a #DfuFirmware - * @format: a #DfuFirmwareFormat, e.g. %DFU_FIRMWARE_FORMAT_DFUSE - * - * Sets the DFU version in BCD format. - **/ -void -dfu_firmware_set_format (DfuFirmware *firmware, DfuFirmwareFormat format) -{ - DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); - g_return_if_fail (DFU_IS_FIRMWARE (firmware)); - priv->format = format; -} - -/** - * dfu_firmware_parse_data: - * @firmware: a #DfuFirmware - * @bytes: raw firmware data - * @flags: optional flags, e.g. %FWUPD_INSTALL_FLAG_FORCE - * @error: a #GError, or %NULL - * - * Parses firmware data which may have an optional DFU suffix. - * - * Return value: %TRUE for success - **/ -gboolean -dfu_firmware_parse_data (DfuFirmware *firmware, GBytes *bytes, - FwupdInstallFlags flags, GError **error) -{ - DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); - - g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), FALSE); - g_return_val_if_fail (bytes != NULL, FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* try to get format if not already set */ - if (priv->format == DFU_FIRMWARE_FORMAT_UNKNOWN) - priv->format = dfu_firmware_detect_dfu (bytes); - if (priv->format == DFU_FIRMWARE_FORMAT_UNKNOWN) - priv->format = DFU_FIRMWARE_FORMAT_RAW; - - /* handled easily */ - switch (priv->format) { - case DFU_FIRMWARE_FORMAT_DFU: - case DFU_FIRMWARE_FORMAT_DFUSE: - if (!dfu_firmware_from_dfu (firmware, bytes, flags, error)) - return FALSE; - break; - default: - if (!dfu_firmware_from_raw (firmware, bytes, flags, error)) - return FALSE; - break; - } - - return TRUE; -} - -/** - * dfu_firmware_parse_file: - * @firmware: a #DfuFirmware - * @file: a #GFile to load and parse - * @flags: optional flags, e.g. %FWUPD_INSTALL_FLAG_FORCE - * @error: a #GError, or %NULL - * - * Parses a DFU firmware, which may contain an optional footer. - * - * Return value: %TRUE for success - **/ -gboolean -dfu_firmware_parse_file (DfuFirmware *firmware, GFile *file, - FwupdInstallFlags flags, - GError **error) -{ - gchar *contents = NULL; - gsize length = 0; - g_autoptr(GBytes) bytes = NULL; - - g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), FALSE); - g_return_val_if_fail (G_IS_FILE (file), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - if (!g_file_load_contents (file, NULL, &contents, &length, NULL, error)) - return FALSE; - bytes = g_bytes_new_take (contents, length); - return dfu_firmware_parse_data (firmware, bytes, flags, error); -} - -static gboolean -dfu_firmware_check_acceptable_for_format (DfuFirmware *firmware, GError **error) -{ - DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); - g_autoptr(GPtrArray) images = fu_firmware_get_images (FU_FIRMWARE (firmware)); - - /* always okay */ - if (images->len <= 1) - return TRUE; - if (priv->format == DFU_FIRMWARE_FORMAT_DFUSE) - return TRUE; - - /* unsupported */ - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "multiple images (%u) not supported for %s", - images->len, - dfu_firmware_format_to_string (priv->format)); - return TRUE; -} - -/** - * dfu_firmware_write_data: - * @firmware: a #DfuFirmware - * @error: a #GError, or %NULL - * - * Writes DFU data to a data blob with a DFU-specific footer. - * - * Return value: (transfer none): firmware data - **/ -GBytes * -dfu_firmware_write_data (DfuFirmware *firmware, GError **error) -{ - DfuFirmwarePrivate *priv = GET_PRIVATE (firmware); - g_autoptr(GPtrArray) images = fu_firmware_get_images (FU_FIRMWARE (firmware)); - - g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - /* at least one image */ - if (images->len == 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "no image data to write"); - return NULL; - } - - /* does the format support this many images */ - if (!dfu_firmware_check_acceptable_for_format (firmware, error)) - return NULL; - - /* raw */ - if (priv->format == DFU_FIRMWARE_FORMAT_RAW) - return dfu_firmware_to_raw (firmware, error); - - /* DFU or DfuSe*/ - if (priv->format == DFU_FIRMWARE_FORMAT_DFU || - priv->format == DFU_FIRMWARE_FORMAT_DFUSE) - return dfu_firmware_to_dfu (firmware, error); - - /* invalid */ - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "invalid format for write (0x%04x)", - priv->format); - return NULL; -} - -/** - * dfu_firmware_write_file: - * @firmware: a #DfuFirmware - * @file: a #GFile - * @error: a #GError, or %NULL - * - * Writes a DFU firmware with the optional footer. - * - * Return value: %TRUE for success - **/ -gboolean -dfu_firmware_write_file (DfuFirmware *firmware, GFile *file, GError **error) -{ - const guint8 *data; - gsize length = 0; - g_autoptr(GBytes) bytes = NULL; - - g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), FALSE); - g_return_val_if_fail (G_IS_FILE (file), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* get blob */ - bytes = dfu_firmware_write_data (firmware, error); - if (bytes == NULL) - return FALSE; - - /* save to firmware */ - data = g_bytes_get_data (bytes, &length); - return g_file_replace_contents (file, - (const gchar *) data, - length, - NULL, - FALSE, - G_FILE_CREATE_NONE, - NULL, - NULL, /* cancellable */ - error); -} - -/** - * dfu_firmware_format_to_string: - * @format: a #DfuFirmwareFormat, e.g. %DFU_FIRMWARE_FORMAT_DFU - * - * Returns a string representation of the format. - * - * Return value: NULL terminated string, or %NULL for invalid - **/ -const gchar * -dfu_firmware_format_to_string (DfuFirmwareFormat format) -{ - if (format == DFU_FIRMWARE_FORMAT_RAW) - return "raw"; - if (format == DFU_FIRMWARE_FORMAT_DFU) - return "dfu"; - if (format == DFU_FIRMWARE_FORMAT_DFUSE) - return "dfuse"; - return NULL; -} - -/** - * dfu_firmware_format_from_string: - * @format: a format string, e.g. `dfuse` - * - * Returns an enumerated version of the format. - * - * Return value: a #DfuFirmwareFormat, e.g. %DFU_FIRMWARE_FORMAT_DFUSE - **/ -DfuFirmwareFormat -dfu_firmware_format_from_string (const gchar *format) -{ - if (g_strcmp0 (format, "raw") == 0) - return DFU_FIRMWARE_FORMAT_RAW; - if (g_strcmp0 (format, "dfu") == 0) - return DFU_FIRMWARE_FORMAT_DFU; - if (g_strcmp0 (format, "dfuse") == 0) - return DFU_FIRMWARE_FORMAT_DFUSE; - return DFU_FIRMWARE_FORMAT_UNKNOWN; -} - -static void -dfu_firmware_class_init (DfuFirmwareClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - object_class->finalize = dfu_firmware_finalize; -} diff -Nru fwupd-1.4.5/plugins/dfu/dfu-firmware.h fwupd-1.5.8/plugins/dfu/dfu-firmware.h --- fwupd-1.4.5/plugins/dfu/dfu-firmware.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/dfu-firmware.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2015-2018 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include -#include - -#include "fu-dfu-firmware.h" - -#include "dfu-common.h" -#include "dfu-image.h" - -#include "fwupd-enums.h" - -#define DFU_TYPE_FIRMWARE (dfu_firmware_get_type ()) -G_DECLARE_DERIVABLE_TYPE (DfuFirmware, dfu_firmware, DFU, FIRMWARE, FuDfuFirmware) - -struct _DfuFirmwareClass -{ - FuDfuFirmwareClass parent_class; -}; - -/** - * DfuFirmwareFormat: - * @DFU_FIRMWARE_FORMAT_UNKNOWN: Format unknown - * @DFU_FIRMWARE_FORMAT_RAW: Raw format - * @DFU_FIRMWARE_FORMAT_DFU: DFU footer - * @DFU_FIRMWARE_FORMAT_DFUSE: DfuSe header - * - * The known versions of the DFU standard in BCD format. - **/ -typedef enum { - DFU_FIRMWARE_FORMAT_UNKNOWN, - DFU_FIRMWARE_FORMAT_RAW, - DFU_FIRMWARE_FORMAT_DFU, - DFU_FIRMWARE_FORMAT_DFUSE, - /*< private >*/ - DFU_FIRMWARE_FORMAT_LAST -} DfuFirmwareFormat; - -DfuFirmware *dfu_firmware_new (void); - -const gchar *dfu_firmware_format_to_string (DfuFirmwareFormat format); -DfuFirmwareFormat dfu_firmware_format_from_string(const gchar *format); - -guint16 dfu_firmware_get_format (DfuFirmware *firmware); -guint32 dfu_firmware_get_size (DfuFirmware *firmware); - -void dfu_firmware_set_format (DfuFirmware *firmware, - DfuFirmwareFormat format); - -gboolean dfu_firmware_parse_data (DfuFirmware *firmware, - GBytes *bytes, - FwupdInstallFlags flags, - GError **error); -gboolean dfu_firmware_parse_file (DfuFirmware *firmware, - GFile *file, - FwupdInstallFlags flags, - GError **error); - -GBytes *dfu_firmware_write_data (DfuFirmware *firmware, - GError **error); -gboolean dfu_firmware_write_file (DfuFirmware *firmware, - GFile *file, - GError **error); diff -Nru fwupd-1.4.5/plugins/dfu/dfu-format-dfu.c fwupd-1.5.8/plugins/dfu/dfu-format-dfu.c --- fwupd-1.4.5/plugins/dfu/dfu-format-dfu.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/dfu-format-dfu.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,157 +0,0 @@ -/* - * Copyright (C) 2015-2016 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include - -#include "fu-dfu-firmware.h" - -#include "dfu-element.h" -#include "dfu-format-dfu.h" -#include "dfu-format-dfuse.h" -#include "dfu-format-raw.h" -#include "dfu-image.h" - -#include "fwupd-error.h" - -/** - * dfu_firmware_detect_dfu: (skip) - * @bytes: data to parse - * - * Attempts to sniff the data and work out the firmware format - * - * Returns: a #DfuFirmwareFormat, e.g. %DFU_FIRMWARE_FORMAT_RAW - **/ -DfuFirmwareFormat -dfu_firmware_detect_dfu (GBytes *bytes) -{ - g_autoptr(FuFirmware) firmware = fu_dfu_firmware_new (); - /* check versions */ - if (!fu_firmware_parse (firmware, bytes, FWUPD_INSTALL_FLAG_NONE, NULL)) - return DFU_FIRMWARE_FORMAT_UNKNOWN; - switch (fu_dfu_firmware_get_version (FU_DFU_FIRMWARE (firmware))) { - case DFU_VERSION_DFU_1_0: - case DFU_VERSION_DFU_1_1: - return DFU_FIRMWARE_FORMAT_DFU; - case DFU_VERSION_DFUSE: - return DFU_FIRMWARE_FORMAT_DFUSE; - default: - break; - } - return DFU_FIRMWARE_FORMAT_UNKNOWN; -} - -/** - * dfu_firmware_from_dfu: (skip) - * @firmware: a #DfuFirmware - * @bytes: data to parse - * @flags: some #FwupdInstallFlags - * @error: a #GError, or %NULL - * - * Unpacks into a firmware object from dfu data. - * - * Returns: %TRUE for success - **/ -gboolean -dfu_firmware_from_dfu (DfuFirmware *firmware, - GBytes *bytes, - FwupdInstallFlags flags, - GError **error) -{ - g_autoptr(FuFirmware) native = fu_dfu_firmware_new (); - g_autoptr(GBytes) contents = NULL; - if (!fu_firmware_parse (native, bytes, flags, error)) - return FALSE; - - fu_dfu_firmware_set_vid (FU_DFU_FIRMWARE (firmware), - fu_dfu_firmware_get_vid (FU_DFU_FIRMWARE (native))); - fu_dfu_firmware_set_pid (FU_DFU_FIRMWARE (firmware), - fu_dfu_firmware_get_pid (FU_DFU_FIRMWARE (native))); - fu_dfu_firmware_set_release (FU_DFU_FIRMWARE (firmware), - fu_dfu_firmware_get_release (FU_DFU_FIRMWARE (native))); - - /* parse DfuSe prefix */ - contents = fu_firmware_get_image_default_bytes (native, error); - if (contents == NULL) - return FALSE; - if (dfu_firmware_get_format (firmware) == DFU_FIRMWARE_FORMAT_DFUSE) - return dfu_firmware_from_dfuse (firmware, contents, flags, error); - - /* just copy old-plain DFU file */ - return dfu_firmware_from_raw (firmware, contents, flags, error); -} - -static DfuVersion -dfu_convert_version (DfuFirmwareFormat format) -{ - if (format == DFU_FIRMWARE_FORMAT_DFU) - return DFU_VERSION_DFU_1_0; - if (format == DFU_FIRMWARE_FORMAT_DFUSE) - return DFU_VERSION_DFUSE; - return DFU_VERSION_UNKNOWN; -} - -static GBytes * -dfu_firmware_add_footer (DfuFirmware *firmware, GBytes *contents, GError **error) -{ - g_autoptr(FuFirmware) native = fu_dfu_firmware_new (); - g_autoptr(FuFirmwareImage) image = fu_firmware_image_new (contents); - fu_dfu_firmware_set_vid (FU_DFU_FIRMWARE (native), - fu_dfu_firmware_get_vid (FU_DFU_FIRMWARE (firmware))); - fu_dfu_firmware_set_pid (FU_DFU_FIRMWARE (native), - fu_dfu_firmware_get_pid (FU_DFU_FIRMWARE (firmware))); - fu_dfu_firmware_set_release (FU_DFU_FIRMWARE (native), - fu_dfu_firmware_get_release (FU_DFU_FIRMWARE (firmware))); - fu_dfu_firmware_set_version (FU_DFU_FIRMWARE (native), - dfu_convert_version (dfu_firmware_get_format (firmware))); - fu_firmware_add_image (native, image); - return fu_firmware_write (native, error); -} -/** - * dfu_firmware_to_dfu: (skip) - * @firmware: a #DfuFirmware - * @error: a #GError, or %NULL - * - * Packs dfu firmware - * - * Returns: (transfer full): the packed data - **/ -GBytes * -dfu_firmware_to_dfu (DfuFirmware *firmware, GError **error) -{ - /* plain DFU */ - if (dfu_firmware_get_format (firmware) == DFU_FIRMWARE_FORMAT_DFU) { - GBytes *contents; - DfuElement *element; - g_autoptr(DfuImage) image = NULL; - image = DFU_IMAGE (fu_firmware_get_image_default (FU_FIRMWARE (firmware), error)); - if (image == NULL) - return NULL; - element = dfu_image_get_element (image, 0); - if (element == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "no firmware element data to write"); - return NULL; - } - contents = dfu_element_get_contents (element); - return dfu_firmware_add_footer (firmware, contents, error); - } - - /* DfuSe */ - if (dfu_firmware_get_format (firmware) == DFU_FIRMWARE_FORMAT_DFUSE) { - g_autoptr(GBytes) contents = NULL; - contents = dfu_firmware_to_dfuse (firmware, error); - if (contents == NULL) - return NULL; - return dfu_firmware_add_footer (firmware, contents, error); - } - - g_assert_not_reached (); - return NULL; -} diff -Nru fwupd-1.4.5/plugins/dfu/dfu-format-dfu.h fwupd-1.5.8/plugins/dfu/dfu-format-dfu.h --- fwupd-1.4.5/plugins/dfu/dfu-format-dfu.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/dfu-format-dfu.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2015-2016 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include -#include - -#include "dfu-firmware.h" - -DfuFirmwareFormat dfu_firmware_detect_dfu (GBytes *bytes); -GBytes *dfu_firmware_to_dfu (DfuFirmware *firmware, - GError **error); -gboolean dfu_firmware_from_dfu (DfuFirmware *firmware, - GBytes *bytes, - FwupdInstallFlags flags, - GError **error); diff -Nru fwupd-1.4.5/plugins/dfu/dfu-format-dfuse.c fwupd-1.5.8/plugins/dfu/dfu-format-dfuse.c --- fwupd-1.4.5/plugins/dfu/dfu-format-dfuse.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/dfu-format-dfuse.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,392 +0,0 @@ -/* - * Copyright (C) 2015-2016 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include - -#include "fu-common.h" - -#include "dfu-element.h" -#include "dfu-format-dfuse.h" -#include "dfu-image.h" - -#include "fwupd-error.h" - -/* DfuSe element header */ -typedef struct __attribute__((packed)) { - guint32 address; - guint32 size; -} DfuSeElementPrefix; - -/** - * dfu_element_from_dfuse: (skip) - * @data: data buffer - * @length: length of @data we can access - * @consumed: (out): the number of bytes we consued - * @error: a #GError, or %NULL - * - * Unpacks an element from DfuSe data. - * - * Returns: a #DfuElement, or %NULL for error - **/ -static DfuElement * -dfu_element_from_dfuse (const guint8 *data, - guint32 length, - guint32 *consumed, - GError **error) -{ - DfuElement *element = NULL; - DfuSeElementPrefix *el = (DfuSeElementPrefix *) data; - guint32 size; - g_autoptr(GBytes) contents = NULL; - - g_assert_cmpint(sizeof(DfuSeElementPrefix), ==, 8); - - /* check input buffer size */ - if (length < sizeof(DfuSeElementPrefix)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "invalid element data size %u", - (guint32) length); - return NULL; - } - - /* check size */ - size = GUINT32_FROM_LE (el->size); - if (size + sizeof(DfuSeElementPrefix) > length) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "invalid element size %u, only %u bytes left", - size, - (guint32) (length - sizeof(DfuSeElementPrefix))); - return NULL; - } - - /* create new element */ - element = dfu_element_new (); - dfu_element_set_address (element, GUINT32_FROM_LE (el->address)); - contents = g_bytes_new (data + sizeof(DfuSeElementPrefix), size); - dfu_element_set_contents (element, contents); - - /* return size */ - if (consumed != NULL) - *consumed = (guint32) sizeof(DfuSeElementPrefix) + size; - - return element; -} - -/** - * dfu_element_to_dfuse: (skip) - * @element: a #DfuElement - * - * Packs a DfuSe element. - * - * Returns: (transfer full): the packed data - **/ -static GBytes * -dfu_element_to_dfuse (DfuElement *element) -{ - DfuSeElementPrefix *el; - const guint8 *data; - gsize length; - guint8 *buf; - - data = g_bytes_get_data (dfu_element_get_contents (element), &length); - buf = g_malloc0 (length + sizeof (DfuSeElementPrefix)); - el = (DfuSeElementPrefix *) buf; - el->address = GUINT32_TO_LE (dfu_element_get_address (element)); - el->size = GUINT32_TO_LE (length); - - memcpy (buf + sizeof (DfuSeElementPrefix), data, length); - return g_bytes_new_take (buf, length + sizeof (DfuSeElementPrefix)); -} - -/* DfuSe image header */ -typedef struct __attribute__((packed)) { - guint8 sig[6]; - guint8 alt_setting; - guint32 target_named; - gchar target_name[255]; - guint32 target_size; - guint32 elements; -} DfuSeImagePrefix; - -/** - * dfu_image_from_dfuse: (skip) - * @data: data buffer - * @length: length of @data we can access - * @consumed: (out): the number of bytes we consued - * @error: a #GError, or %NULL - * - * Unpacks an image from DfuSe data. - * - * Returns: a #DfuImage, or %NULL for error - **/ -static DfuImage * -dfu_image_from_dfuse (const guint8 *data, - guint32 length, - guint32 *consumed, - GError **error) -{ - DfuSeImagePrefix *im; - guint32 elements; - guint32 offset = sizeof(DfuSeImagePrefix); - g_autoptr(DfuImage) image = NULL; - - g_assert_cmpint(sizeof(DfuSeImagePrefix), ==, 274); - - /* check input buffer size */ - if (length < sizeof(DfuSeImagePrefix)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "invalid image data size %u", - (guint32) length); - return NULL; - } - - /* verify image signature */ - im = (DfuSeImagePrefix *) data; - if (memcmp (im->sig, "Target", 6) != 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "invalid DfuSe target signature"); - return NULL; - } - - /* create new image */ - image = dfu_image_new (); - dfu_image_set_alt_setting (image, im->alt_setting); - if (GUINT32_FROM_LE (im->target_named) == 0x01) - dfu_image_set_name (image, im->target_name); - - /* parse elements */ - length -= offset; - elements = GUINT32_FROM_LE (im->elements); - for (guint j = 0; j < elements; j++) { - guint32 consumed_local; - g_autoptr(DfuElement) element = NULL; - element = dfu_element_from_dfuse (data + offset, length, - &consumed_local, error); - if (element == NULL) - return NULL; - dfu_image_add_element (image, element); - offset += consumed_local; - length -= consumed_local; - } - - /* return size */ - if (consumed != NULL) - *consumed = offset; - - return g_object_ref (image); -} - -/** - * dfu_image_to_dfuse: (skip) - * @image: a #DfuImage - * - * Packs a DfuSe image - * - * Returns: (transfer full): the packed data - **/ -static GBytes * -dfu_image_to_dfuse (DfuImage *image) -{ - DfuSeImagePrefix *im; - GPtrArray *elements; - guint32 length_total = 0; - guint32 offset = sizeof (DfuSeImagePrefix); - guint8 *buf; - g_autoptr(GPtrArray) element_array = NULL; - - /* get total size */ - element_array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref); - elements = dfu_image_get_elements (image); - for (guint i = 0; i < elements->len; i++) { - DfuElement *element = g_ptr_array_index (elements, i); - GBytes *bytes = dfu_element_to_dfuse (element); - g_ptr_array_add (element_array, bytes); - length_total += (guint32) g_bytes_get_size (bytes); - } - - /* add prefix */ - buf = g_malloc0 (length_total + sizeof (DfuSeImagePrefix)); - im = (DfuSeImagePrefix *) buf; - memcpy (im->sig, "Target", 6); - im->alt_setting = dfu_image_get_alt_setting (image); - if (dfu_image_get_name (image) != NULL) { - im->target_named = GUINT32_TO_LE (0x01); - memcpy (im->target_name, dfu_image_get_name (image), 255); - } - im->target_size = GUINT32_TO_LE (length_total); - im->elements = GUINT32_TO_LE (elements->len); - - /* copy data */ - for (guint i = 0; i < element_array->len; i++) { - gsize length; - GBytes *bytes = g_ptr_array_index (element_array, i); - const guint8 *data = g_bytes_get_data (bytes, &length); - g_autoptr(GError) error = NULL; - if (!fu_memcpy_safe (buf, length_total + sizeof (DfuSeImagePrefix), offset, /* dst */ - data, length, 0x0, /* src */ - length, &error)) { - g_critical ("failed to pack buffer: %s", error->message); - continue; - } - offset += (guint32) length; - } - return g_bytes_new_take (buf, length_total + sizeof (DfuSeImagePrefix)); -} - -/* DfuSe header */ -typedef struct __attribute__((packed)) { - guint8 sig[5]; - guint8 ver; - guint32 image_size; - guint8 targets; -} DfuSePrefix; - -/** - * dfu_firmware_to_dfuse: (skip) - * @firmware: a #DfuFirmware - * @error: a #GError, or %NULL - * - * Packs a DfuSe firmware - * - * Returns: (transfer full): the packed data - **/ -GBytes * -dfu_firmware_to_dfuse (DfuFirmware *firmware, GError **error) -{ - DfuSePrefix *prefix; - guint32 image_size_total = 0; - guint32 offset = sizeof (DfuSePrefix); - g_autofree guint8 *buf = NULL; - g_autoptr(GPtrArray) dfuse_images = NULL; - g_autoptr(GPtrArray) images = NULL; - - /* get all the image data */ - dfuse_images = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref); - images = fu_firmware_get_images (FU_FIRMWARE (firmware)); - for (guint i = 0; i < images->len; i++) { - DfuImage *im = g_ptr_array_index (images, i); - GBytes *contents; - contents = dfu_image_to_dfuse (im); - image_size_total += (guint32) g_bytes_get_size (contents); - g_ptr_array_add (dfuse_images, contents); - } - g_debug ("image_size_total: %" G_GUINT32_FORMAT, image_size_total); - - buf = g_malloc0 (sizeof (DfuSePrefix) + image_size_total); - - /* DfuSe header */ - prefix = (DfuSePrefix *) buf; - memcpy (prefix->sig, "DfuSe", 5); - prefix->ver = 0x01; - prefix->image_size = GUINT32_TO_LE (offset + image_size_total); - if (images->len > G_MAXUINT8) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "too many (%u) images to write DfuSe file", - images->len); - return NULL; - } - prefix->targets = (guint8) images->len; - - /* copy images */ - for (guint i = 0; i < dfuse_images->len; i++) { - GBytes *contents = g_ptr_array_index (dfuse_images, i); - gsize length; - const guint8 *data; - data = g_bytes_get_data (contents, &length); - if (!fu_memcpy_safe (buf, sizeof (DfuSePrefix) + image_size_total, offset, /* dst */ - data, length, 0x0, /* src */ - length, error)) - return NULL; - offset += (guint32) length; - } - - /* return blob */ - return g_bytes_new (buf, sizeof (DfuSePrefix) + image_size_total); -} - -/** - * dfu_firmware_from_dfuse: (skip) - * @firmware: a #DfuFirmware - * @bytes: data to parse - * @flags: some #FwupdInstallFlags - * @error: a #GError, or %NULL - * - * Unpacks into a firmware object from DfuSe data. - * - * Returns: %TRUE for success - **/ -gboolean -dfu_firmware_from_dfuse (DfuFirmware *firmware, - GBytes *bytes, - FwupdInstallFlags flags, - GError **error) -{ - DfuSePrefix *prefix; - gsize len; - guint32 offset = sizeof(DfuSePrefix); - guint8 *data; - - /* check the prefix (BE) */ - data = (guint8 *) g_bytes_get_data (bytes, &len); - prefix = (DfuSePrefix *) data; - if (memcmp (prefix->sig, "DfuSe", 5) != 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "invalid DfuSe prefix"); - return FALSE; - } - - /* check the version */ - if (prefix->ver != 0x01) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "invalid DfuSe version, got %02x", - prefix->ver); - return FALSE; - } - - /* check image size */ - if (GUINT32_FROM_LE (prefix->image_size) != len) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "invalid DfuSe image size, " - "got %" G_GUINT32_FORMAT ", " - "expected %" G_GSIZE_FORMAT, - GUINT32_FROM_LE (prefix->image_size), - len); - return FALSE; - } - - /* parse the image targets */ - len -= sizeof(DfuSePrefix); - for (guint i = 0; i < prefix->targets; i++) { - guint consumed; - g_autoptr(DfuImage) image = NULL; - image = dfu_image_from_dfuse (data + offset, (guint32) len, - &consumed, error); - if (image == NULL) - return FALSE; - fu_firmware_add_image (FU_FIRMWARE (firmware), FU_FIRMWARE_IMAGE (image)); - offset += consumed; - len -= consumed; - } - return TRUE; -} diff -Nru fwupd-1.4.5/plugins/dfu/dfu-format-dfuse.h fwupd-1.5.8/plugins/dfu/dfu-format-dfuse.h --- fwupd-1.4.5/plugins/dfu/dfu-format-dfuse.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/dfu-format-dfuse.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2015-2016 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include -#include - -#include "dfu-firmware.h" - -DfuFirmwareFormat dfu_firmware_detect_dfuse (GBytes *bytes); -GBytes *dfu_firmware_to_dfuse (DfuFirmware *firmware, - GError **error); -gboolean dfu_firmware_from_dfuse (DfuFirmware *firmware, - GBytes *bytes, - FwupdInstallFlags flags, - GError **error); diff -Nru fwupd-1.4.5/plugins/dfu/dfu-format-raw.c fwupd-1.5.8/plugins/dfu/dfu-format-raw.c --- fwupd-1.4.5/plugins/dfu/dfu-format-raw.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/dfu-format-raw.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2015-2016 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include - -#include "dfu-element.h" -#include "dfu-format-raw.h" -#include "dfu-image.h" - -#include "fwupd-error.h" - -/** - * dfu_firmware_from_raw: (skip) - * @firmware: a #DfuFirmware - * @bytes: data to parse - * @flags: some #FwupdInstallFlags - * @error: a #GError, or %NULL - * - * Unpacks into a firmware object from raw data. - * - * Returns: %TRUE for success - **/ -gboolean -dfu_firmware_from_raw (DfuFirmware *firmware, - GBytes *bytes, - FwupdInstallFlags flags, - GError **error) -{ - g_autoptr(DfuElement) element = NULL; - g_autoptr(DfuImage) image = NULL; - image = dfu_image_new (); - element = dfu_element_new (); - dfu_element_set_contents (element, bytes); - dfu_image_add_element (image, element); - fu_firmware_add_image (FU_FIRMWARE (firmware), FU_FIRMWARE_IMAGE (image)); - return TRUE; -} - -/** - * dfu_firmware_to_raw: (skip) - * @firmware: a #DfuFirmware - * @error: a #GError, or %NULL - * - * Packs raw firmware - * - * Returns: (transfer full): the packed data - **/ -GBytes * -dfu_firmware_to_raw (DfuFirmware *firmware, GError **error) -{ - DfuElement *element; - DfuImage *image; - GBytes *contents; - - image = DFU_IMAGE (fu_firmware_get_image_default (FU_FIRMWARE (firmware), error)); - if (image == NULL) - return NULL; - element = dfu_image_get_element (image, 0); - if (element == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "no firmware element data to write"); - return NULL; - } - contents = dfu_element_get_contents (element); - return g_bytes_ref (contents); -} diff -Nru fwupd-1.4.5/plugins/dfu/dfu-format-raw.h fwupd-1.5.8/plugins/dfu/dfu-format-raw.h --- fwupd-1.4.5/plugins/dfu/dfu-format-raw.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/dfu-format-raw.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2015-2016 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include -#include - -#include "dfu-firmware.h" - -GBytes *dfu_firmware_to_raw (DfuFirmware *firmware, - GError **error); -gboolean dfu_firmware_from_raw (DfuFirmware *firmware, - GBytes *bytes, - FwupdInstallFlags flags, - GError **error); diff -Nru fwupd-1.4.5/plugins/dfu/dfu-image.c fwupd-1.5.8/plugins/dfu/dfu-image.c --- fwupd-1.4.5/plugins/dfu/dfu-image.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/dfu-image.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,261 +0,0 @@ -/* - * Copyright (C) 2015 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -/** - * SECTION:dfu-image - * @short_description: Object representing a a firmware image - * - * A #DfuImage is typically made up of several #DfuElements, although - * typically there will only be one. - * - * See also: #DfuElement - */ - -#include "config.h" - -#include -#include - -#include "fu-common.h" - -#include "dfu-common.h" -#include "dfu-element.h" -#include "dfu-image.h" - -static void dfu_image_finalize (GObject *object); - -typedef struct { - GPtrArray *elements; - gchar name[255]; -} DfuImagePrivate; - -G_DEFINE_TYPE_WITH_PRIVATE (DfuImage, dfu_image, FU_TYPE_FIRMWARE_IMAGE) -#define GET_PRIVATE(o) (dfu_image_get_instance_private (o)) - -static void -dfu_image_init (DfuImage *image) -{ - DfuImagePrivate *priv = GET_PRIVATE (image); - priv->elements = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - memset (priv->name, 0x00, 255); -} - -static void -dfu_image_finalize (GObject *object) -{ - DfuImage *image = DFU_IMAGE (object); - DfuImagePrivate *priv = GET_PRIVATE (image); - - g_ptr_array_unref (priv->elements); - - G_OBJECT_CLASS (dfu_image_parent_class)->finalize (object); -} - -/** - * dfu_image_new: - * - * Creates a new DFU image object. - * - * Return value: a new #DfuImage - **/ -DfuImage * -dfu_image_new (void) -{ - DfuImage *image; - image = g_object_new (DFU_TYPE_IMAGE, NULL); - return image; -} - -/** - * dfu_image_get_elements: - * @image: a #DfuImage - * - * Gets the element data. - * - * Return value: (transfer none) (element-type DfuElement): element data - **/ -GPtrArray * -dfu_image_get_elements (DfuImage *image) -{ - DfuImagePrivate *priv = GET_PRIVATE (image); - g_return_val_if_fail (DFU_IS_IMAGE (image), NULL); - return priv->elements; -} - -/** - * dfu_image_get_element: - * @image: a #DfuImage - * @idx: an array index - * - * Gets the element. - * - * Return value: (transfer none): element data, or %NULL for invalid - **/ -DfuElement * -dfu_image_get_element (DfuImage *image, guint8 idx) -{ - DfuImagePrivate *priv = GET_PRIVATE (image); - g_return_val_if_fail (DFU_IS_IMAGE (image), NULL); - if (idx >= priv->elements->len) - return NULL; - return g_ptr_array_index (priv->elements, idx); -} - -/** - * dfu_image_get_element_default: - * @image: a #DfuImage - * - * Gets the default element. - * - * Return value: (transfer none): element data, or %NULL for invalid - **/ -DfuElement * -dfu_image_get_element_default (DfuImage *image) -{ - DfuImagePrivate *priv = GET_PRIVATE (image); - g_return_val_if_fail (DFU_IS_IMAGE (image), NULL); - if (priv->elements->len == 0) - return NULL; - return g_ptr_array_index (priv->elements, 0); -} - -/** - * dfu_image_get_alt_setting: - * @image: a #DfuImage - * - * Gets the alternate setting. - * - * Return value: integer, or 0x00 for unset - **/ -guint8 -dfu_image_get_alt_setting (DfuImage *image) -{ - g_return_val_if_fail (DFU_IS_IMAGE (image), 0xff); - return fu_firmware_image_get_idx (FU_FIRMWARE_IMAGE (image)); -} - -/** - * dfu_image_get_name: - * @image: a #DfuImage - * - * Gets the target name. - * - * Return value: a string, or %NULL for unset - **/ -const gchar * -dfu_image_get_name (DfuImage *image) -{ - DfuImagePrivate *priv = GET_PRIVATE (image); - g_return_val_if_fail (DFU_IS_IMAGE (image), NULL); - return priv->name; -} - -/** - * dfu_image_get_size: - * @image: a #DfuImage - * - * Gets the size of all the elements in the image. - * - * This only returns actual data that would be sent to the device and - * does not include any padding. - * - * Return value: a integer value, or 0 if there are no elements. - **/ -guint32 -dfu_image_get_size (DfuImage *image) -{ - DfuImagePrivate *priv = GET_PRIVATE (image); - guint32 length = 0; - g_return_val_if_fail (DFU_IS_IMAGE (image), 0); - for (guint i = 0; i < priv->elements->len; i++) { - DfuElement *element = g_ptr_array_index (priv->elements, i); - length += (guint32) g_bytes_get_size (dfu_element_get_contents (element)); - } - return length; -} - -/** - * dfu_image_add_element: - * @image: a #DfuImage - * @element: a #DfuElement - * - * Adds an element to the image. - **/ -void -dfu_image_add_element (DfuImage *image, DfuElement *element) -{ - DfuImagePrivate *priv = GET_PRIVATE (image); - g_return_if_fail (DFU_IS_IMAGE (image)); - g_return_if_fail (DFU_IS_ELEMENT (element)); - g_ptr_array_add (priv->elements, g_object_ref (element)); -} - -/** - * dfu_image_set_alt_setting: - * @image: a #DfuImage - * @alt_setting: vendor ID, or 0xffff for unset - * - * Sets the vendor ID. - **/ -void -dfu_image_set_alt_setting (DfuImage *image, guint8 alt_setting) -{ - fu_firmware_image_set_idx (FU_FIRMWARE_IMAGE (image), alt_setting); -} - -/** - * dfu_image_set_name: - * @image: a #DfuImage - * @name: a target string, or %NULL - * - * Sets the target name. - **/ -void -dfu_image_set_name (DfuImage *image, const gchar *name) -{ - guint16 sz; - DfuImagePrivate *priv = GET_PRIVATE (image); - g_return_if_fail (DFU_IS_IMAGE (image)); - - /* this is a hard limit in DfuSe */ - memset (priv->name, 0x00, 0xff); - if (name != NULL) { - sz = MIN ((guint16) strlen (name), 0xff - 1); - memcpy (priv->name, name, sz); - } - - /* copy junk data in self tests for 1:1 copies */ - if (name != NULL && G_UNLIKELY (g_getenv ("DFU_SELF_TEST_IMAGE_MEMCPY_NAME") != NULL)) - memcpy (priv->name, name, 0xff); -} - -static void -dfu_image_to_string (FuFirmwareImage *self, guint idt, GString *str) -{ - DfuImage *image = DFU_IMAGE (self); - DfuImagePrivate *priv = GET_PRIVATE (image); - if (priv->name[0] != '\0') - fu_common_string_append_kv (str, idt, "Name", priv->name); - fu_common_string_append_ku (str, idt, "Elements", priv->elements->len); - - /* add elements */ - for (guint i = 0; i < priv->elements->len; i++) { - DfuElement *element = g_ptr_array_index (priv->elements, i); - g_autofree gchar *tmp = NULL; - tmp = dfu_element_to_string (element); - g_string_append_printf (str, "== ELEMENT %u ==\n", i); - g_string_append_printf (str, "%s\n", tmp); - } -} - -static void -dfu_image_class_init (DfuImageClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - FuFirmwareImageClass *firmware_image_class = FU_FIRMWARE_IMAGE_CLASS (klass); - object_class->finalize = dfu_image_finalize; - firmware_image_class->to_string = dfu_image_to_string; -} diff -Nru fwupd-1.4.5/plugins/dfu/dfu-image.h fwupd-1.5.8/plugins/dfu/dfu-image.h --- fwupd-1.4.5/plugins/dfu/dfu-image.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/dfu-image.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2015 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include -#include - -#include "fu-firmware-image.h" - -#include "dfu-element.h" - -#define DFU_TYPE_IMAGE (dfu_image_get_type ()) -G_DECLARE_DERIVABLE_TYPE (DfuImage, dfu_image, DFU, IMAGE, FuFirmwareImage) - -struct _DfuImageClass -{ - FuFirmwareImageClass parent_class; -}; - -DfuImage *dfu_image_new (void); - -GPtrArray *dfu_image_get_elements (DfuImage *image); -DfuElement *dfu_image_get_element (DfuImage *image, - guint8 idx); -DfuElement *dfu_image_get_element_default (DfuImage *image); -guint8 dfu_image_get_alt_setting (DfuImage *image); -const gchar *dfu_image_get_name (DfuImage *image); -guint32 dfu_image_get_size (DfuImage *image); - -void dfu_image_add_element (DfuImage *image, - DfuElement *element); - -void dfu_image_set_alt_setting (DfuImage *image, - guint8 alt_setting); -void dfu_image_set_name (DfuImage *image, - const gchar *name); diff -Nru fwupd-1.4.5/plugins/dfu/dfu.quirk fwupd-1.5.8/plugins/dfu/dfu.quirk --- fwupd-1.4.5/plugins/dfu/dfu.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/dfu.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,331 +1,386 @@ # All DFU devices -[DeviceInstanceId=USB\CLASS_FE&SUBCLASS_01] +[USB\CLASS_FE&SUBCLASS_01] Plugin = dfu +# GD32VF103 Rev1 +[USB\VID_28E9&PID_0189] +Flags = gd32,force-dfu-mode +Vendor = GDMicroelectronics + # Realtek USB camera -[DeviceInstanceId=USB\VID_0BDA&PID_5850] +[USB\VID_0BDA&PID_5850] CounterpartGuid = USB\VID_0BDA&PID_5800 -[DeviceInstanceId=USB\VID_0BDA&PID_5855] +[USB\VID_0BDA&PID_5855] CounterpartGuid = USB\VID_0BDA&PID_5800 -[DeviceInstanceId=USB\VID_0BDA&PID_58FE] +[USB\VID_0BDA&PID_58FE] CounterpartGuid = USB\VID_0BDA&PID_5800 -[DeviceInstanceId=USB\VID_0BDA&PID_5800] +[USB\VID_0BDA&PID_5800] Flags = detach-for-attach # Openmoko Freerunner / GTA02 -[DeviceInstanceId=USB\VID_1D50&PID_5119] +[USB\VID_1D50&PID_5119] Plugin = dfu -Flags = ignore-polltimeout,no-pid-change,no-dfu-runtime,needs-bootloader,no-get-status-upload +Flags = ignore-polltimeout,no-pid-change,no-fu-dfu-runtime,needs-bootloader,no-get-status-upload # OpenPCD Reader -[DeviceInstanceId=USB\VID_16C0&PID_076B] +[USB\VID_16C0&PID_076B] Plugin = dfu Flags = ignore-polltimeout # SIMtrace -[DeviceInstanceId=USB\VID_16C0&PID_0762] +[USB\VID_16C0&PID_0762] Plugin = dfu Flags = ignore-polltimeout # OpenPICC -[DeviceInstanceId=USB\VID_16C0&PID_076C] +[USB\VID_16C0&PID_076C] Plugin = dfu Flags = ignore-polltimeout # Siemens AG, PXM 40 & PXM 50 -[DeviceInstanceId=USB\VID_0908&PID_02C4] +[USB\VID_0908&PID_02C4] Plugin = dfu -[DeviceInstanceId=USB\VID_0908&PID_02C5] +[USB\VID_0908&PID_02C5] Plugin = dfu -[DeviceInstanceId=USB\VID_0908&PID_02C4&REV_0000] +[USB\VID_0908&PID_02C4&REV_0000] Flags = ignore-polltimeout -[DeviceInstanceId=USB\VID_0908&PID_02C5&REV_0000] +[USB\VID_0908&PID_02C5&REV_0000] Flags = ignore-polltimeout # Midiman M-Audio Transit -[DeviceInstanceId=USB\VID_0763&PID_2806] +[USB\VID_0763&PID_2806] Plugin = dfu Flags = ignore-polltimeout # LPC DFU bootloader -[DeviceInstanceId=USB\VID_1FC9&PID_000C] +[USB\VID_1FC9&PID_000C] Plugin = dfu Flags = force-dfu-mode # m-stack DFU -[DeviceInstanceId=USB\VID_273F&PID_1003] +[USB\VID_273F&PID_1003] Flags = attach-upload-download -[DeviceInstanceId=USB\VID_273F&PID_100A] +[USB\VID_273F&PID_100A] Flags = attach-upload-download -[DeviceInstanceId=USB\VID_273F&PID_1008] +[USB\VID_273F&PID_1008] Flags = attach-upload-download # HydraBus -[DeviceInstanceId=USB\VID_1D50&PID_60A7] +[USB\VID_1D50&PID_60A7] Plugin = dfu -Flags = no-dfu-runtime,needs-bootloader +Flags = no-fu-dfu-runtime,needs-bootloader # Jabra 410 [appIDLE & dfuIDLE] -[DeviceInstanceId=USB\VID_0B0E&PID_0411] +[USB\VID_0B0E&PID_0411] Plugin = dfu Flags = no-pid-change,ignore-upload,attach-extra-reset # Jabra 510 [appIDLE & dfuIDLE] -[DeviceInstanceId=USB\VID_0B0E&PID_0421] +[USB\VID_0B0E&PID_0421] Plugin = dfu Flags = no-pid-change,ignore-upload,attach-extra-reset # Jabra 710 [appIDLE & dfuIDLE] -[DeviceInstanceId=USB\VID_0B0E&PID_0982] +[USB\VID_0B0E&PID_0982] Plugin = dfu Flags = no-pid-change,ignore-upload,attach-extra-reset # Jabra 810 [appIDLE & dfuIDLE] -[DeviceInstanceId=USB\VID_0B0E&PID_0971] +[USB\VID_0B0E&PID_0971] Plugin = dfu Flags = no-pid-change,ignore-upload,attach-extra-reset # Atmel AT90USB Bootloader -[DeviceInstanceId=USB\VID_03EB&PID_2FF7] +[USB\VID_03EB&PID_2FF7] Plugin = dfu Flags = use-any-interface,legacy-protocol,force-dfu-mode -[DeviceInstanceId=USB\VID_03EB&PID_2FF9] +[USB\VID_03EB&PID_2FF9] Plugin = dfu Flags = use-any-interface,legacy-protocol,force-dfu-mode -[DeviceInstanceId=USB\VID_03EB&PID_2FFA] +[USB\VID_03EB&PID_2FFA] Plugin = dfu Flags = use-any-interface,legacy-protocol,force-dfu-mode -[DeviceInstanceId=USB\VID_03EB&PID_2FFB] +[USB\VID_03EB&PID_2FFB] Plugin = dfu Flags = use-any-interface,legacy-protocol,force-dfu-mode # Atmel ATMEGA Bootloader -[DeviceInstanceId=USB\VID_03EB&PID_2FEE] +[USB\VID_03EB&PID_2FEE] Plugin = dfu Flags = use-any-interface,legacy-protocol,force-dfu-mode -[DeviceInstanceId=USB\VID_03EB&PID_2FEF] +[USB\VID_03EB&PID_2FEF] Plugin = dfu Flags = use-any-interface,legacy-protocol,force-dfu-mode -[DeviceInstanceId=USB\VID_03EB&PID_2FF0] +[USB\VID_03EB&PID_2FF0] Plugin = dfu Flags = use-any-interface,legacy-protocol,force-dfu-mode -[DeviceInstanceId=USB\VID_03EB&PID_2FF2] +[USB\VID_03EB&PID_2FF2] Plugin = dfu Flags = use-any-interface,legacy-protocol,force-dfu-mode -[DeviceInstanceId=USB\VID_03EB&PID_2FF3] +[USB\VID_03EB&PID_2FF3] Plugin = dfu Flags = use-any-interface,legacy-protocol,force-dfu-mode -[DeviceInstanceId=USB\VID_03EB&PID_2FF4] +[USB\VID_03EB&PID_2FF4] Plugin = dfu Flags = use-any-interface,legacy-protocol,force-dfu-mode # Atmel XMEGA Bootloader -[DeviceInstanceId=USB\VID_03EB&PID_2FE2] +[USB\VID_03EB&PID_2FE2] Plugin = dfu Flags = use-any-interface,force-dfu-mode # Leaflabs Maple3 -[DeviceInstanceId=USB\VID_1EAF&PID_0003&REV_0200] +[USB\VID_1EAF&PID_0003&REV_0200] Plugin = dfu DfuForceVersion = 0110 # Atmel FLIP Bootloader -[DeviceInstanceId=USB\VID_03EB] +[USB\VID_03EB] Plugin = dfu DfuForceVersion = ff01 # AT32UC3B1256 [BLDR][USER] USER@0x2000, BLDR+USER=0x40000 -[AvrChipId=0x58200203] +[DFU_AVR\CID_0x58200203] DfuAltName = @Flash/0x2000/1*248Kg # AT32UC3A3256 [BLDR][USER] USER@0x2000, BLDR+USER=0x40000 -[AvrChipId=0x58200204] +[DFU_AVR\CID_0x58200204] DfuAltName = @Flash/0x2000/1*248Kg # AT90USB1287 [USER][BLDR] BLDR@0x1e000, BLDR+USER=0x20000 -[AvrChipId=0x581e9782] +[DFU_AVR\CID_0x581e9782] DfuAltName = @Flash/0x0/1*120Kg # AT90USB647 [USER][BLDR] BLDR@0x0e000, BLDR+USER=0x10000 # AT90USB646 [USER][BLDR] BLDR@0x0e000, BLDR+USER=0x10000 -[AvrChipId=0x581e9682] +[DFU_AVR\CID_0x581e9682] DfuAltName = @Flash/0x0/1*56Kg # ATmega32U4 [USER][BLDR] BLDR@0x07000, BLDR+USER=0x08000 -[AvrChipId=0x581e9587] +[DFU_AVR\CID_0x581e9587] DfuAltName = @Flash/0x0/1*28Kg # ATmega16U4 [USER][BLDR] BLDR@0x03000, BLDR+USER=0x04000 -[AvrChipId=0x581e9488] +[DFU_AVR\CID_0x581e9488] DfuAltName = @Flash/0x0/1*12Kg # ATmega32U2 [USER][BLDR] BLDR@0x07000, BLDR+USER=0x08000 -[AvrChipId=0x581e958a] +[DFU_AVR\CID_0x581e958a] DfuAltName = @Flash/0x0/1*28Kg # ATmega16U2 [USER][BLDR] BLDR@0x03000, BLDR+USER=0x04000 -[AvrChipId=0x581e9489] +[DFU_AVR\CID_0x581e9489] DfuAltName = @Flash/0x0/1*12Kg # AT90USB162 [USER][BLDR] BLDR@0x03000, BLDR+USER=0x04000 -[AvrChipId=0x581e9482] +[DFU_AVR\CID_0x581e9482] DfuAltName = @Flash/0x0/1*12Kg # ATmega8U2 [USER][BLDR] BLDR@0x01000, BLDR+USER=0x02000 -[AvrChipId=0x581e9389] +[DFU_AVR\CID_0x581e9389] DfuAltName = @Flash/0x0/1*4Kg # AT90USB82 [USER][BLDR] BLDR@0x01000, BLDR+USER=0x02000 -[AvrChipId=0x581e9382] +[DFU_AVR\CID_0x581e9382] DfuAltName = @Flash/0x0/1*4Kg # ATxmega16A4 [USER] USER=0x4000 -[AvrChipId=0x1e9441] +[DFU_AVR\CID_0x1e9441] DfuAltName = @Flash/0x0/1*16Kg # ATxmega16C4 [USER] USER=0x4000 -[AvrChipId=0x1e9544] +[DFU_AVR\CID_0x1e9544] DfuAltName = @Flash/0x0/1*16Kg # ATxmega16D4 [USER] USER=0x4000 -[AvrChipId=0x1e9442] +[DFU_AVR\CID_0x1e9442] DfuAltName = @Flash/0x0/1*16Kg # ATxmega32A4 [USER] USER=0x8000 -[AvrChipId=0x1e9541] +[DFU_AVR\CID_0x1e9541] DfuAltName = @Flash/0x0/1*32Kg # ATxmega32C4 [USER] USER=0x8000 -[AvrChipId=0x1e9443] +[DFU_AVR\CID_0x1e9443] DfuAltName = @Flash/0x0/1*32Kg # ATxmega32D4 [USER] USER=0x8000 -[AvrChipId=0x1e9542] +[DFU_AVR\CID_0x1e9542] DfuAltName = @Flash/0x0/1*32Kg # ATxmega64A4 [USER] USER=0x10000 -[AvrChipId=0x1e9646] +[DFU_AVR\CID_0x1e9646] DfuAltName = @Flash/0x0/1*64Kg # ATxmega64C3 [USER] USER=0x10000 -[AvrChipId=0x1e9649] +[DFU_AVR\CID_0x1e9649] DfuAltName = @Flash/0x0/1*64Kg # ATxmega64D3 [USER] USER=0x10000 -[AvrChipId=0x1e964a] +[DFU_AVR\CID_0x1e964a] DfuAltName = @Flash/0x0/1*64Kg # ATxmega64D4 [USER] USER=0x10000 -[AvrChipId=0x1e9647] +[DFU_AVR\CID_0x1e9647] DfuAltName = @Flash/0x0/1*64Kg # ATxmega64A1 [USER] USER=0x10000 -[AvrChipId=0x1e964e] +[DFU_AVR\CID_0x1e964e] DfuAltName = @Flash/0x0/1*64Kg # ATxmega64A3 [USER] USER=0x10000 -[AvrChipId=0x1e9642] +[DFU_AVR\CID_0x1e9642] DfuAltName = @Flash/0x0/1*64Kg # ATxmega64B1 [USER] USER=0x10000 -[AvrChipId=0x1e9652] +[DFU_AVR\CID_0x1e9652] DfuAltName = @Flash/0x0/1*64Kg # ATxmega64B3 [USER] USER=0x10000 -[AvrChipId=0x1e9651] +[DFU_AVR\CID_0x1e9651] DfuAltName = @Flash/0x0/1*64Kg # ATxmega128C3 [USER] USER=0x20000 -[AvrChipId=0x1e9752] +[DFU_AVR\CID_0x1e9752] DfuAltName = @Flash/0x0/1*128Kg # ATxmega128D3 [USER] USER=0x20000 -[AvrChipId=0x1e9748] +[DFU_AVR\CID_0x1e9748] DfuAltName = @Flash/0x0/1*128Kg # ATxmega128D4 [USER] USER=0x20000 - [AvrChipId=0x1e9747] + [DFU_AVR\CID_0x1e9747] DfuAltName = @Flash/0x0/1*128Kg # ATxmega128A1 [USER] USER=0x20000 -[AvrChipId=0x1e974c] +[DFU_AVR\CID_0x1e974c] DfuAltName = @Flash/0x0/1*128Kg # ATxmega128A1D [USER] USER=0x20000 -[AvrChipId=0x1e9741] +[DFU_AVR\CID_0x1e9741] DfuAltName = @Flash/0x0/1*128Kg # ATxmega128A3 [USER] USER=0x20000 -[AvrChipId=0x1e9742] +[DFU_AVR\CID_0x1e9742] DfuAltName = @Flash/0x0/1*128Kg # ATxmega128A4 [USER] USER=0x20000 -[AvrChipId=0x1e9746] +[DFU_AVR\CID_0x1e9746] DfuAltName = @Flash/0x0/1*128Kg # ATxmega128B1 [USER] USER=0x20000 -[AvrChipId=0x1e974d] +[DFU_AVR\CID_0x1e974d] DfuAltName = @Flash/0x0/1*128Kg # ATxmega128B3 [USER] USER=0x20000 -[AvrChipId=0x1e974b] +[DFU_AVR\CID_0x1e974b] DfuAltName = @Flash/0x0/1*128Kg # ATxmega192C3 [USER] USER=0x30000 -[AvrChipId=0x1e9751] +[DFU_AVR\CID_0x1e9751] DfuAltName = @Flash/0x0/1*192Kg # ATxmega192D3 [USER] USER=0x30000 -[AvrChipId=0x1e9749] +[DFU_AVR\CID_0x1e9749] DfuAltName = @Flash/0x0/1*192Kg # ATxmega192A1 [USER] USER=0x30000 -[AvrChipId=0x1e974e] +[DFU_AVR\CID_0x1e974e] DfuAltName = @Flash/0x0/1*192Kg # ATxmega192A3 [USER] USER=0x30000 -[AvrChipId=0x1e9744] +[DFU_AVR\CID_0x1e9744] DfuAltName = @Flash/0x0/1*192Kg # ATxmega256 [USER] USER=0x40000 -[AvrChipId=0x1e9846] +[DFU_AVR\CID_0x1e9846] DfuAltName = @Flash/0x0/1*256Kg # ATxmega256D3 [USER] USER=0x40000 -[AvrChipId=0x1e9844] +[DFU_AVR\CID_0x1e9844] DfuAltName = @Flash/0x0/1*256Kg # ATxmega256A3 [USER] USER=0x40000 -[AvrChipId=0x1e9842] +[DFU_AVR\CID_0x1e9842] DfuAltName = @Flash/0x0/1*256Kg # ATxmega256A3B [USER] USER=0x40000 -[AvrChipId=0x1e9843] +[DFU_AVR\CID_0x1e9843] DfuAltName = @Flash/0x0/1*256Kg # ATxmega384C3 [USER] USER=0x60000 -[AvrChipId=0x1e9845] +[DFU_AVR\CID_0x1e9845] DfuAltName = @Flash/0x0/1*384Kg # ATxmega384D3 [USER] USER=0x60000 -[AvrChipId=0x1e9847] +[DFU_AVR\CID_0x1e9847] DfuAltName = @Flash/0x0/1*384Kg # ATxmega8E5 [USER] USER=0x2000 -[AvrChipId=0x1e9341] +[DFU_AVR\CID_0x1e9341] DfuAltName = @Flash/0x0/1*8Kg # ATxmega16E5 [USER] USER=0x4000 -[AvrChipId=0x1e9445] +[DFU_AVR\CID_0x1e9445] DfuAltName = @Flash/0x0/1*16Kg # ATxmega32E5 [USER] USER=0x8000 -[AvrChipId=0x1e954c] +[DFU_AVR\CID_0x1e954c] DfuAltName = @Flash/0x0/1*32Kg # STM32F745 dfuse bootloader -[DeviceInstanceId=USB\VID_0483&PID_DF11] +[USB\VID_0483&PID_DF11] Flags = absent-sector-size Plugin = dfu DfuForceVersion = 011a DfuForceTimeout = 5000 + +# Poly Studio +[USB\VID_095D&PID_9217] +Plugin = dfu +Flags = manifest-poll,no-bus-reset-attach +RemoveDelay = 60000 +[USB\VID_095D&PID_9218] +Plugin = dfu +Flags = manifest-poll,no-bus-reset-attach +RemoveDelay = 60000 + +# Poly Eagle Eye Cube +[USB\VID_095D&PID_9212] +Plugin = dfu +Flags = manifest-poll +RemoveDelay = 30000 +[USB\VID_095D&PID_9213] +Plugin = dfu +Flags = manifest-poll +RemoveDelay = 30000 + +# Poly P30 +[USB\VID_095D&PID_9290] +Plugin = dfu +Flags = manifest-poll +RemoveDelay = 60000 +[USB\VID_095D&PID_9291] +Plugin = dfu +Flags = manifest-poll +RemoveDelay = 60000 + +# Poly ULCC +[USB\VID_095D&PID_9160] +Plugin = dfu +Flags = manifest-poll,no-bus-reset-attach +RemoveDelay = 60000 +[USB\VID_095D&PID_927B] +Plugin = dfu +Flags = manifest-poll,no-bus-reset-attach +RemoveDelay = 60000 + +# Poly Eagle Eye Mini +[USB\VID_095D&PID_3001] +Plugin = dfu +Flags = manifest-poll +RemoveDelay = 9000 +[USB\VID_095D&PID_3002] +Plugin = dfu +Flags = manifest-poll +RemoveDelay = 9000 diff -Nru fwupd-1.4.5/plugins/dfu/dfu-sector.c fwupd-1.5.8/plugins/dfu/dfu-sector.c --- fwupd-1.4.5/plugins/dfu/dfu-sector.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/dfu-sector.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,236 +0,0 @@ -/* - * Copyright (C) 2015 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -/** - * SECTION:dfu-sector - * @short_description: Object representing a sector on a chip - * - * This object represents an sector of memory at a specific address on the - * device itself. - * - * This allows relocatable data segments to be stored in different - * locations on the device itself. - * - * You can think of these objects as flash segments on devices, where a - * complete block can be erased and then written to. - * - * See also: #DfuElement - */ - -#include "config.h" - -#include -#include - -#include "dfu-common.h" -#include "dfu-sector.h" - -typedef struct { - guint32 address; - guint32 size; - guint32 size_left; - guint16 zone; - guint16 number; - DfuSectorCap cap; -} DfuSectorPrivate; - -G_DEFINE_TYPE_WITH_PRIVATE (DfuSector, dfu_sector, G_TYPE_OBJECT) -#define GET_PRIVATE(o) (dfu_sector_get_instance_private (o)) - -static void -dfu_sector_class_init (DfuSectorClass *klass) -{ -} - -static void -dfu_sector_init (DfuSector *sector) -{ -} - -/** - * dfu_sector_new: (skip) - * address: the address for the sector - * size: the size of this sector - * size_left: the size of the rest of the sector - * zone: the zone of memory the setor belongs - * number: the sector number in the zone - * cap: the #DfuSectorCap - * - * Creates a new DFU sector object. - * - * Return value: a new #DfuSector - **/ -DfuSector * -dfu_sector_new (guint32 address, guint32 size, guint32 size_left, - guint16 zone, guint16 number, DfuSectorCap cap) -{ - DfuSectorPrivate *priv; - DfuSector *sector; - sector = g_object_new (DFU_TYPE_SECTOR, NULL); - priv = GET_PRIVATE (sector); - priv->address = address; - priv->size = size; - priv->size_left = size_left; - priv->zone = zone; - priv->number = number; - priv->cap = cap; - return sector; -} - -/** - * dfu_sector_get_address: - * @sector: a #DfuSector - * - * Gets the alternate setting. - * - * Return value: integer, or 0x00 for unset - **/ -guint32 -dfu_sector_get_address (DfuSector *sector) -{ - DfuSectorPrivate *priv = GET_PRIVATE (sector); - g_return_val_if_fail (DFU_IS_SECTOR (sector), 0x00); - return priv->address; -} - -/** - * dfu_sector_get_size: - * @sector: a #DfuSector - * - * Gets the sector size. - * - * Return value: integer, or 0x00 for unset - **/ -guint32 -dfu_sector_get_size (DfuSector *sector) -{ - DfuSectorPrivate *priv = GET_PRIVATE (sector); - g_return_val_if_fail (DFU_IS_SECTOR (sector), 0x00); - return priv->size; -} - -/** - * dfu_sector_get_size_left: - * @sector: a #DfuSector - * - * Gets the size of the rest of the sector. - * - * Return value: integer, or 0x00 for unset - **/ -guint32 -dfu_sector_get_size_left (DfuSector *sector) -{ - DfuSectorPrivate *priv = GET_PRIVATE (sector); - g_return_val_if_fail (DFU_IS_SECTOR (sector), 0x00); - return priv->size_left; -} - -/** - * dfu_sector_get_zone: - * @sector: a #DfuSector - * - * Gets the sector zone number. - * - * Return value: integer, or 0x00 for unset - **/ -guint16 -dfu_sector_get_zone (DfuSector *sector) -{ - DfuSectorPrivate *priv = GET_PRIVATE (sector); - g_return_val_if_fail (DFU_IS_SECTOR (sector), 0x00); - return priv->zone; -} - -/** - * dfu_sector_get_number: - * @sector: a #DfuSector - * - * Gets the sector index number. - * - * Return value: integer, or 0x00 for unset - **/ -guint16 -dfu_sector_get_number (DfuSector *sector) -{ - DfuSectorPrivate *priv = GET_PRIVATE (sector); - g_return_val_if_fail (DFU_IS_SECTOR (sector), 0x00); - return priv->number; -} - -/** - * dfu_sector_get_id: - * @sector: a #DfuSector - * - * Gets the sector ID which is a combination of the zone and sector number. - * You can use this number to check if the segment is the 'same' as the last - * written or read sector. - * - * Return value: integer ID, or 0x00 for unset - **/ -guint32 -dfu_sector_get_id (DfuSector *sector) -{ - DfuSectorPrivate *priv = GET_PRIVATE (sector); - g_return_val_if_fail (DFU_IS_SECTOR (sector), 0x00); - return (((guint32) priv->zone) << 16) | priv->number; -} - -/** - * dfu_sector_has_cap: - * @sector: a #DfuSector - * @cap: a #DfuSectorCap, e.g. %DFU_SECTOR_CAP_ERASEABLE - * - * Finds out if the sector has the required capability. - * - * Return value: %TRUE if the sector has the capabilily - **/ -gboolean -dfu_sector_has_cap (DfuSector *sector, DfuSectorCap cap) -{ - DfuSectorPrivate *priv = GET_PRIVATE (sector); - g_return_val_if_fail (DFU_IS_SECTOR (sector), FALSE); - return (priv->cap & cap) > 0; -} - -static gchar * -dfu_sector_cap_to_string (DfuSectorCap cap) -{ - GString *str = g_string_new (NULL); - if (cap & DFU_SECTOR_CAP_READABLE) - g_string_append (str, "R"); - if (cap & DFU_SECTOR_CAP_ERASEABLE) - g_string_append (str, "E"); - if (cap & DFU_SECTOR_CAP_WRITEABLE) - g_string_append (str, "W"); - return g_string_free (str, FALSE); -} - -/** - * dfu_sector_to_string: - * @sector: a #DfuSector - * - * Returns a string representation of the object. - * - * Return value: NULL terminated string, or %NULL for invalid - **/ -gchar * -dfu_sector_to_string (DfuSector *sector) -{ - DfuSectorPrivate *priv = GET_PRIVATE (sector); - GString *str; - g_autofree gchar *caps_str = NULL; - - g_return_val_if_fail (DFU_IS_SECTOR (sector), NULL); - - str = g_string_new (""); - caps_str = dfu_sector_cap_to_string (priv->cap); - g_string_append_printf (str, - "Zone:%i, Sec#:%i, Addr:0x%08x, " - "Size:0x%04x, Caps:0x%01x [%s]", - priv->zone, priv->number, priv->address, - priv->size, priv->cap, caps_str); - return g_string_free (str, FALSE); -} diff -Nru fwupd-1.4.5/plugins/dfu/dfu-sector.h fwupd-1.5.8/plugins/dfu/dfu-sector.h --- fwupd-1.4.5/plugins/dfu/dfu-sector.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/dfu-sector.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2015 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include -#include - -#define DFU_TYPE_SECTOR (dfu_sector_get_type ()) -G_DECLARE_DERIVABLE_TYPE (DfuSector, dfu_sector, DFU, SECTOR, GObject) - -struct _DfuSectorClass -{ - GObjectClass parent_class; -}; - -/** - * DfuSectorCap: - * @DFU_SECTOR_CAP_NONE: No operations possible - * @DFU_SECTOR_CAP_READABLE: Sector can be read - * @DFU_SECTOR_CAP_WRITEABLE: Sector can be written - * @DFU_SECTOR_CAP_ERASEABLE: Sector can be erased - * - * The flags indicating what the sector can do. - **/ -typedef enum { - DFU_SECTOR_CAP_NONE = 0, - DFU_SECTOR_CAP_READABLE = 1 << 0, - DFU_SECTOR_CAP_WRITEABLE = 1 << 1, - DFU_SECTOR_CAP_ERASEABLE = 1 << 2, - /*< private >*/ - DFU_SECTOR_CAP_LAST -} DfuSectorCap; - -DfuSector *dfu_sector_new (guint32 address, - guint32 size, - guint32 size_left, - guint16 zone, - guint16 number, - DfuSectorCap cap); -guint32 dfu_sector_get_id (DfuSector *sector); -guint32 dfu_sector_get_address (DfuSector *sector); -guint32 dfu_sector_get_size (DfuSector *sector); -guint32 dfu_sector_get_size_left (DfuSector *sector); -guint16 dfu_sector_get_zone (DfuSector *sector); -guint16 dfu_sector_get_number (DfuSector *sector); -gboolean dfu_sector_has_cap (DfuSector *sector, - DfuSectorCap cap); -gchar *dfu_sector_to_string (DfuSector *sector); diff -Nru fwupd-1.4.5/plugins/dfu/dfu-self-test.c fwupd-1.5.8/plugins/dfu/dfu-self-test.c --- fwupd-1.4.5/plugins/dfu/dfu-self-test.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/dfu-self-test.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,362 +0,0 @@ -/* - * Copyright (C) 2015 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include -#include -#include - -#include "dfu-common.h" -#include "dfu-device.h" -#include "dfu-firmware.h" -#include "dfu-sector.h" -#include "dfu-target-private.h" - -#include "fu-common.h" - -#include "fwupd-error.h" - -static gchar * -dfu_test_get_filename (const gchar *filename) -{ - g_autofree gchar *path = NULL; - path = g_build_filename (TESTDATADIR, filename, NULL); - return fu_common_realpath (path, NULL); -} - -static void -dfu_enums_func (void) -{ - for (guint i = 0; i < DFU_STATE_LAST; i++) - g_assert_cmpstr (dfu_state_to_string (i), !=, NULL); - for (guint i = 0; i < DFU_STATUS_LAST; i++) - g_assert_cmpstr (dfu_status_to_string (i), !=, NULL); -} - -static GBytes * -dfu_self_test_get_bytes_for_file (GFile *file, GError **error) -{ - gchar *contents = NULL; - gsize length = 0; - if (!g_file_load_contents (file, NULL, &contents, &length, NULL, error)) - return NULL; - return g_bytes_new_take (contents, length); -} - -static gboolean -fu_test_compare_lines (const gchar *txt1, const gchar *txt2, GError **error) -{ - g_autofree gchar *output = NULL; - if (g_strcmp0 (txt1, txt2) == 0) - return TRUE; - if (fu_common_fnmatch (txt2, txt1)) - return TRUE; - if (!g_file_set_contents ("/tmp/a", txt1, -1, error)) - return FALSE; - if (!g_file_set_contents ("/tmp/b", txt2, -1, error)) - return FALSE; - if (!g_spawn_command_line_sync ("diff -urNp /tmp/b /tmp/a", - &output, NULL, NULL, error)) - return FALSE; - g_set_error_literal (error, 1, 0, output); - return FALSE; -} - -static void -dfu_firmware_raw_func (void) -{ - DfuElement *element; - GBytes *no_suffix_contents; - gchar buf[256]; - gboolean ret; - g_autoptr(DfuFirmware) firmware = NULL; - g_autoptr(DfuImage) image_tmp = NULL; - g_autoptr(GBytes) fw = NULL; - g_autoptr(GBytes) roundtrip = NULL; - g_autoptr(GError) error = NULL; - - /* set up some dummy data */ - for (guint i = 0; i < 256; i++) - buf[i] = (gchar) i; - fw = g_bytes_new_static (buf, 256); - - /* load a non DFU firmware */ - firmware = dfu_firmware_new (); - ret = dfu_firmware_parse_data (firmware, fw, FWUPD_INSTALL_FLAG_NONE, &error); - g_assert_no_error (error); - g_assert (ret); - g_assert_cmpint (fu_dfu_firmware_get_vid (FU_DFU_FIRMWARE (firmware)), ==, 0xffff); - g_assert_cmpint (fu_dfu_firmware_get_pid (FU_DFU_FIRMWARE (firmware)), ==, 0xffff); - g_assert_cmpint (fu_dfu_firmware_get_release (FU_DFU_FIRMWARE (firmware)), ==, 0xffff); - g_assert_cmpint (dfu_firmware_get_format (firmware), ==, DFU_FIRMWARE_FORMAT_RAW); - image_tmp = DFU_IMAGE (fu_firmware_get_image_by_idx (FU_FIRMWARE (firmware), 0xfe, NULL)); - g_assert (image_tmp == NULL); - image_tmp = DFU_IMAGE (fu_firmware_get_image_by_idx (FU_FIRMWARE (firmware), 0, NULL)); - g_assert (image_tmp != NULL); - g_assert_cmpint (dfu_image_get_size (image_tmp), ==, 256); - element = dfu_image_get_element (image_tmp, 0); - g_assert (element != NULL); - no_suffix_contents = dfu_element_get_contents (element); - g_assert (no_suffix_contents != NULL); - g_assert_cmpint (g_bytes_compare (no_suffix_contents, fw), ==, 0); - - /* can we roundtrip without adding data */ - roundtrip = dfu_firmware_write_data (firmware, &error); - g_assert_no_error (error); - g_assert (roundtrip != NULL); - ret = fu_common_bytes_compare (roundtrip, fw, &error); - g_assert_no_error (error); - g_assert_true (ret); -} - -static void -dfu_firmware_dfu_func (void) -{ - gchar buf[256]; - gboolean ret; - g_autofree gchar *filename = NULL; - g_autoptr(DfuFirmware) firmware1 = dfu_firmware_new (); - g_autoptr(DfuFirmware) firmware2 = dfu_firmware_new (); - g_autoptr(DfuFirmware) firmware3 = dfu_firmware_new (); - g_autoptr(DfuImage) image = NULL; - g_autoptr(DfuElement) element = NULL; - g_autoptr(GBytes) data = NULL; - g_autoptr(GBytes) fw = NULL; - g_autoptr(GBytes) roundtrip_orig = NULL; - g_autoptr(GBytes) roundtrip = NULL; - g_autoptr(GError) error = NULL; - g_autoptr(GFile) file = NULL; - - /* set up some dummy data */ - for (guint i = 0; i < 256; i++) - buf[i] = (gchar) i; - fw = g_bytes_new_static (buf, 256); - - /* write DFU format */ - dfu_firmware_set_format (firmware1, DFU_FIRMWARE_FORMAT_DFU); - fu_dfu_firmware_set_vid (FU_DFU_FIRMWARE (firmware1), 0x1234); - fu_dfu_firmware_set_pid (FU_DFU_FIRMWARE (firmware1), 0x5678); - fu_dfu_firmware_set_release (FU_DFU_FIRMWARE (firmware1), 0xfedc); - image = dfu_image_new (); - element = dfu_element_new (); - dfu_element_set_contents (element, fw); - dfu_image_add_element (image, element); - fu_firmware_add_image (FU_FIRMWARE (firmware1), FU_FIRMWARE_IMAGE (image)); - g_assert_cmpint (dfu_firmware_get_size (firmware1), ==, 256); - data = dfu_firmware_write_data (firmware1, &error); - g_assert_no_error (error); - g_assert (data != NULL); - - /* can we load it again? */ - ret = dfu_firmware_parse_data (firmware2, data, FWUPD_INSTALL_FLAG_NONE, &error); - g_assert_no_error (error); - g_assert (ret); - g_assert_cmpint (fu_dfu_firmware_get_vid (FU_DFU_FIRMWARE (firmware2)), ==, 0x1234); - g_assert_cmpint (fu_dfu_firmware_get_pid (FU_DFU_FIRMWARE (firmware2)), ==, 0x5678); - g_assert_cmpint (fu_dfu_firmware_get_release (FU_DFU_FIRMWARE (firmware2)), ==, 0xfedc); - g_assert_cmpint (dfu_firmware_get_format (firmware2), ==, DFU_FIRMWARE_FORMAT_DFU); - g_assert_cmpint (dfu_firmware_get_size (firmware2), ==, 256); - - /* load a real firmware */ - filename = dfu_test_get_filename ("kiibohd.dfu.bin"); - g_assert (filename != NULL); - file = g_file_new_for_path (filename); - ret = dfu_firmware_parse_file (firmware3, file, - FWUPD_INSTALL_FLAG_NONE, - &error); - g_assert_no_error (error); - g_assert (ret); - g_assert_cmpint (fu_dfu_firmware_get_vid (FU_DFU_FIRMWARE (firmware3)), ==, 0x1c11); - g_assert_cmpint (fu_dfu_firmware_get_pid (FU_DFU_FIRMWARE (firmware3)), ==, 0xb007); - g_assert_cmpint (fu_dfu_firmware_get_release (FU_DFU_FIRMWARE (firmware3)), ==, 0xffff); - g_assert_cmpint (dfu_firmware_get_format (firmware3), ==, DFU_FIRMWARE_FORMAT_DFU); - g_assert_cmpint (dfu_firmware_get_size (firmware3), ==, 0x8eB4); - - /* can we roundtrip without losing data */ - roundtrip_orig = dfu_self_test_get_bytes_for_file (file, &error); - g_assert_no_error (error); - g_assert (roundtrip_orig != NULL); - roundtrip = dfu_firmware_write_data (firmware3, &error); - g_assert_no_error (error); - g_assert (roundtrip != NULL); - ret = fu_common_bytes_compare (roundtrip, roundtrip_orig, &error); - g_assert_no_error (error); - g_assert_true (ret); -} - -static void -dfu_firmware_dfuse_func (void) -{ - gboolean ret; - g_autofree gchar *filename = NULL; - g_autoptr(DfuFirmware) firmware = NULL; - g_autoptr(GBytes) roundtrip_orig = NULL; - g_autoptr(GBytes) roundtrip = NULL; - g_autoptr(GError) error = NULL; - g_autoptr(GFile) file = NULL; - - /* load a DeFUse firmware */ - g_setenv ("DFU_SELF_TEST_IMAGE_MEMCPY_NAME", "", FALSE); - filename = dfu_test_get_filename ("dev_VRBRAIN.dfu"); - g_assert (filename != NULL); - file = g_file_new_for_path (filename); - firmware = dfu_firmware_new (); - ret = dfu_firmware_parse_file (firmware, file, - FWUPD_INSTALL_FLAG_NONE, - &error); - g_assert_no_error (error); - g_assert (ret); - g_assert_cmpint (fu_dfu_firmware_get_vid (FU_DFU_FIRMWARE (firmware)), ==, 0x0483); - g_assert_cmpint (fu_dfu_firmware_get_pid (FU_DFU_FIRMWARE (firmware)), ==, 0x0000); - g_assert_cmpint (fu_dfu_firmware_get_release (FU_DFU_FIRMWARE (firmware)), ==, 0x0000); - g_assert_cmpint (dfu_firmware_get_format (firmware), ==, DFU_FIRMWARE_FORMAT_DFUSE); - g_assert_cmpint (dfu_firmware_get_size (firmware), ==, 0x168d5); - - /* can we roundtrip without losing data */ - roundtrip_orig = dfu_self_test_get_bytes_for_file (file, &error); - g_assert_no_error (error); - g_assert (roundtrip_orig != NULL); - roundtrip = dfu_firmware_write_data (firmware, &error); - g_assert_no_error (error); - g_assert (roundtrip != NULL); - -// g_file_set_contents ("/tmp/1.bin", -// g_bytes_get_data (roundtrip, NULL), -// g_bytes_get_size (roundtrip), NULL); - - ret = fu_common_bytes_compare (roundtrip, roundtrip_orig, &error); - g_assert_no_error (error); - g_assert_true (ret); - - /* use usual image name copying */ - g_unsetenv ("DFU_SELF_TEST_IMAGE_MEMCPY_NAME"); -} - -static gchar * -dfu_target_sectors_to_string (DfuTarget *target) -{ - GPtrArray *sectors; - GString *str; - - str = g_string_new (""); - sectors = dfu_target_get_sectors (target); - for (guint i = 0; i < sectors->len; i++) { - DfuSector *sector = g_ptr_array_index (sectors, i); - g_autofree gchar *tmp = dfu_sector_to_string (sector); - g_string_append_printf (str, "%s\n", tmp); - } - if (str->len > 0) - g_string_truncate (str, str->len - 1); - return g_string_free (str, FALSE); -} - -static void -dfu_target_dfuse_func (void) -{ - gboolean ret; - gchar *tmp; - g_autoptr(DfuDevice) device = dfu_device_new (NULL); - g_autoptr(DfuTarget) target = NULL; - g_autoptr(GError) error = NULL; - - /* NULL */ - target = g_object_new (DFU_TYPE_TARGET, NULL); - dfu_target_set_device (target, device); - ret = dfu_target_parse_sectors (target, NULL, &error); - g_assert_no_error (error); - g_assert (ret); - tmp = dfu_target_sectors_to_string (target); - g_assert_cmpstr (tmp, ==, ""); - g_free (tmp); - - /* no addresses */ - ret = dfu_target_parse_sectors (target, "@Flash3", &error); - g_assert_no_error (error); - g_assert (ret); - tmp = dfu_target_sectors_to_string (target); - g_assert_cmpstr (tmp, ==, ""); - g_free (tmp); - - /* one sector, no space */ - ret = dfu_target_parse_sectors (target, "@Internal Flash /0x08000000/2*001Ka", &error); - g_assert_no_error (error); - g_assert (ret); - tmp = dfu_target_sectors_to_string (target); - ret = fu_test_compare_lines (tmp, - "Zone:0, Sec#:0, Addr:0x08000000, Size:0x0400, Caps:0x1 [R]\n" - "Zone:0, Sec#:0, Addr:0x08000400, Size:0x0400, Caps:0x1 [R]", - &error); - g_assert_no_error (error); - g_assert (ret); - g_free (tmp); - - /* multiple sectors */ - ret = dfu_target_parse_sectors (target, "@Flash1 /0x08000000/2*001Ka,4*001Kg", &error); - g_assert_no_error (error); - g_assert (ret); - tmp = dfu_target_sectors_to_string (target); - ret = fu_test_compare_lines (tmp, - "Zone:0, Sec#:0, Addr:0x08000000, Size:0x0400, Caps:0x1 [R]\n" - "Zone:0, Sec#:0, Addr:0x08000400, Size:0x0400, Caps:0x1 [R]\n" - "Zone:0, Sec#:1, Addr:0x08000800, Size:0x0400, Caps:0x7 [REW]\n" - "Zone:0, Sec#:1, Addr:0x08000c00, Size:0x0400, Caps:0x7 [REW]\n" - "Zone:0, Sec#:1, Addr:0x08001000, Size:0x0400, Caps:0x7 [REW]\n" - "Zone:0, Sec#:1, Addr:0x08001400, Size:0x0400, Caps:0x7 [REW]", - &error); - g_assert_no_error (error); - g_assert (ret); - g_free (tmp); - - /* non-contiguous */ - ret = dfu_target_parse_sectors (target, "@Flash2 /0xF000/4*100Ba/0xE000/3*8Kg/0x80000/2*24Kg", &error); - g_assert_no_error (error); - g_assert (ret); - tmp = dfu_target_sectors_to_string (target); - ret = fu_test_compare_lines (tmp, - "Zone:0, Sec#:0, Addr:0x0000f000, Size:0x0064, Caps:0x1 [R]\n" - "Zone:0, Sec#:0, Addr:0x0000f064, Size:0x0064, Caps:0x1 [R]\n" - "Zone:0, Sec#:0, Addr:0x0000f0c8, Size:0x0064, Caps:0x1 [R]\n" - "Zone:0, Sec#:0, Addr:0x0000f12c, Size:0x0064, Caps:0x1 [R]\n" - "Zone:1, Sec#:0, Addr:0x0000e000, Size:0x2000, Caps:0x7 [REW]\n" - "Zone:1, Sec#:0, Addr:0x00010000, Size:0x2000, Caps:0x7 [REW]\n" - "Zone:1, Sec#:0, Addr:0x00012000, Size:0x2000, Caps:0x7 [REW]\n" - "Zone:2, Sec#:0, Addr:0x00080000, Size:0x6000, Caps:0x7 [REW]\n" - "Zone:2, Sec#:0, Addr:0x00086000, Size:0x6000, Caps:0x7 [REW]", - &error); - g_assert_no_error (error); - g_assert (ret); - g_free (tmp); - - /* invalid */ - ret = dfu_target_parse_sectors (target, "Flash", NULL); - g_assert (ret); - ret = dfu_target_parse_sectors (target, "@Internal Flash /0x08000000", NULL); - g_assert (!ret); - ret = dfu_target_parse_sectors (target, "@Internal Flash /0x08000000/12*001a", NULL); - g_assert (!ret); -} - -int -main (int argc, char **argv) -{ - g_test_init (&argc, &argv, NULL); - - /* only critical and error are fatal */ - g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); - - /* log everything */ - g_setenv ("G_MESSAGES_DEBUG", "all", FALSE); - - /* tests go here */ - g_test_add_func ("/dfu/enums", dfu_enums_func); - g_test_add_func ("/dfu/target(DfuSe}", dfu_target_dfuse_func); - g_test_add_func ("/dfu/firmware{raw}", dfu_firmware_raw_func); - g_test_add_func ("/dfu/firmware{dfu}", dfu_firmware_dfu_func); - g_test_add_func ("/dfu/firmware{dfuse}", dfu_firmware_dfuse_func); - return g_test_run (); -} - diff -Nru fwupd-1.4.5/plugins/dfu/dfu-target-avr.c fwupd-1.5.8/plugins/dfu/dfu-target-avr.c --- fwupd-1.4.5/plugins/dfu/dfu-target-avr.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/dfu-target-avr.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,768 +0,0 @@ -/* - * Copyright (C) 2017 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include -#include - -#include "fu-chunk.h" - -#include "dfu-common.h" -#include "dfu-sector.h" -#include "dfu-target-avr.h" -#include "dfu-target-private.h" -#include "dfu-device.h" - -#include "fwupd-error.h" - -/** - * FU_QUIRKS_DFU_AVR_ALT_NAME: - * @key: the AVR chip ID, e.g. `0x58200204` - * @value: the UM0424 sector description, e.g. `@Flash/0x2000/1*248Kg` - * - * Assigns a sector description for the chip ID. This is required so fwupd can - * program the user firmware avoiding the bootloader and for checking the total - * element size. - * - * The chip ID can be found from a datasheet or using `dfu-tool list` when the - * hardware is connected and in bootloader mode. - * - * Since: 1.0.1 - */ -#define FU_QUIRKS_DFU_AVR_ALT_NAME "DfuAltName" - -typedef struct { - guint32 device_id; -} DfuTargetAvrPrivate; - -G_DEFINE_TYPE_WITH_PRIVATE (DfuTargetAvr, dfu_target_avr, DFU_TYPE_TARGET) -#define GET_PRIVATE(o) (dfu_target_avr_get_instance_private (o)) - -/* ATMEL AVR version of DFU: - * http://www.atmel.com/Images/doc7618.pdf */ -#define DFU_AVR_CMD_PROG_START 0x01 -#define DFU_AVR_CMD_DISPLAY_DATA 0x03 -#define DFU_AVR_CMD_WRITE_COMMAND 0x04 -#define DFU_AVR_CMD_READ_COMMAND 0x05 -#define DFU_AVR_CMD_CHANGE_BASE_ADDR 0x06 - -/* Atmel AVR32 version of DFU: - * http://www.atmel.com/images/doc32131.pdf */ -#define DFU_AVR32_GROUP_SELECT 0x06 /** SELECT */ -#define DFU_AVR32_CMD_SELECT_MEMORY 0x03 -#define DFU_AVR32_MEMORY_UNIT 0x00 -#define DFU_AVR32_MEMORY_PAGE 0x01 -#define DFU_AVR32_MEMORY_UNIT_FLASH 0x00 -#define DFU_AVR32_MEMORY_UNIT_EEPROM 0x01 -#define DFU_AVR32_MEMORY_UNIT_SECURITY 0x02 -#define DFU_AVR32_MEMORY_UNIT_CONFIGURATION 0x03 -#define DFU_AVR32_MEMORY_UNIT_BOOTLOADER 0x04 -#define DFU_AVR32_MEMORY_UNIT_SIGNATURE 0x05 -#define DFU_AVR32_MEMORY_UNIT_USER 0x06 -#define DFU_AVR32_GROUP_DOWNLOAD 0x01 /** DOWNLOAD */ -#define DFU_AVR32_CMD_PROGRAM_START 0x00 -#define DFU_AVR32_GROUP_UPLOAD 0x03 /** UPLOAD */ -#define DFU_AVR32_CMD_READ_MEMORY 0x00 -#define DFU_AVR32_CMD_BLANK_CHECK 0x01 -#define DFU_AVR32_GROUP_EXEC 0x04 /** EXEC */ -#define DFU_AVR32_CMD_ERASE 0x00 -#define DFU_AVR32_ERASE_EVERYTHING 0xff -#define DFU_AVR32_CMD_START_APPLI 0x03 -#define DFU_AVR32_START_APPLI_RESET 0x00 -#define DFU_AVR32_START_APPLI_NO_RESET 0x01 - -#define ATMEL_64KB_PAGE 0x10000 -#define ATMEL_MAX_TRANSFER_SIZE 0x0400 -#define ATMEL_AVR_CONTROL_BLOCK_SIZE 32 -#define ATMEL_AVR32_CONTROL_BLOCK_SIZE 64 - -#define ATMEL_MANUFACTURER_CODE1 0x58 -#define ATMEL_MANUFACTURER_CODE2 0x1e - -static gboolean -dfu_target_avr_mass_erase (DfuTarget *target, GError **error) -{ - g_autoptr(GBytes) data_in = NULL; - guint8 buf[3]; - - /* this takes a long time on some devices */ - dfu_device_set_timeout (dfu_target_get_device (target), 5000); - - /* format buffer */ - buf[0] = DFU_AVR32_GROUP_EXEC; - buf[1] = DFU_AVR32_CMD_ERASE; - buf[2] = 0xff; - data_in = g_bytes_new_static (buf, sizeof(buf)); - g_debug ("mass erasing"); - dfu_target_set_action (target, FWUPD_STATUS_DEVICE_ERASE); - if (!dfu_target_download_chunk (target, 0, data_in, error)) { - g_prefix_error (error, "cannot mass-erase: "); - return FALSE; - } - dfu_target_set_action (target, FWUPD_STATUS_IDLE); - return TRUE; -} - -static gboolean -dfu_target_avr_attach (DfuTarget *target, GError **error) -{ - guint8 buf[3]; - g_autoptr(GBytes) data_empty = NULL; - g_autoptr(GBytes) data_in = NULL; - g_autoptr(GError) error_local = NULL; - - /* format buffer */ - buf[0] = DFU_AVR32_GROUP_EXEC; - buf[1] = DFU_AVR32_CMD_START_APPLI; - buf[2] = DFU_AVR32_START_APPLI_RESET; - data_in = g_bytes_new_static (buf, sizeof(buf)); - if (!dfu_target_download_chunk (target, 0, data_in, &error_local)) { - if (g_error_matches (error_local, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED)) { - g_debug ("ignoring as device rebooting: %s", error_local->message); - return TRUE; - } - g_prefix_error (error, "cannot start application reset attach: "); - return FALSE; - } - - /* do zero-sized download to initiate the reset */ - data_empty = g_bytes_new (NULL, 0); - if (!dfu_target_download_chunk (target, 0, data_empty, &error_local)) { - if (g_error_matches (error_local, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED)) { - g_debug ("ignoring as device rebooting: %s", error_local->message); - return TRUE; - } - g_prefix_error (error, "cannot initiate reset for attach: "); - return FALSE; - } - - /* success */ - return TRUE; -} - -/** - * dfu_target_avr_select_memory_unit: - * @target: a #DfuTarget - * @memory_unit: a unit, e.g. %DFU_AVR32_MEMORY_UNIT_FLASH - * @error: a #GError, or %NULL - * - * Selects the memory unit for the device. - * - * Return value: %TRUE for success - **/ -static gboolean -dfu_target_avr_select_memory_unit (DfuTarget *target, - guint8 memory_unit, - GError **error) -{ - g_autoptr(GBytes) data_in = NULL; - guint8 buf[4]; - - /* check legacy protocol quirk */ - if (fu_device_has_custom_flag (FU_DEVICE (dfu_target_get_device (target)), - "legacy-protocol")) { - g_debug ("ignoring select memory unit as legacy protocol"); - return TRUE; - } - - /* format buffer */ - buf[0] = DFU_AVR32_GROUP_SELECT; - buf[1] = DFU_AVR32_CMD_SELECT_MEMORY; - buf[2] = DFU_AVR32_MEMORY_UNIT; - buf[3] = memory_unit; - data_in = g_bytes_new_static (buf, sizeof(buf)); - g_debug ("selecting memory unit 0x%02x", (guint) memory_unit); - if (!dfu_target_download_chunk (target, 0, data_in, error)) { - g_prefix_error (error, "cannot select memory unit: "); - return FALSE; - } - return TRUE; -} - -/** - * dfu_target_avr_select_memory_page: - * @target: a #DfuTarget - * @memory_page: an address - * @error: a #GError, or %NULL - * - * Selects the memory page for the AVR device. - * - * Return value: %TRUE for success - **/ -static gboolean -dfu_target_avr_select_memory_page (DfuTarget *target, - guint16 memory_page, - GError **error) -{ - g_autoptr(GBytes) data_in = NULL; - guint8 buf[4]; - - /* check page not too large for protocol */ - if (memory_page > 0xff) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "cannot select memory page:0x%02x " - "with FLIP protocol version 1", - memory_page); - return FALSE; - } - - /* format buffer */ - buf[0] = DFU_AVR_CMD_CHANGE_BASE_ADDR; - buf[1] = 0x03; - buf[2] = 0x00; - buf[3] = memory_page & 0xff; - data_in = g_bytes_new_static (buf, sizeof(buf)); - g_debug ("selecting memory page 0x%01x", (guint) memory_page); - if (!dfu_target_download_chunk (target, 0, data_in, error)) { - g_prefix_error (error, "cannot select memory page: "); - return FALSE; - } - return TRUE; -} - -/** - * dfu_target_avr32_select_memory_page: - * @target: a #DfuTarget - * @memory_page: an address - * @error: a #GError, or %NULL - * - * Selects the memory page for the AVR32 device. - * - * Return value: %TRUE for success - **/ -static gboolean -dfu_target_avr32_select_memory_page (DfuTarget *target, - guint16 memory_page, - GError **error) -{ - g_autoptr(GBytes) data_in = NULL; - guint8 buf[5]; - - /* format buffer */ - buf[0] = DFU_AVR32_GROUP_SELECT; - buf[1] = DFU_AVR32_CMD_SELECT_MEMORY; - buf[2] = DFU_AVR32_MEMORY_PAGE; - fu_common_write_uint16 (&buf[3], memory_page, G_BIG_ENDIAN); - data_in = g_bytes_new_static (buf, sizeof(buf)); - g_debug ("selecting memory page 0x%02x", (guint) memory_page); - if (!dfu_target_download_chunk (target, 0, data_in, error)) { - g_prefix_error (error, "cannot select memory page: "); - return FALSE; - } - return TRUE; -} - -/** - * dfu_target_avr_read_memory - * @target: a #DfuTarget - * @addr_start: an address - * @addr_end: an address - * @error: a #GError, or %NULL - * - * Reads flash data from the device. - * - * Return value: %TRUE for success - **/ -static gboolean -dfu_target_avr_read_memory (DfuTarget *target, - guint16 addr_start, - guint16 addr_end, - GError **error) -{ - g_autoptr(GBytes) data_in = NULL; - guint8 buf[6]; - - /* format buffer */ - buf[0] = DFU_AVR32_GROUP_UPLOAD; - buf[1] = DFU_AVR32_CMD_READ_MEMORY; - fu_common_write_uint16 (&buf[2], addr_start, G_BIG_ENDIAN); - fu_common_write_uint16 (&buf[4], addr_end, G_BIG_ENDIAN); - data_in = g_bytes_new_static (buf, sizeof(buf)); - g_debug ("reading memory from 0x%04x to 0x%04x", - (guint) addr_start, (guint) addr_end); - if (!dfu_target_download_chunk (target, 0, data_in, error)) { - g_prefix_error (error, "cannot read memory 0x%04x to 0x%04x: ", - (guint) addr_start, (guint) addr_end); - return FALSE; - } - return TRUE; -} - -/** - * dfu_target_avr_read_command: - * @target: a #DfuTarget - * @memory_unit: a unit, e.g. %DFU_AVR32_MEMORY_UNIT_FLASH - * @error: a #GError, or %NULL - * - * Performs a read operation on the device. - * - * Return value: %TRUE for success - **/ -static gboolean -dfu_target_avr_read_command (DfuTarget *target, guint8 page, guint8 addr, GError **error) -{ - g_autoptr(GBytes) data_in = NULL; - guint8 buf[3]; - - /* format buffer */ - buf[0] = DFU_AVR_CMD_READ_COMMAND; - buf[1] = page; - buf[2] = addr; - data_in = g_bytes_new_static (buf, sizeof(buf)); - g_debug ("read command page:0x%02x addr:0x%02x", (guint) page, (guint) addr); - if (!dfu_target_download_chunk (target, 0, data_in, error)) { - g_prefix_error (error, "cannot read command page: "); - return FALSE; - } - return TRUE; -} - -/** - * dfu_target_avr32_get_chip_signature: - * @target: a #DfuTarget - * @error: a #GError, or %NULL - * - * Gets the chip signature for the AVR32 device. - * - * Return value: a 4-byte %GBytes object for success, else %NULL - **/ -static GBytes * -dfu_target_avr32_get_chip_signature (DfuTarget *target, GError **error) -{ - /* select unit, and request 4 bytes */ - if (!dfu_target_avr_select_memory_unit (target, - DFU_AVR32_MEMORY_UNIT_SIGNATURE, - error)) - return NULL; - if (!dfu_target_avr32_select_memory_page (target, 0x00, error)) - return NULL; - if (!dfu_target_avr_read_memory (target, 0x00, 0x03, error)) - return NULL; - - /* get data back */ - return dfu_target_upload_chunk (target, 0x00, 0, error); -} - -/** - * dfu_target_avr_get_chip_signature: - * @target: a #DfuTarget - * @error: a #GError, or %NULL - * - * Gets the chip signature for the AVR device. - * - * Return value: a 4-byte %GBytes object for success, else %NULL - **/ -static GBytes * -dfu_target_avr_get_chip_signature (DfuTarget *target, GError **error) -{ - struct { - guint8 page; - guint addr; - } signature_locations[] = { - { 0x01, 0x30 }, - { 0x01, 0x31 }, - { 0x01, 0x60 }, - { 0x01, 0x61 }, - { 0xff, 0xff } - }; - g_autoptr(GPtrArray) chunks = NULL; - - /* we have to request this one byte at a time */ - chunks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref); - for (guint i = 0; signature_locations[i].page != 0xff; i++) { - g_autoptr(GBytes) chunk_byte = NULL; - - /* request a single byte */ - if (!dfu_target_avr_read_command (target, - signature_locations[i].page, - signature_locations[i].addr, - error)) - return NULL; - - /* get data back */ - chunk_byte = dfu_target_upload_chunk (target, 0x00, 0x01, error); - if (chunk_byte == NULL) - return NULL; - if (g_bytes_get_size (chunk_byte) != 1) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "cannot read signature memory page:0x%02x " - "addr:0x%02x, got 0x%02x bytes", - (guint) signature_locations[i].page, - (guint) signature_locations[i].addr, - (guint) g_bytes_get_size (chunk_byte)); - return NULL; - } - g_ptr_array_add (chunks, g_steal_pointer (&chunk_byte)); - } - return dfu_utils_bytes_join_array (chunks); -} - -static gboolean -dfu_target_avr_setup (DfuTarget *target, GError **error) -{ - DfuDevice *device; - DfuTargetAvr *target_avr = DFU_TARGET_AVR (target); - DfuTargetAvrPrivate *priv = GET_PRIVATE (target_avr); - const gchar *quirk_str; - const guint8 *buf; - gsize sz; - guint32 device_id_be; - g_autofree gchar *chip_id = NULL; - g_autofree gchar *chip_id_prefixed = NULL; - g_autoptr(GBytes) chunk_sig = NULL; - - /* already done */ - if (priv->device_id > 0x0) - return TRUE; - - /* different methods for AVR vs. AVR32 */ - if (fu_device_has_custom_flag (FU_DEVICE (dfu_target_get_device (target)), - "legacy-protocol")) { - chunk_sig = dfu_target_avr_get_chip_signature (target, error); - if (chunk_sig == NULL) - return FALSE; - } else { - chunk_sig = dfu_target_avr32_get_chip_signature (target, error); - if (chunk_sig == NULL) { - g_prefix_error (error, "failed to get chip signature: "); - return FALSE; - } - } - - /* get data back */ - buf = g_bytes_get_data (chunk_sig, &sz); - if (sz != 4) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "cannot read config memory, got 0x%02x bytes", - (guint) sz); - return FALSE; - } - memcpy (&device_id_be, buf, 4); - priv->device_id = GINT32_FROM_BE (device_id_be); - if (buf[0] == ATMEL_MANUFACTURER_CODE1) { - chip_id = g_strdup_printf ("0x%08x", (guint) priv->device_id); - } else if (buf[0] == ATMEL_MANUFACTURER_CODE2) { - chip_id = g_strdup_printf ("0x%06x", (guint) priv->device_id >> 8); - } else { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "cannot read config vendor, got 0x%08x, " - "expected 0x%02x or 0x%02x", - (guint) priv->device_id, - (guint) ATMEL_MANUFACTURER_CODE1, - (guint) ATMEL_MANUFACTURER_CODE2); - return FALSE; - } - - /* set the alt-name using the device ID */ - dfu_device_set_chip_id (dfu_target_get_device (target), chip_id); - device = dfu_target_get_device (target); - chip_id_prefixed = g_strdup_printf ("AvrChipId=%s", chip_id); - quirk_str = fu_quirks_lookup_by_id (fu_device_get_quirks (FU_DEVICE (device)), - chip_id_prefixed, - FU_QUIRKS_DFU_AVR_ALT_NAME); - if (quirk_str == NULL) { - dfu_device_remove_attribute (dfu_target_get_device (target), - DFU_DEVICE_ATTRIBUTE_CAN_DOWNLOAD); - dfu_device_remove_attribute (dfu_target_get_device (target), - DFU_DEVICE_ATTRIBUTE_CAN_UPLOAD); - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "DeviceID %s is not supported", - chip_id); - return FALSE; - } - dfu_target_set_alt_name (target, quirk_str); - - return TRUE; -} - -static gboolean -dfu_target_avr_download_element (DfuTarget *target, - DfuElement *element, - DfuTargetTransferFlags flags, - GError **error) -{ - DfuSector *sector; - GBytes *blob; - const guint8 *data; - gsize header_sz = ATMEL_AVR32_CONTROL_BLOCK_SIZE; - guint16 page_last = G_MAXUINT16; - guint32 address; - guint32 address_offset = 0x0; - g_autoptr(GPtrArray) chunks = NULL; - const guint8 footer[] = { 0x00, 0x00, 0x00, 0x00, /* CRC */ - 16, /* len */ - 'D', 'F', 'U', /* signature */ - 0x01, 0x10, /* version */ - 0xff, 0xff, /* vendor ID */ - 0xff, 0xff, /* product ID */ - 0xff, 0xff }; /* release */ - - /* select a memory and erase everything */ - if (!dfu_target_avr_select_memory_unit (target, - dfu_target_get_alt_setting (target), - error)) - return FALSE; - if (!dfu_target_avr_mass_erase (target, error)) - return FALSE; - - /* verify the element isn't larger than the target size */ - blob = dfu_element_get_contents (element); - sector = dfu_target_get_sector_default (target); - if (sector == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "no sector defined for target"); - return FALSE; - } - address = dfu_element_get_address (element) & ~0x80000000; - if (address < dfu_sector_get_address (sector)) { - address_offset = dfu_sector_get_address (sector) - address; - g_warning ("firmware element starts at 0x%x but sector " - "starts at 0x%x, so offsetting by 0x%x (bootloader?)", - (guint) address, - (guint) dfu_sector_get_address (sector), - (guint) address_offset); - } - if (g_bytes_get_size (blob) + address_offset > dfu_sector_get_size (sector)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "element was larger than sector size: 0x%x", - (guint) dfu_sector_get_size (sector)); - return FALSE; - } - - /* the original AVR protocol uses a half-size control block */ - if (fu_device_has_custom_flag (FU_DEVICE (dfu_target_get_device (target)), - "legacy-protocol")) { - header_sz = ATMEL_AVR_CONTROL_BLOCK_SIZE; - } - - /* chunk up the memory space into pages */ - data = g_bytes_get_data (blob, NULL); - chunks = fu_chunk_array_new (data + address_offset, - g_bytes_get_size (blob) - address_offset, - dfu_sector_get_address (sector), - ATMEL_64KB_PAGE, - ATMEL_MAX_TRANSFER_SIZE); - - /* update UI */ - dfu_target_set_action (target, FWUPD_STATUS_DEVICE_WRITE); - - /* process each chunk */ - for (guint i = 0; i < chunks->len; i++) { - const FuChunk *chk = g_ptr_array_index (chunks, i); - g_autofree guint8 *buf = NULL; - g_autoptr(GBytes) chunk_tmp = NULL; - - /* select page if required */ - if (chk->page != page_last) { - if (fu_device_has_custom_flag (FU_DEVICE (dfu_target_get_device (target)), - "legacy-protocol")) { - if (!dfu_target_avr_select_memory_page (target, - chk->page, - error)) - return FALSE; - } else { - if (!dfu_target_avr32_select_memory_page (target, - chk->page, - error)) - return FALSE; - } - page_last = chk->page; - } - - /* create chk with header and footer */ - buf = g_malloc0 (chk->data_sz + header_sz + sizeof(footer)); - buf[0] = DFU_AVR32_GROUP_DOWNLOAD; - buf[1] = DFU_AVR32_CMD_PROGRAM_START; - fu_common_write_uint16 (&buf[2], chk->address, G_BIG_ENDIAN); - fu_common_write_uint16 (&buf[4], chk->address + chk->data_sz - 1, G_BIG_ENDIAN); - memcpy (&buf[header_sz], chk->data, chk->data_sz); - memcpy (&buf[header_sz + chk->data_sz], footer, sizeof(footer)); - - /* download data */ - chunk_tmp = g_bytes_new_static (buf, chk->data_sz + header_sz + sizeof(footer)); - g_debug ("sending %" G_GSIZE_FORMAT " bytes to the hardware", - g_bytes_get_size (chunk_tmp)); - if (!dfu_target_download_chunk (target, i, chunk_tmp, error)) - return FALSE; - - /* update UI */ - dfu_target_set_percentage (target, i + 1, chunks->len); - } - - /* done */ - dfu_target_set_percentage_raw (target, 100); - dfu_target_set_action (target, FWUPD_STATUS_IDLE); - return TRUE; -} - -static DfuElement * -dfu_target_avr_upload_element (DfuTarget *target, - guint32 address, - gsize expected_size, - gsize maximum_size, - GError **error) -{ - guint16 page_last = G_MAXUINT16; - guint chunk_valid = G_MAXUINT; - g_autoptr(DfuElement) element = NULL; - g_autoptr(GBytes) contents = NULL; - g_autoptr(GBytes) contents_truncated = NULL; - g_autoptr(GPtrArray) blobs = NULL; - g_autoptr(GPtrArray) chunks = NULL; - DfuSector *sector; - - /* select unit */ - if (!dfu_target_avr_select_memory_unit (target, - dfu_target_get_alt_setting (target), - error)) - return NULL; - - /* verify the element isn't lower than the flash area */ - sector = dfu_target_get_sector_default (target); - if (sector == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "no sector defined for target"); - return NULL; - } - if (address < dfu_sector_get_address (sector)) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "cannot read from below sector start"); - return NULL; - } - - /* the flash starts at 0x80000000, but is indexed from zero */ - address &= ~0x80000000; - - /* chunk up the memory space into pages */ - chunks = fu_chunk_array_new (NULL, maximum_size, address, - ATMEL_64KB_PAGE, ATMEL_MAX_TRANSFER_SIZE); - - /* update UI */ - dfu_target_set_action (target, FWUPD_STATUS_DEVICE_READ); - - /* process each chunk */ - blobs = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref); - for (guint i = 0; i < chunks->len; i++) { - GBytes *blob_tmp = NULL; - const FuChunk *chk = g_ptr_array_index (chunks, i); - - /* select page if required */ - if (chk->page != page_last) { - if (fu_device_has_custom_flag (FU_DEVICE (dfu_target_get_device (target)), - "legacy-protocol")) { - if (!dfu_target_avr_select_memory_page (target, - chk->page, - error)) - return NULL; - } else { - if (!dfu_target_avr32_select_memory_page (target, - chk->page, - error)) - return NULL; - } - page_last = chk->page; - } - - /* prepare to read */ - if (!dfu_target_avr_read_memory (target, - chk->address, - chk->address + chk->data_sz - 1, - error)) - return NULL; - - /* upload data */ - g_debug ("requesting %i bytes from the hardware for chunk 0x%x", - ATMEL_MAX_TRANSFER_SIZE, i); - blob_tmp = dfu_target_upload_chunk (target, i, - ATMEL_MAX_TRANSFER_SIZE, - error); - if (blob_tmp == NULL) - return NULL; - g_ptr_array_add (blobs, blob_tmp); - - /* this page has valid data */ - if (!fu_common_bytes_is_empty (blob_tmp)) { - g_debug ("chunk %u has data (page %" G_GUINT32_FORMAT ")", - i, chk->page); - chunk_valid = i; - } else { - g_debug ("chunk %u is empty", i); - } - - /* update UI */ - dfu_target_set_percentage (target, i + 1, chunks->len); - } - - /* done */ - dfu_target_set_percentage_raw (target, 100); - dfu_target_set_action (target, FWUPD_STATUS_IDLE); - - /* truncate the image if any sectors are empty, i.e. all 0xff */ - if (chunk_valid == G_MAXUINT) { - g_debug ("all %u chunks are empty", blobs->len); - g_ptr_array_set_size (chunks, 0); - } else if (blobs->len != chunk_valid + 1) { - g_debug ("truncating chunks from %u to %u", - blobs->len, chunk_valid + 1); - g_ptr_array_set_size (blobs, chunk_valid + 1); - } - - /* create element of required size */ - contents = dfu_utils_bytes_join_array (blobs); - if (expected_size > 0 && g_bytes_get_size (contents) > expected_size) { - contents_truncated = g_bytes_new_from_bytes (contents, 0x0, expected_size); - } else { - contents_truncated = g_bytes_ref (contents); - } - - element = dfu_element_new (); - dfu_element_set_address (element, address | 0x80000000); /* flash */ - dfu_element_set_contents (element, contents_truncated); - return g_steal_pointer (&element); -} - -static void -dfu_target_avr_init (DfuTargetAvr *target_avr) -{ -} - -static void -dfu_target_avr_class_init (DfuTargetAvrClass *klass) -{ - DfuTargetClass *klass_target = DFU_TARGET_CLASS (klass); - klass_target->setup = dfu_target_avr_setup; - klass_target->attach = dfu_target_avr_attach; - klass_target->mass_erase = dfu_target_avr_mass_erase; - klass_target->upload_element = dfu_target_avr_upload_element; - klass_target->download_element = dfu_target_avr_download_element; -} - -DfuTarget * -dfu_target_avr_new (void) -{ - DfuTarget *target; - target = g_object_new (DFU_TYPE_TARGET_AVR, NULL); - return target; -} diff -Nru fwupd-1.4.5/plugins/dfu/dfu-target-avr.h fwupd-1.5.8/plugins/dfu/dfu-target-avr.h --- fwupd-1.4.5/plugins/dfu/dfu-target-avr.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/dfu-target-avr.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2017 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include -#include - -#include "dfu-target.h" - -#define DFU_TYPE_TARGET_AVR (dfu_target_avr_get_type ()) -G_DECLARE_DERIVABLE_TYPE (DfuTargetAvr, dfu_target_avr, DFU, TARGET_AVR, DfuTarget) - -struct _DfuTargetAvrClass -{ - DfuTargetClass parent_class; -}; - -DfuTarget *dfu_target_avr_new (void); diff -Nru fwupd-1.4.5/plugins/dfu/dfu-target.c fwupd-1.5.8/plugins/dfu/dfu-target.c --- fwupd-1.4.5/plugins/dfu/dfu-target.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/dfu-target.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1369 +0,0 @@ -/* - * Copyright (C) 2015-2017 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -/** - * SECTION:dfu-target - * @short_description: Object representing a DFU-capable target - * - * This object allows uploading and downloading an image onto a - * specific DFU-capable target. - * - * You only need to use this in preference to #DfuDevice if you only - * want to update one target on the device. Most users will want to - * update all the targets on the device at the same time. - * - * See also: #DfuDevice, #DfuImage - */ - -#include "config.h" - -#include -#include - -#include "dfu-common.h" -#include "dfu-device.h" -#include "dfu-sector.h" -#include "dfu-target-private.h" - -#include "fwupd-error.h" - -static void dfu_target_finalize (GObject *object); - -typedef struct { - DfuDevice *device; /* not refcounted */ - gboolean done_setup; - guint8 alt_setting; - guint8 alt_idx; - gchar *alt_name; - gchar *alt_name_for_display; - GPtrArray *sectors; /* of DfuSector */ - guint old_percentage; - FwupdStatus old_action; -} DfuTargetPrivate; - -enum { - SIGNAL_PERCENTAGE_CHANGED, - SIGNAL_ACTION_CHANGED, - SIGNAL_LAST -}; - -static guint signals [SIGNAL_LAST] = { 0 }; - -G_DEFINE_TYPE_WITH_PRIVATE (DfuTarget, dfu_target, G_TYPE_OBJECT) -#define GET_PRIVATE(o) (dfu_target_get_instance_private (o)) - -static void -dfu_target_class_init (DfuTargetClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - /** - * DfuTarget::percentage-changed: - * @device: the #DfuTarget instance that emitted the signal - * @percentage: the new percentage - * - * The ::percentage-changed signal is emitted when the percentage changes. - **/ - signals [SIGNAL_PERCENTAGE_CHANGED] = - g_signal_new ("percentage-changed", - G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (DfuTargetClass, percentage_changed), - NULL, NULL, g_cclosure_marshal_VOID__UINT, - G_TYPE_NONE, 1, G_TYPE_UINT); - - /** - * DfuTarget::action-changed: - * @device: the #DfuTarget instance that emitted the signal - * @action: the new FwupdStatus - * - * The ::action-changed signal is emitted when the high level action changes. - **/ - signals [SIGNAL_ACTION_CHANGED] = - g_signal_new ("action-changed", - G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (DfuTargetClass, action_changed), - NULL, NULL, g_cclosure_marshal_VOID__UINT, - G_TYPE_NONE, 1, G_TYPE_UINT); - - object_class->finalize = dfu_target_finalize; -} - -static void -dfu_target_init (DfuTarget *target) -{ - DfuTargetPrivate *priv = GET_PRIVATE (target); - priv->sectors = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - priv->old_percentage = G_MAXUINT; - priv->old_action = FWUPD_STATUS_IDLE; -} - -static void -dfu_target_finalize (GObject *object) -{ - DfuTarget *target = DFU_TARGET (object); - DfuTargetPrivate *priv = GET_PRIVATE (target); - - g_free (priv->alt_name); - g_free (priv->alt_name_for_display); - g_ptr_array_unref (priv->sectors); - - /* we no longer care */ - if (priv->device != NULL) { - g_object_remove_weak_pointer (G_OBJECT (priv->device), - (gpointer *) &priv->device); - } - - G_OBJECT_CLASS (dfu_target_parent_class)->finalize (object); -} - -static gchar * -dfu_target_sectors_to_string (DfuTarget *target) -{ - DfuTargetPrivate *priv = GET_PRIVATE (target); - GString *str = g_string_new (""); - for (guint i = 0; i < priv->sectors->len; i++) { - DfuSector *sector = g_ptr_array_index (priv->sectors, i); - g_autofree gchar *tmp = dfu_sector_to_string (sector); - g_string_append_printf (str, "%s\n", tmp); - } - if (str->len > 0) - g_string_truncate (str, str->len - 1); - return g_string_free (str, FALSE); -} - -DfuSector * -dfu_target_get_sector_for_addr (DfuTarget *target, guint32 addr) -{ - DfuTargetPrivate *priv = GET_PRIVATE (target); - - for (guint i = 0; i < priv->sectors->len; i++) { - DfuSector *sector = g_ptr_array_index (priv->sectors, i); - if (addr < dfu_sector_get_address (sector)) - continue; - if (addr > dfu_sector_get_address (sector) + - dfu_sector_get_size (sector)) - continue; - return sector; - } - return NULL; -} - -static gboolean -dfu_target_parse_sector (DfuTarget *target, - const gchar *dfuse_sector_id, - guint32 *addr, - guint16 zone, - guint16 number, - GError **error) -{ - DfuTargetPrivate *priv = GET_PRIVATE (target); - DfuSectorCap cap = DFU_SECTOR_CAP_NONE; - gchar *tmp; - guint32 addr_offset = 0; - guint64 nr_sectors; - guint64 sector_size; - - /* parse # of sectors */ - nr_sectors = g_ascii_strtoull (dfuse_sector_id, &tmp, 10); - if (nr_sectors > 999) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Invalid number of sectors: %s", - dfuse_sector_id); - return FALSE; - } - - /* check this is the delimiter */ - if (tmp[0] != '*') { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Invalid sector ID: %s", - dfuse_sector_id); - return FALSE; - } - - /* parse sector size */ - sector_size = g_ascii_strtoull (tmp + 1, &tmp, 10); - if (sector_size > 999) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Invalid sector size: %s", - dfuse_sector_id); - return FALSE; - } - - /* handle weirdness */ - if (fu_device_has_custom_flag (FU_DEVICE (dfu_target_get_device (target)), - "absent-sector-size")) { - if (tmp[1] == '\0') { - tmp[1] = tmp[0]; - tmp[0] = 'B'; - } - } - - /* get multiplier */ - switch (tmp[0]) { - case 'B': /* byte */ - case ' ': /* byte, ST reference bootloader :/ */ - break; - case 'K': /* Kilo */ - sector_size *= 0x400; - break; - case 'M': /* Mega */ - sector_size *= 0x100000 ; - break; - default: - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Invalid sector multiplier: %s", - tmp); - return FALSE; - } - - /* get sector type */ - switch (tmp[1]) { - case 'a': - cap = DFU_SECTOR_CAP_READABLE; - break; - case 'b': - cap = DFU_SECTOR_CAP_ERASEABLE; - break; - case 'c': - cap = DFU_SECTOR_CAP_READABLE | - DFU_SECTOR_CAP_ERASEABLE; - break; - case 'd': - cap = DFU_SECTOR_CAP_WRITEABLE; - break; - case 'e': - cap = DFU_SECTOR_CAP_READABLE | - DFU_SECTOR_CAP_WRITEABLE; - break; - case 'f': - cap = DFU_SECTOR_CAP_ERASEABLE | - DFU_SECTOR_CAP_WRITEABLE; - break; - case 'g': - cap = DFU_SECTOR_CAP_READABLE | - DFU_SECTOR_CAP_ERASEABLE | - DFU_SECTOR_CAP_WRITEABLE; - break; - default: - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Invalid sector type: %s", - tmp); - return FALSE; - } - - /* add all the sectors */ - for (guint i = 0; i < nr_sectors; i++) { - DfuSector *sector; - sector = dfu_sector_new (*addr + addr_offset, - (guint32) sector_size, - (guint32) ((nr_sectors * sector_size) - addr_offset), - zone, - number, - cap); - g_ptr_array_add (priv->sectors, sector); - addr_offset += dfu_sector_get_size (sector); - } - - /* update for next sector */ - *addr += addr_offset; - return TRUE; -} - -gboolean -dfu_target_parse_sectors (DfuTarget *target, const gchar *alt_name, GError **error) -{ - DfuTargetPrivate *priv = GET_PRIVATE (target); - g_autofree gchar *str_debug = NULL; - g_auto(GStrv) zones = NULL; - - /* not set */ - if (alt_name == NULL) - return TRUE; - - /* From the Neo Freerunner */ - if (g_str_has_prefix (alt_name, "RAM 0x")) { - DfuSector *sector; - guint64 addr_tmp; - addr_tmp = g_ascii_strtoull (alt_name + 6, NULL, 16); - if (addr_tmp == 0 || addr_tmp > G_MAXUINT32) - return FALSE; - g_debug ("RAM description, so parsing"); - sector = dfu_sector_new ((guint32) addr_tmp, - 0x0, /* size */ - 0x0, /* size_left */ - 0x0, /* zone */ - 0x0, /* number */ - DFU_SECTOR_CAP_READABLE | - DFU_SECTOR_CAP_WRITEABLE); - g_ptr_array_add (priv->sectors, sector); - } - - /* not a DfuSe alternative name */ - if (alt_name[0] != '@') - return TRUE; - - /* clear any existing zones */ - g_ptr_array_set_size (priv->sectors, 0); - - /* parse zones */ - zones = g_strsplit (alt_name, "/", -1); - g_free (priv->alt_name_for_display); - priv->alt_name_for_display = g_strdup (g_strchomp (zones[0] + 1)); - for (guint i = 1; zones[i] != NULL; i += 2) { - guint32 addr; - guint64 addr_tmp; - g_auto(GStrv) sectors = NULL; - - /* parse address */ - if (!g_str_has_prefix (zones[i], "0x")) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "No sector address"); - return FALSE; - } - addr_tmp = g_ascii_strtoull (zones[i] + 2, NULL, 16); - if (addr_tmp > G_MAXUINT32) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Sector address too large"); - return FALSE; - } - addr = (guint32) addr_tmp; - - /* no sectors?! */ - if (zones[i+1] == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "No sector section"); - return FALSE; - } - - /* parse sectors */ - sectors = g_strsplit (zones[i+1], ",", -1); - for (guint16 j = 0; sectors[j] != NULL; j++) { - if (!dfu_target_parse_sector (target, - sectors[j], - &addr, - (i - 1) / 2, j, - error)) { - g_prefix_error (error, - "Failed to parse: '%s': ", - sectors[j]); - return FALSE; - } - } - } - - /* success */ - str_debug = dfu_target_sectors_to_string (target); - g_debug ("%s", str_debug); - return TRUE; -} - -/** - * dfu_target_new: (skip) - * - * Creates a new DFU target, which represents an alt-setting on a - * DFU-capable device. - * - * Return value: a #DfuTarget - **/ -DfuTarget * -dfu_target_new (void) -{ - DfuTarget *target; - target = g_object_new (DFU_TYPE_TARGET, NULL); - return target; -} - -/** - * dfu_target_get_sectors: - * @target: a #GUsbDevice - * - * Gets the sectors exported by the target. - * - * Return value: (transfer none) (element-type DfuSector): sectors - **/ -GPtrArray * -dfu_target_get_sectors (DfuTarget *target) -{ - DfuTargetPrivate *priv = GET_PRIVATE (target); - g_return_val_if_fail (DFU_IS_TARGET (target), NULL); - return priv->sectors; -} - -/** - * dfu_target_get_sector_default: - * @target: a #GUsbDevice - * - * Gets the default (first) sector exported by the target. - * - * Return value: (transfer none): a #DfuSector, or %NULL - **/ -DfuSector * -dfu_target_get_sector_default (DfuTarget *target) -{ - DfuTargetPrivate *priv = GET_PRIVATE (target); - g_return_val_if_fail (DFU_IS_TARGET (target), NULL); - if (priv->sectors->len == 0) - return NULL; - return DFU_SECTOR (g_ptr_array_index (priv->sectors, 0)); -} - -/** - * dfu_target_status_to_error_msg: - * @status: a #DfuStatus, e.g. %DFU_STATUS_ERR_ERASE - * - * Converts an enumerated value to an error description. - * - * Return value: a string - **/ -static const gchar * -dfu_target_status_to_error_msg (DfuStatus status) -{ - if (status == DFU_STATUS_OK) - return "No error condition is present"; - if (status == DFU_STATUS_ERR_TARGET) - return "Firmware is not for designed this device"; - if (status == DFU_STATUS_ERR_FILE) - return "Firmware is for this device but fails verification"; - if (status == DFU_STATUS_ERR_WRITE) - return "Device is unable to write memory"; - if (status == DFU_STATUS_ERR_ERASE) - return "Memory erase function failed"; - if (status == DFU_STATUS_ERR_CHECK_ERASED) - return "Memory erase check failed"; - if (status == DFU_STATUS_ERR_PROG) - return "Program memory function failed"; - if (status == DFU_STATUS_ERR_VERIFY) - return "Programmed memory failed verification"; - if (status == DFU_STATUS_ERR_ADDRESS) - return "Cannot program memory due to address out of range"; - if (status == DFU_STATUS_ERR_NOTDONE) - return "Received zero-length download but data is incomplete"; - if (status == DFU_STATUS_ERR_FIRMWARE) - return "Device firmware is corrupt"; - if (status == DFU_STATUS_ERR_VENDOR) - return "Vendor-specific error"; - if (status == DFU_STATUS_ERR_USBR) - return "Device detected unexpected USB reset signaling"; - if (status == DFU_STATUS_ERR_POR) - return "Device detected unexpected power on reset"; - if (status == DFU_STATUS_ERR_UNKNOWN) - return "Something unexpected went wrong"; - if (status == DFU_STATUS_ERR_STALLDPKT) - return "Device stalled an unexpected request"; - return NULL; -} - -gboolean -dfu_target_check_status (DfuTarget *target, GError **error) -{ - DfuTargetPrivate *priv = GET_PRIVATE (target); - DfuStatus status; - - /* get the status */ - if (!dfu_device_refresh (priv->device, error)) - return FALSE; - - /* wait for dfuDNBUSY to not be set */ - if (dfu_device_get_version (priv->device) == DFU_VERSION_DFUSE) { - while (dfu_device_get_state (priv->device) == DFU_STATE_DFU_DNBUSY) { - g_debug ("waiting for DFU_STATE_DFU_DNBUSY to clear"); - g_usleep (dfu_device_get_download_timeout (priv->device) * 1000); - if (!dfu_device_refresh (priv->device, error)) - return FALSE; - } - } - - /* not in an error state */ - if (dfu_device_get_state (priv->device) != DFU_STATE_DFU_ERROR) - return TRUE; - - /* STM32-specific long errors */ - status = dfu_device_get_status (priv->device); - if (dfu_device_get_version (priv->device) == DFU_VERSION_DFUSE) { - if (status == DFU_STATUS_ERR_VENDOR) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Read protection is active"); - return FALSE; - } - if (status == DFU_STATUS_ERR_TARGET) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Address is wrong or unsupported"); - return FALSE; - } - } - - /* use a proper error description */ - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - dfu_target_status_to_error_msg (status)); - return FALSE; -} - -/** - * dfu_target_use_alt_setting: - * @target: a #DfuTarget - * @error: a #GError, or %NULL - * - * Opens a DFU-capable target. - * - * Return value: %TRUE for success - **/ -static gboolean -dfu_target_use_alt_setting (DfuTarget *target, GError **error) -{ - DfuTargetPrivate *priv = GET_PRIVATE (target); - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (priv->device)); - g_autoptr(GError) error_local = NULL; - - g_return_val_if_fail (DFU_IS_TARGET (target), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* ensure interface is claimed */ - if (!dfu_device_ensure_interface (priv->device, error)) - return FALSE; - - /* use the correct setting */ - if (fu_device_has_flag (FU_DEVICE (priv->device), FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { - if (!g_usb_device_set_interface_alt (usb_device, - (gint) dfu_device_get_interface (priv->device), - (gint) priv->alt_setting, - &error_local)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "cannot set alternate setting 0x%02x on interface %i: %s", - priv->alt_setting, - dfu_device_get_interface (priv->device), - error_local->message); - return FALSE; - } - } - - return TRUE; -} - -void -dfu_target_set_alt_name (DfuTarget *target, const gchar *alt_name) -{ - DfuTargetPrivate *priv = GET_PRIVATE (target); - g_free (priv->alt_name); - priv->alt_name = g_strdup (alt_name); -} - -void -dfu_target_set_device (DfuTarget *target, DfuDevice *device) -{ - DfuTargetPrivate *priv = GET_PRIVATE (target); - g_set_object (&priv->device, device); - - /* if we try to ref the target and destroy the device */ - g_object_add_weak_pointer (G_OBJECT (priv->device), - (gpointer *) &priv->device); -} - -/** - * dfu_target_setup: - * @target: a #DfuTarget - * @error: a #GError, or %NULL - * - * Opens a DFU-capable target. - * - * Return value: %TRUE for success - **/ -gboolean -dfu_target_setup (DfuTarget *target, GError **error) -{ - DfuTargetClass *klass = DFU_TARGET_GET_CLASS (target); - DfuTargetPrivate *priv = GET_PRIVATE (target); - - g_return_val_if_fail (DFU_IS_TARGET (target), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* already done */ - if (priv->done_setup) - return TRUE; - - /* superclassed */ - if (klass->setup != NULL) { - if (!klass->setup (target, error)) - return FALSE; - } - - /* get string */ - if (priv->alt_idx != 0x00 && priv->alt_name == NULL) { - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (priv->device)); - priv->alt_name = - g_usb_device_get_string_descriptor (usb_device, - priv->alt_idx, - NULL); - } - - /* parse the DfuSe format according to UM0424 */ - if (!dfu_target_parse_sectors (target, - priv->alt_name, - error)) - return FALSE; - - /* add a dummy entry */ - if (priv->sectors->len == 0) { - DfuSector *sector; - sector = dfu_sector_new (0x0, /* addr */ - 0x0, /* size */ - 0x0, /* size_left */ - 0x0, /* zone */ - 0x0, /* number */ - DFU_SECTOR_CAP_READABLE | - DFU_SECTOR_CAP_WRITEABLE); - g_debug ("no UM0424 sector description in %s", priv->alt_name); - g_ptr_array_add (priv->sectors, sector); - } - - priv->done_setup = TRUE; - return TRUE; -} - -/** - * dfu_target_mass_erase: - * @target: a #DfuTarget - * @error: a #GError, or %NULL - * - * Mass erases the device clearing all SRAM and EEPROM memory. - * - * IMPORTANT: This only works on STM32 devices from ST and AVR32 devices from Atmel. - * - * Return value: %TRUE for success - **/ -gboolean -dfu_target_mass_erase (DfuTarget *target, GError **error) -{ - DfuTargetClass *klass = DFU_TARGET_GET_CLASS (target); - if (!dfu_target_setup (target, error)) - return FALSE; - if (klass->mass_erase == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "mass erase not supported"); - return FALSE; - } - return klass->mass_erase (target, error); -} - -gboolean -dfu_target_download_chunk (DfuTarget *target, guint16 index, GBytes *bytes, GError **error) -{ - DfuTargetPrivate *priv = GET_PRIVATE (target); - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (priv->device)); - g_autoptr(GError) error_local = NULL; - gsize actual_length; - - /* low level packet debugging */ - if (g_getenv ("FWUPD_DFU_VERBOSE") != NULL) { - gsize sz = 0; - const guint8 *data = g_bytes_get_data (bytes, &sz); - for (gsize i = 0; i < sz; i++) - g_print ("Message: m[%" G_GSIZE_FORMAT "] = 0x%02x\n", i, (guint) data[i]); - } - - if (!g_usb_device_control_transfer (usb_device, - G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, - G_USB_DEVICE_REQUEST_TYPE_CLASS, - G_USB_DEVICE_RECIPIENT_INTERFACE, - DFU_REQUEST_DNLOAD, - index, - dfu_device_get_interface (priv->device), - (guint8 *) g_bytes_get_data (bytes, NULL), - g_bytes_get_size (bytes), - &actual_length, - dfu_device_get_timeout (priv->device), - NULL, - &error_local)) { - /* refresh the error code */ - dfu_device_error_fixup (priv->device, &error_local); - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "cannot download data: %s", - error_local->message); - return FALSE; - } - - /* for STM32 devices, the action only occurs when we do GetStatus */ - if (dfu_device_get_version (priv->device) == DFU_VERSION_DFUSE) { - if (!dfu_device_refresh (priv->device, error)) - return FALSE; - } - - /* wait for the device to write contents to the EEPROM */ - if (g_bytes_get_size (bytes) == 0 && - dfu_device_get_download_timeout (priv->device) > 0) { - dfu_target_set_action (target, FWUPD_STATUS_IDLE); - dfu_target_set_action (target, FWUPD_STATUS_DEVICE_BUSY); - } - if (dfu_device_get_download_timeout (priv->device) > 0) { - g_debug ("sleeping for %ums…", - dfu_device_get_download_timeout (priv->device)); - g_usleep (dfu_device_get_download_timeout (priv->device) * 1000); - } - - /* find out if the write was successful */ - if (!dfu_device_refresh (priv->device, error)) - return FALSE; - - g_assert (actual_length == g_bytes_get_size (bytes)); - return TRUE; -} - -GBytes * -dfu_target_upload_chunk (DfuTarget *target, guint16 index, gsize buf_sz, GError **error) -{ - DfuTargetPrivate *priv = GET_PRIVATE (target); - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (priv->device)); - g_autoptr(GError) error_local = NULL; - guint8 *buf; - gsize actual_length; - - /* unset */ - if (buf_sz == 0) - buf_sz = (gsize) dfu_device_get_transfer_size (priv->device); - - buf = g_new0 (guint8, buf_sz); - if (!g_usb_device_control_transfer (usb_device, - G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, - G_USB_DEVICE_REQUEST_TYPE_CLASS, - G_USB_DEVICE_RECIPIENT_INTERFACE, - DFU_REQUEST_UPLOAD, - index, - dfu_device_get_interface (priv->device), - buf, buf_sz, - &actual_length, - dfu_device_get_timeout (priv->device), - NULL, - &error_local)) { - /* refresh the error code */ - dfu_device_error_fixup (priv->device, &error_local); - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "cannot upload data: %s", - error_local->message); - return NULL; - } - - /* low level packet debugging */ - if (g_getenv ("FWUPD_DFU_VERBOSE") != NULL) { - for (gsize i = 0; i < actual_length; i++) - g_print ("Message: r[%" G_GSIZE_FORMAT "] = 0x%02x\n", i, (guint) buf[i]); - } - - return g_bytes_new_take (buf, actual_length); -} - -void -dfu_target_set_alt_idx (DfuTarget *target, guint8 alt_idx) -{ - DfuTargetPrivate *priv = GET_PRIVATE (target); - priv->alt_idx = alt_idx; -} - -void -dfu_target_set_alt_setting (DfuTarget *target, guint8 alt_setting) -{ - DfuTargetPrivate *priv = GET_PRIVATE (target); - priv->alt_setting = alt_setting; -} - -void -dfu_target_set_action (DfuTarget *target, FwupdStatus action) -{ - DfuTargetPrivate *priv = GET_PRIVATE (target); - - /* unchanged */ - if (priv->old_action == action) - return; - if (priv->old_action != FWUPD_STATUS_IDLE && - action != FWUPD_STATUS_IDLE) { - g_debug ("ignoring action %s as %s already set and not idle", - fwupd_status_to_string (action), - fwupd_status_to_string (priv->old_action)); - return; - } - g_debug ("setting action %s", fwupd_status_to_string (action)); - g_signal_emit (target, signals[SIGNAL_ACTION_CHANGED], 0, action); - priv->old_action = action; -} - -DfuDevice * -dfu_target_get_device (DfuTarget *target) -{ - DfuTargetPrivate *priv = GET_PRIVATE (target); - return priv->device; -} - -void -dfu_target_set_percentage_raw (DfuTarget *target, guint percentage) -{ - DfuTargetPrivate *priv = GET_PRIVATE (target); - if (percentage == priv->old_percentage) - return; - g_debug ("setting percentage %u%% of %s", - percentage, fwupd_status_to_string (priv->old_action)); - g_signal_emit (target, - signals[SIGNAL_PERCENTAGE_CHANGED], - 0, percentage); - priv->old_percentage = percentage; -} - -void -dfu_target_set_percentage (DfuTarget *target, guint value, guint total) -{ - guint percentage; - - g_return_if_fail (total > 0); - - percentage = (value * 100) / total; - if (percentage >= 100) - return; - dfu_target_set_percentage_raw (target, percentage); -} - -gboolean -dfu_target_attach (DfuTarget *target, GError **error) -{ - DfuTargetPrivate *priv = GET_PRIVATE (target); - DfuTargetClass *klass = DFU_TARGET_GET_CLASS (target); - - /* ensure populated */ - if (!dfu_target_setup (target, error)) - return FALSE; - - /* implemented as part of a superclass */ - if (klass->attach != NULL) - return klass->attach (target, error); - - /* normal DFU mode just needs a bus reset */ - return dfu_device_reset (priv->device, error); -} - -static DfuElement * -dfu_target_upload_element_dfu (DfuTarget *target, - guint32 address, - gsize expected_size, - gsize maximum_size, - GError **error) -{ - DfuTargetPrivate *priv = GET_PRIVATE (target); - DfuElement *element = NULL; - GBytes *chunk_tmp; - guint32 offset = 0; - guint percentage_size = expected_size > 0 ? expected_size : maximum_size; - gsize total_size = 0; - guint16 transfer_size = dfu_device_get_transfer_size (priv->device); - g_autoptr(GBytes) contents = NULL; - g_autoptr(GPtrArray) chunks = NULL; - - /* update UI */ - dfu_target_set_action (target, FWUPD_STATUS_DEVICE_READ); - - /* get all the chunks from the hardware */ - chunks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref); - for (guint16 idx = 0; idx < G_MAXUINT16; idx++) { - guint32 chunk_size; - - /* read chunk of data */ - chunk_tmp = dfu_target_upload_chunk (target, - idx, - 0, /* device transfer size */ - error); - if (chunk_tmp == NULL) - return NULL; - - /* keep a sum of all the chunks */ - chunk_size = (guint32) g_bytes_get_size (chunk_tmp); - total_size += chunk_size; - offset += chunk_size; - - /* add to array */ - g_debug ("got #%04x chunk of size %" G_GUINT32_FORMAT, - idx, chunk_size); - g_ptr_array_add (chunks, chunk_tmp); - - /* update UI */ - if (chunk_size > 0) - dfu_target_set_percentage (target, total_size, percentage_size); - - /* detect short write as EOF */ - if (chunk_size < transfer_size) - break; - } - - /* check final size */ - if (expected_size > 0) { - if (total_size != expected_size) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "invalid size, got %" G_GSIZE_FORMAT ", " - "expected %" G_GSIZE_FORMAT , - total_size, expected_size); - return NULL; - } - } - - /* done */ - dfu_target_set_percentage_raw (target, 100); - dfu_target_set_action (target, FWUPD_STATUS_IDLE); - - /* create new image */ - contents = dfu_utils_bytes_join_array (chunks); - element = dfu_element_new (); - dfu_element_set_contents (element, contents); - return element; -} - -static DfuElement * -dfu_target_upload_element (DfuTarget *target, - guint32 address, - gsize expected_size, - gsize maximum_size, - GError **error) -{ - DfuTargetClass *klass = DFU_TARGET_GET_CLASS (target); - - /* implemented as part of a superclass */ - if (klass->upload_element != NULL) { - return klass->upload_element (target, address, expected_size, - maximum_size, error); - } - return dfu_target_upload_element_dfu (target, - address, - expected_size, - maximum_size, - error); -} - -static guint32 -dfu_target_get_size_of_zone (DfuTarget *target, guint16 zone) -{ - DfuTargetPrivate *priv = GET_PRIVATE (target); - guint32 len = 0; - for (guint i = 0; i < priv->sectors->len; i++) { - DfuSector *sector = g_ptr_array_index (priv->sectors, i); - if (dfu_sector_get_zone (sector) != zone) - continue; - len += dfu_sector_get_size (sector); - } - return len; -} - -/** - * dfu_target_upload: - * @target: a #DfuTarget - * @flags: flags to use, e.g. %DFU_TARGET_TRANSFER_FLAG_VERIFY - * @error: a #GError, or %NULL - * - * Uploads firmware from the target to the host. - * - * Return value: (transfer full): the uploaded image, or %NULL for error - **/ -DfuImage * -dfu_target_upload (DfuTarget *target, - DfuTargetTransferFlags flags, - GError **error) -{ - DfuTargetPrivate *priv = GET_PRIVATE (target); - DfuSector *sector; - guint16 zone_cur; - guint32 zone_size = 0; - guint32 zone_last = G_MAXUINT; - g_autoptr(DfuImage) image = NULL; - - g_return_val_if_fail (DFU_IS_TARGET (target), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - /* ensure populated */ - if (!dfu_target_setup (target, error)) - return NULL; - - /* can the target do this? */ - if (!dfu_device_can_upload (priv->device)) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "target cannot do uploading"); - return NULL; - } - - /* use correct alt */ - if (!dfu_target_use_alt_setting (target, error)) - return NULL; - - /* no open?! */ - if (priv->sectors->len == 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "no sectors defined for target"); - return NULL; - } - - /* create a new image */ - image = dfu_image_new (); - dfu_image_set_name (image, priv->alt_name); - dfu_image_set_alt_setting (image, priv->alt_setting); - - /* get all the sectors for the device */ - for (guint i = 0; i < priv->sectors->len; i++) { - g_autoptr(DfuElement) element = NULL; - - /* only upload to the start of any zone:sector */ - sector = g_ptr_array_index (priv->sectors, i); - zone_cur = dfu_sector_get_zone (sector); - if (zone_cur == zone_last) - continue; - - /* get the size of the entire continuous zone */ - zone_size = dfu_target_get_size_of_zone (target, zone_cur); - zone_last = zone_cur; - - /* get the first element from the hardware */ - g_debug ("starting upload from 0x%08x (0x%04x)", - dfu_sector_get_address (sector), - zone_size); - element = dfu_target_upload_element (target, - dfu_sector_get_address (sector), - 0, /* expected */ - zone_size, /* maximum */ - error); - if (element == NULL) - return NULL; - - /* this element was uploaded okay */ - dfu_image_add_element (image, element); - } - - /* success */ - return g_object_ref (image); -} - -static gchar * -_g_bytes_compare_verbose (GBytes *bytes1, GBytes *bytes2) -{ - const guint8 *data1; - const guint8 *data2; - gsize length1; - gsize length2; - - data1 = g_bytes_get_data (bytes1, &length1); - data2 = g_bytes_get_data (bytes2, &length2); - - /* not the same length */ - if (length1 != length2) { - return g_strdup_printf ("got %" G_GSIZE_FORMAT " bytes, " - "expected %" G_GSIZE_FORMAT, - length1, length2); - } - - /* return 00 01 02 03 */ - for (guint i = 0; i < length1; i++) { - if (data1[i] != data2[i]) { - return g_strdup_printf ("got 0x%02x, expected 0x%02x @ 0x%04x", - data1[i], data2[i], i); - } - } - return NULL; -} - -static gboolean -dfu_target_download_element_dfu (DfuTarget *target, - DfuElement *element, - DfuTargetTransferFlags flags, - GError **error) -{ - DfuTargetPrivate *priv = GET_PRIVATE (target); - GBytes *bytes; - guint16 nr_chunks; - guint16 transfer_size = dfu_device_get_transfer_size (priv->device); - - /* round up as we have to transfer incomplete blocks */ - bytes = dfu_element_get_contents (element); - nr_chunks = (guint) ceil ((gdouble) g_bytes_get_size (bytes) / - (gdouble) transfer_size); - if (nr_chunks == 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "zero-length firmware"); - return FALSE; - } - dfu_target_set_action (target, FWUPD_STATUS_DEVICE_WRITE); - for (guint16 i = 0; i < nr_chunks + 1; i++) { - gsize length; - guint32 offset; - g_autoptr(GBytes) bytes_tmp = NULL; - - /* caclulate the offset into the element data */ - offset = i * transfer_size; - - /* we have to write one final zero-sized chunk for EOF */ - if (i < nr_chunks) { - length = g_bytes_get_size (bytes) - offset; - if (length > transfer_size) - length = transfer_size; - bytes_tmp = g_bytes_new_from_bytes (bytes, offset, length); - } else { - bytes_tmp = g_bytes_new (NULL, 0); - } - g_debug ("writing #%04x chunk of size %" G_GSIZE_FORMAT, - i, g_bytes_get_size (bytes_tmp)); - if (!dfu_target_download_chunk (target, i, bytes_tmp, error)) - return FALSE; - - /* update UI */ - dfu_target_set_percentage (target, offset, g_bytes_get_size (bytes)); - } - - /* done */ - dfu_target_set_percentage_raw (target, 100); - dfu_target_set_action (target, FWUPD_STATUS_IDLE); - - /* success */ - return TRUE; -} - -static gboolean -dfu_target_download_element (DfuTarget *target, - DfuElement *element, - DfuTargetTransferFlags flags, - GError **error) -{ - DfuTargetPrivate *priv = GET_PRIVATE (target); - DfuTargetClass *klass = DFU_TARGET_GET_CLASS (target); - - /* implemented as part of a superclass */ - if (klass->download_element != NULL) { - if (!klass->download_element (target, element, flags, error)) - return FALSE; - } else { - if (!dfu_target_download_element_dfu (target, - element, - flags, - error)) - return FALSE; - } - - /* verify */ - if (flags & DFU_TARGET_TRANSFER_FLAG_VERIFY && - dfu_device_has_attribute (priv->device, DFU_DEVICE_ATTRIBUTE_CAN_UPLOAD)) { - GBytes *bytes; - GBytes *bytes_tmp; - g_autoptr(DfuElement) element_tmp = NULL; - dfu_target_set_action (target, FWUPD_STATUS_DEVICE_VERIFY); - bytes = dfu_element_get_contents (element); - element_tmp = dfu_target_upload_element (target, - dfu_element_get_address (element), - g_bytes_get_size (bytes), - g_bytes_get_size (bytes), - error); - if (element_tmp == NULL) - return FALSE; - bytes_tmp = dfu_element_get_contents (element_tmp); - if (g_bytes_compare (bytes_tmp, bytes) != 0) { - g_autofree gchar *bytes_cmp_str = NULL; - bytes_cmp_str = _g_bytes_compare_verbose (bytes_tmp, bytes); - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_READ, - "verify failed: %s", - bytes_cmp_str); - return FALSE; - } - dfu_target_set_action (target, FWUPD_STATUS_IDLE); - } - - return TRUE; -} - -/** - * dfu_target_download: - * @target: a #DfuTarget - * @image: a #DfuImage - * @flags: flags to use, e.g. %DFU_TARGET_TRANSFER_FLAG_VERIFY - * @error: a #GError, or %NULL - * - * Downloads firmware from the host to the target, optionally verifying - * the transfer. - * - * Return value: %TRUE for success - **/ -gboolean -dfu_target_download (DfuTarget *target, DfuImage *image, - DfuTargetTransferFlags flags, GError **error) -{ - DfuTargetPrivate *priv = GET_PRIVATE (target); - GPtrArray *elements; - gboolean ret; - - g_return_val_if_fail (DFU_IS_TARGET (target), FALSE); - g_return_val_if_fail (DFU_IS_IMAGE (image), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* ensure populated */ - if (!dfu_target_setup (target, error)) - return FALSE; - - /* can the target do this? */ - if (!dfu_device_can_download (priv->device)) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "target cannot do downloading"); - return FALSE; - } - - /* use correct alt */ - if (!dfu_target_use_alt_setting (target, error)) - return FALSE; - - /* download all elements in the image to the device */ - elements = dfu_image_get_elements (image); - if (elements->len == 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "no image elements"); - return FALSE; - } - for (guint i = 0; i < elements->len; i++) { - DfuElement *element = dfu_image_get_element (image, (guint8) i); - g_debug ("downloading element at 0x%04x", - dfu_element_get_address (element)); - - /* auto-detect missing firmware address -- this assumes - * that the first target is the main program memory and that - * there is only one element in the firmware file */ - if (flags & DFU_TARGET_TRANSFER_FLAG_ADDR_HEURISTIC && - dfu_element_get_address (element) == 0x0 && - elements->len == 1 && - priv->sectors->len > 0) { - DfuSector *sector = g_ptr_array_index (priv->sectors, 0); - g_debug ("fixing up firmware address from 0x0 to 0x%x", - dfu_sector_get_address (sector)); - dfu_element_set_address (element, dfu_sector_get_address (sector)); - } - - /* download to device */ - ret = dfu_target_download_element (target, - element, - flags, - error); - if (!ret) - return FALSE; - } - - /* success */ - return TRUE; -} - -/** - * dfu_target_get_alt_setting: - * @target: a #DfuTarget - * - * Gets the alternate setting to use for this interface. - * - * Return value: the alternative setting, typically zero - **/ -guint8 -dfu_target_get_alt_setting (DfuTarget *target) -{ - DfuTargetPrivate *priv = GET_PRIVATE (target); - g_return_val_if_fail (DFU_IS_TARGET (target), 0xff); - return priv->alt_setting; -} - -/** - * dfu_target_get_alt_name: - * @target: a #DfuTarget - * @error: a #GError, or %NULL - * - * Gets the alternate setting name to use for this interface. - * - * Return value: the alternative setting name, typically %NULL - **/ -const gchar * -dfu_target_get_alt_name (DfuTarget *target, GError **error) -{ - DfuTargetPrivate *priv = GET_PRIVATE (target); - g_return_val_if_fail (DFU_IS_TARGET (target), NULL); - - /* ensure populated */ - if (!dfu_target_setup (target, error)) - return NULL; - - /* nothing */ - if (priv->alt_name == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "no alt-name"); - return NULL; - } - - return priv->alt_name; -} - -/** - * dfu_target_get_alt_name_for_display: - * @target: a #DfuTarget - * @error: a #GError, or %NULL - * - * Gets the alternate setting name to use for this interface that can be - * shown on the display. - * - * Return value: the alternative setting name - **/ -const gchar * -dfu_target_get_alt_name_for_display (DfuTarget *target, GError **error) -{ - DfuTargetPrivate *priv = GET_PRIVATE (target); - g_return_val_if_fail (DFU_IS_TARGET (target), NULL); - - /* ensure populated */ - if (!dfu_target_setup (target, error)) - return NULL; - - /* nothing */ - if (priv->alt_name_for_display == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "no alt-name for display"); - return NULL; - } - - return priv->alt_name_for_display; -} diff -Nru fwupd-1.4.5/plugins/dfu/dfu-target.h fwupd-1.5.8/plugins/dfu/dfu-target.h --- fwupd-1.4.5/plugins/dfu/dfu-target.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/dfu-target.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2015-2017 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include -#include -#include - -#include "dfu-common.h" -#include "dfu-image.h" -#include "dfu-sector.h" - -#include "fwupd-enums.h" - -#define DFU_TYPE_TARGET (dfu_target_get_type ()) -G_DECLARE_DERIVABLE_TYPE (DfuTarget, dfu_target, DFU, TARGET, GUsbDevice) - -/** - * DfuTargetTransferFlags: - * @DFU_TARGET_TRANSFER_FLAG_NONE: No flags set - * @DFU_TARGET_TRANSFER_FLAG_VERIFY: Verify the download once complete - * @DFU_TARGET_TRANSFER_FLAG_WILDCARD_VID: Allow downloading images with wildcard VIDs - * @DFU_TARGET_TRANSFER_FLAG_WILDCARD_PID: Allow downloading images with wildcard PIDs - * @DFU_TARGET_TRANSFER_FLAG_ADDR_HEURISTIC: Automatically detect the address to use - * - * The optional flags used for transferring firmware. - **/ -typedef enum { - DFU_TARGET_TRANSFER_FLAG_NONE = 0, - DFU_TARGET_TRANSFER_FLAG_VERIFY = (1 << 0), - DFU_TARGET_TRANSFER_FLAG_WILDCARD_VID = (1 << 4), - DFU_TARGET_TRANSFER_FLAG_WILDCARD_PID = (1 << 5), - DFU_TARGET_TRANSFER_FLAG_ADDR_HEURISTIC = (1 << 7), - /*< private >*/ - DFU_TARGET_TRANSFER_FLAG_LAST -} DfuTargetTransferFlags; - -struct _DfuTargetClass -{ - GUsbDeviceClass parent_class; - void (*percentage_changed) (DfuTarget *target, - guint percentage); - void (*action_changed) (DfuTarget *target, - FwupdStatus action); - gboolean (*setup) (DfuTarget *target, - GError **error); - gboolean (*attach) (DfuTarget *target, - GError **error); - gboolean (*detach) (DfuTarget *target, - GError **error); - gboolean (*mass_erase) (DfuTarget *target, - GError **error); - DfuElement *(*upload_element) (DfuTarget *target, - guint32 address, - gsize expected_size, - gsize maximum_size, - GError **error); - gboolean (*download_element) (DfuTarget *target, - DfuElement *element, - DfuTargetTransferFlags flags, - GError **error); -}; - -GPtrArray *dfu_target_get_sectors (DfuTarget *target); -DfuSector *dfu_target_get_sector_default (DfuTarget *target); -guint8 dfu_target_get_alt_setting (DfuTarget *target); -const gchar *dfu_target_get_alt_name (DfuTarget *target, - GError **error); -const gchar *dfu_target_get_alt_name_for_display (DfuTarget *target, - GError **error); -DfuImage *dfu_target_upload (DfuTarget *target, - DfuTargetTransferFlags flags, - GError **error); -gboolean dfu_target_setup (DfuTarget *target, - GError **error); -gboolean dfu_target_download (DfuTarget *target, - DfuImage *image, - DfuTargetTransferFlags flags, - GError **error); -gboolean dfu_target_mass_erase (DfuTarget *target, - GError **error); diff -Nru fwupd-1.4.5/plugins/dfu/dfu-target-private.h fwupd-1.5.8/plugins/dfu/dfu-target-private.h --- fwupd-1.4.5/plugins/dfu/dfu-target-private.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/dfu-target-private.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2015 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include - -#include "dfu-device.h" -#include "dfu-target.h" -#include "dfu-sector.h" - - -DfuTarget *dfu_target_new (void); - -GBytes *dfu_target_upload_chunk (DfuTarget *target, - guint16 index, - gsize buf_sz, - GError **error); -gboolean dfu_target_download_chunk (DfuTarget *target, - guint16 index, - GBytes *bytes, - GError **error); -gboolean dfu_target_attach (DfuTarget *target, - GError **error); -void dfu_target_set_alt_idx (DfuTarget *target, - guint8 alt_idx); -void dfu_target_set_alt_setting (DfuTarget *target, - guint8 alt_setting); - -/* for the other implementations */ -void dfu_target_set_action (DfuTarget *target, - FwupdStatus action); -void dfu_target_set_percentage_raw (DfuTarget *target, - guint percentage); -void dfu_target_set_percentage (DfuTarget *target, - guint value, - guint total); -void dfu_target_set_alt_name (DfuTarget *target, - const gchar *alt_name); -void dfu_target_set_device (DfuTarget *target, - DfuDevice *device); -DfuDevice *dfu_target_get_device (DfuTarget *target); -gboolean dfu_target_check_status (DfuTarget *target, - GError **error); -DfuSector *dfu_target_get_sector_for_addr (DfuTarget *target, - guint32 addr); - -/* export this just for the self tests */ -gboolean dfu_target_parse_sectors (DfuTarget *target, - const gchar *alt_name, - GError **error); diff -Nru fwupd-1.4.5/plugins/dfu/dfu-target-stm.c fwupd-1.5.8/plugins/dfu/dfu-target-stm.c --- fwupd-1.4.5/plugins/dfu/dfu-target-stm.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/dfu-target-stm.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,398 +0,0 @@ -/* - * Copyright (C) 2017 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include -#include -#include - -#include "dfu-common.h" -#include "dfu-sector.h" -#include "dfu-target-stm.h" -#include "dfu-target-private.h" - -#include "fwupd-error.h" - -G_DEFINE_TYPE (DfuTargetStm, dfu_target_stm, DFU_TYPE_TARGET) - -/* STMicroelectronics STM32 version of DFU: - * www.st.com/resource/en/application_note/cd00264379.pdf */ -#define DFU_STM_CMD_GET_COMMAND 0x00 -#define DFU_STM_CMD_SET_ADDRESS_POINTER 0x21 -#define DFU_STM_CMD_ERASE 0x41 -#define DFU_STM_CMD_READ_UNPROTECT 0x92 - -static gboolean -dfu_target_stm_attach (DfuTarget *target, GError **error) -{ - /* downloading empty payload will cause a dfu to leave, - * the returned status will be dfuMANIFEST and expect the device to disconnect */ - g_autoptr(GBytes) bytes_tmp = g_bytes_new (NULL, 0); - return dfu_target_download_chunk (target, 2, bytes_tmp, error); -} - -static gboolean -dfu_target_stm_mass_erase (DfuTarget *target, GError **error) -{ - GBytes *data_in; - guint8 buf[1]; - - /* format buffer */ - buf[0] = DFU_STM_CMD_ERASE; - data_in = g_bytes_new_static (buf, sizeof(buf)); - if (!dfu_target_download_chunk (target, 0, data_in, error)) { - g_prefix_error (error, "cannot mass-erase: "); - return FALSE; - } - - /* 2nd check required to get error code */ - return dfu_target_check_status (target, error); -} - -/** - * dfu_target_stm_set_address: - * @target: a #DfuTarget - * @address: memory address - * @error: a #GError, or %NULL - * - * Sets the address used for the next download or upload request. - * - * Return value: %TRUE for success - **/ -static gboolean -dfu_target_stm_set_address (DfuTarget *target, guint32 address, GError **error) -{ - GBytes *data_in; - guint8 buf[5]; - - /* format buffer */ - buf[0] = DFU_STM_CMD_SET_ADDRESS_POINTER; - memcpy (buf + 1, &address, 4); - data_in = g_bytes_new_static (buf, sizeof(buf)); - if (!dfu_target_download_chunk (target, 0, data_in, error)) { - g_prefix_error (error, "cannot set address 0x%x: ", address); - return FALSE; - } - - /* 2nd check required to get error code */ - g_debug ("doing actual check status"); - return dfu_target_check_status (target, error); -} - -static DfuElement * -dfu_target_stm_upload_element (DfuTarget *target, - guint32 address, - gsize expected_size, - gsize maximum_size, - GError **error) -{ - DfuDevice *device = dfu_target_get_device (target); - DfuSector *sector; - DfuElement *element = NULL; - GBytes *chunk_tmp; - guint32 offset = address; - guint percentage_size = expected_size > 0 ? expected_size : maximum_size; - gsize total_size = 0; - guint16 transfer_size = dfu_device_get_transfer_size (device); - g_autoptr(GBytes) contents = NULL; - g_autoptr(GBytes) contents_truncated = NULL; - g_autoptr(GPtrArray) chunks = NULL; - - /* for DfuSe devices we need to handle the address manually */ - sector = dfu_target_get_sector_for_addr (target, offset); - if (sector == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "no memory sector at 0x%04x", - (guint) offset); - return NULL; - } - g_debug ("using sector %u for read of %x", - dfu_sector_get_id (sector), - offset); - if (!dfu_sector_has_cap (sector, DFU_SECTOR_CAP_READABLE)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "memory sector at 0x%04x is not readable", - (guint) offset); - return NULL; - } - - /* update UI */ - dfu_target_set_action (target, FWUPD_STATUS_DEVICE_READ); - - /* manually set the sector address */ - g_debug ("setting DfuSe address to 0x%04x", (guint) offset); - if (!dfu_target_stm_set_address (target, offset, error)) - return NULL; - - /* abort back to IDLE */ - if (!dfu_device_abort (device, error)) - return NULL; - - /* get all the chunks from the hardware */ - chunks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref); - for (guint16 idx = 0; idx < G_MAXUINT16; idx++) { - guint32 chunk_size; - - /* read chunk of data -- ST uses wBlockNum=0 for DfuSe commands - * and wBlockNum=1 is reserved */ - chunk_tmp = dfu_target_upload_chunk (target, - idx + 2, - 0, /* device transfer size */ - error); - if (chunk_tmp == NULL) - return NULL; - - /* add to array */ - chunk_size = (guint32) g_bytes_get_size (chunk_tmp); - g_debug ("got #%04x chunk @0x%x of size %" G_GUINT32_FORMAT, - idx, offset, chunk_size); - g_ptr_array_add (chunks, chunk_tmp); - total_size += chunk_size; - offset += chunk_size; - - /* update UI */ - if (chunk_size > 0) - dfu_target_set_percentage (target, total_size, percentage_size); - - /* detect short write as EOF */ - if (chunk_size < transfer_size) - break; - - /* more data than we needed */ - if (maximum_size > 0 && total_size > maximum_size) - break; - } - - /* abort back to IDLE */ - if (!dfu_device_abort (device, error)) - return NULL; - - /* check final size */ - if (expected_size > 0) { - if (total_size < expected_size) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "invalid size, got %" G_GSIZE_FORMAT ", " - "expected %" G_GSIZE_FORMAT , - total_size, expected_size); - return NULL; - } - } - - /* done */ - dfu_target_set_percentage_raw (target, 100); - dfu_target_set_action (target, FWUPD_STATUS_IDLE); - - /* create new image */ - contents = dfu_utils_bytes_join_array (chunks); - if (expected_size > 0) - contents_truncated = g_bytes_new_from_bytes (contents, 0, expected_size); - else - contents_truncated = g_bytes_ref (contents); - element = dfu_element_new (); - dfu_element_set_contents (element, contents_truncated); - dfu_element_set_address (element, address); - return element; -} - -/** - * dfu_target_stm_erase_address: - * @target: a #DfuTarget - * @address: memory address - * @error: a #GError, or %NULL - * - * Erases a memory sector at a given address. - * - * Return value: %TRUE for success - **/ -static gboolean -dfu_target_stm_erase_address (DfuTarget *target, guint32 address, GError **error) -{ - GBytes *data_in; - guint8 buf[5]; - - /* format buffer */ - buf[0] = DFU_STM_CMD_ERASE; - memcpy (buf + 1, &address, 4); - data_in = g_bytes_new_static (buf, sizeof(buf)); - if (!dfu_target_download_chunk (target, 0, data_in, error)) { - g_prefix_error (error, "cannot erase address 0x%x: ", address); - return FALSE; - } - - /* 2nd check required to get error code */ - g_debug ("doing actual check status"); - return dfu_target_check_status (target, error); -} - -static gboolean -dfu_target_stm_download_element (DfuTarget *target, - DfuElement *element, - DfuTargetTransferFlags flags, - GError **error) -{ - DfuDevice *device = dfu_target_get_device (target); - DfuSector *sector; - GBytes *bytes; - guint nr_chunks; - guint zone_last = G_MAXUINT; - guint16 transfer_size = dfu_device_get_transfer_size (device); - g_autoptr(GPtrArray) sectors_array = NULL; - g_autoptr(GHashTable) sectors_hash = NULL; - - /* round up as we have to transfer incomplete blocks */ - bytes = dfu_element_get_contents (element); - nr_chunks = (guint) ceil ((gdouble) g_bytes_get_size (bytes) / - (gdouble) transfer_size); - if (nr_chunks == 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "zero-length firmware"); - return FALSE; - } - - /* 1st pass: work out which sectors need erasing */ - sectors_array = g_ptr_array_new (); - sectors_hash = g_hash_table_new (g_direct_hash, g_direct_equal); - for (guint i = 0; i < nr_chunks; i++) { - guint32 offset_dev; - - /* for DfuSe devices we need to handle the erase and setting - * the sectory address manually */ - offset_dev = dfu_element_get_address (element) + (i * transfer_size); - sector = dfu_target_get_sector_for_addr (target, offset_dev); - if (sector == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "no memory sector at 0x%04x", - (guint) offset_dev); - return FALSE; - } - if (!dfu_sector_has_cap (sector, DFU_SECTOR_CAP_WRITEABLE)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "memory sector at 0x%04x is not writable", - (guint) offset_dev); - return FALSE; - } - - /* if it's erasable and not yet blanked */ - if (dfu_sector_has_cap (sector, DFU_SECTOR_CAP_ERASEABLE) && - g_hash_table_lookup (sectors_hash, sector) == NULL) { - g_hash_table_insert (sectors_hash, - sector, - GINT_TO_POINTER (1)); - g_ptr_array_add (sectors_array, sector); - g_debug ("marking sector 0x%04x-%04x to be erased", - dfu_sector_get_address (sector), - dfu_sector_get_address (sector) + dfu_sector_get_size (sector)); - } - } - - /* 2nd pass: actually erase sectors */ - dfu_target_set_action (target, FWUPD_STATUS_DEVICE_ERASE); - for (guint i = 0; i < sectors_array->len; i++) { - sector = g_ptr_array_index (sectors_array, i); - g_debug ("erasing sector at 0x%04x", - dfu_sector_get_address (sector)); - if (!dfu_target_stm_erase_address (target, - dfu_sector_get_address (sector), - error)) - return FALSE; - dfu_target_set_percentage (target, i + 1, sectors_array->len); - } - dfu_target_set_percentage_raw (target, 100); - dfu_target_set_action (target, FWUPD_STATUS_IDLE); - - /* 3rd pass: write data */ - dfu_target_set_action (target, FWUPD_STATUS_DEVICE_WRITE); - for (guint i = 0; i < nr_chunks; i++) { - gsize length; - guint32 offset; - guint32 offset_dev; - g_autoptr(GBytes) bytes_tmp = NULL; - - /* caclulate the offset into the element data */ - offset = i * transfer_size; - offset_dev = dfu_element_get_address (element) + offset; - - /* for DfuSe devices we need to set the address manually */ - sector = dfu_target_get_sector_for_addr (target, offset_dev); - g_assert (sector != NULL); - - /* manually set the sector address */ - if (dfu_sector_get_zone (sector) != zone_last) { - g_debug ("setting address to 0x%04x", - (guint) offset_dev); - if (!dfu_target_stm_set_address (target, - (guint32) offset_dev, - error)) - return FALSE; - zone_last = dfu_sector_get_zone (sector); - } - - /* we have to write one final zero-sized chunk for EOF */ - length = g_bytes_get_size (bytes) - offset; - if (length > transfer_size) - length = transfer_size; - bytes_tmp = g_bytes_new_from_bytes (bytes, offset, length); - g_debug ("writing sector at 0x%04x (0x%" G_GSIZE_FORMAT ")", - offset_dev, - g_bytes_get_size (bytes_tmp)); - /* ST uses wBlockNum=0 for DfuSe commands and wBlockNum=1 is reserved */ - if (!dfu_target_download_chunk (target, - (guint8) (i + 2), - bytes_tmp, - error)) - return FALSE; - - /* getting the status moves the state machine to DNLOAD-IDLE */ - if (!dfu_target_check_status (target, error)) - return FALSE; - - /* update UI */ - dfu_target_set_percentage (target, offset, g_bytes_get_size (bytes)); - } - - /* done */ - dfu_target_set_percentage_raw (target, 100); - dfu_target_set_action (target, FWUPD_STATUS_IDLE); - - /* success */ - return TRUE; -} - -static void -dfu_target_stm_init (DfuTargetStm *target_stm) -{ -} - -static void -dfu_target_stm_class_init (DfuTargetStmClass *klass) -{ - DfuTargetClass *klass_target = DFU_TARGET_CLASS (klass); - klass_target->attach = dfu_target_stm_attach; - klass_target->mass_erase = dfu_target_stm_mass_erase; - klass_target->upload_element = dfu_target_stm_upload_element; - klass_target->download_element = dfu_target_stm_download_element; -} - -DfuTarget * -dfu_target_stm_new (void) -{ - DfuTarget *target; - target = g_object_new (DFU_TYPE_TARGET_STM, NULL); - return target; -} diff -Nru fwupd-1.4.5/plugins/dfu/dfu-target-stm.h fwupd-1.5.8/plugins/dfu/dfu-target-stm.h --- fwupd-1.4.5/plugins/dfu/dfu-target-stm.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/dfu-target-stm.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2017 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include -#include - -#include "dfu-target.h" - -#define DFU_TYPE_TARGET_STM (dfu_target_stm_get_type ()) -G_DECLARE_DERIVABLE_TYPE (DfuTargetStm, dfu_target_stm, DFU, TARGET_STM, DfuTarget) - -struct _DfuTargetStmClass -{ - DfuTargetClass parent_class; -}; - -DfuTarget *dfu_target_stm_new (void); diff -Nru fwupd-1.4.5/plugins/dfu/dfu-tool.c fwupd-1.5.8/plugins/dfu/dfu-tool.c --- fwupd-1.4.5/plugins/dfu/dfu-tool.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/dfu-tool.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1095 +0,0 @@ -/* - * Copyright (C) 2015 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include -#include -#include -#include -#ifdef HAVE_GIO_UNIX -#include -#endif - -#include "dfu-device.h" -#include "dfu-sector.h" - -#include "fu-device-locker.h" - -#include "fwupd-error.h" - -typedef struct { - GCancellable *cancellable; - GPtrArray *cmd_array; - gboolean force; - gchar *device_vid_pid; - guint16 transfer_size; - FuQuirks *quirks; -} DfuToolPrivate; - -static void -dfu_tool_print_indent (const gchar *title, const gchar *message, guint indent) -{ - for (gsize i = 0; i < indent; i++) - g_print (" "); - g_print ("%s:", title); - for (gsize i = strlen (title) + indent; i < 15; i++) - g_print (" "); - g_print ("%s\n", message); -} - -static void -dfu_tool_private_free (DfuToolPrivate *priv) -{ - if (priv == NULL) - return; - g_free (priv->device_vid_pid); - g_object_unref (priv->cancellable); - g_object_unref (priv->quirks); - if (priv->cmd_array != NULL) - g_ptr_array_unref (priv->cmd_array); - g_free (priv); -} -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-function" -G_DEFINE_AUTOPTR_CLEANUP_FUNC(DfuToolPrivate, dfu_tool_private_free) -#pragma clang diagnostic pop - -typedef gboolean (*FuUtilPrivateCb) (DfuToolPrivate *util, - gchar **values, - GError **error); - -typedef struct { - gchar *name; - gchar *arguments; - gchar *description; - FuUtilPrivateCb callback; -} FuUtilItem; - -static void -dfu_tool_item_free (FuUtilItem *item) -{ - g_free (item->name); - g_free (item->arguments); - g_free (item->description); - g_free (item); -} - -static gint -dfu_tool_sort_command_name_cb (FuUtilItem **item1, FuUtilItem **item2) -{ - return g_strcmp0 ((*item1)->name, (*item2)->name); -} - -static void -dfu_tool_add (GPtrArray *array, - const gchar *name, - const gchar *arguments, - const gchar *description, - FuUtilPrivateCb callback) -{ - g_auto(GStrv) names = NULL; - - g_return_if_fail (name != NULL); - g_return_if_fail (description != NULL); - g_return_if_fail (callback != NULL); - - /* add each one */ - names = g_strsplit (name, ",", -1); - for (guint i = 0; names[i] != NULL; i++) { - FuUtilItem *item = g_new0 (FuUtilItem, 1); - item->name = g_strdup (names[i]); - if (i == 0) { - item->description = g_strdup (description); - } else { - /* TRANSLATORS: this is a command alias, e.g. 'get-devices' */ - item->description = g_strdup_printf (_("Alias to %s"), - names[0]); - } - item->arguments = g_strdup (arguments); - item->callback = callback; - g_ptr_array_add (array, item); - } -} - -static gchar * -dfu_tool_get_descriptions (GPtrArray *array) -{ - gsize len; - const gsize max_len = 31; - FuUtilItem *item; - GString *string; - - /* print each command */ - string = g_string_new (""); - for (guint i = 0; i < array->len; i++) { - item = g_ptr_array_index (array, i); - g_string_append (string, " "); - g_string_append (string, item->name); - len = strlen (item->name) + 2; - if (item->arguments != NULL) { - g_string_append (string, " "); - g_string_append (string, item->arguments); - len += strlen (item->arguments) + 1; - } - if (len < max_len) { - for (guint j = len; j < max_len + 1; j++) - g_string_append_c (string, ' '); - g_string_append (string, item->description); - g_string_append_c (string, '\n'); - } else { - g_string_append_c (string, '\n'); - for (guint j = 0; j < max_len + 1; j++) - g_string_append_c (string, ' '); - g_string_append (string, item->description); - g_string_append_c (string, '\n'); - } - } - - /* remove trailing newline */ - if (string->len > 0) - g_string_set_size (string, string->len - 1); - - return g_string_free (string, FALSE); -} - -static gboolean -dfu_tool_run (DfuToolPrivate *priv, - const gchar *command, - gchar **values, - GError **error) -{ - /* find command */ - for (guint i = 0; i < priv->cmd_array->len; i++) { - FuUtilItem *item = g_ptr_array_index (priv->cmd_array, i); - if (g_strcmp0 (item->name, command) == 0) - return item->callback (priv, values, error); - } - - /* not found */ - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - /* TRANSLATORS: error message */ - _("Command not found")); - return FALSE; -} - -static DfuDevice * -dfu_tool_get_default_device (DfuToolPrivate *priv, GError **error) -{ - g_autoptr(GUsbContext) usb_context = NULL; - g_autoptr(GPtrArray) devices = NULL; - - /* get all the DFU devices */ - usb_context = g_usb_context_new (error); - if (usb_context == NULL) - return NULL; - g_usb_context_enumerate (usb_context); - - /* we specified it manually */ - if (priv->device_vid_pid != NULL) { - gchar *tmp; - guint64 pid; - guint64 vid; - g_autoptr(DfuDevice) device = NULL; - g_autoptr(GUsbDevice) usb_device = NULL; - - /* parse */ - vid = g_ascii_strtoull (priv->device_vid_pid, &tmp, 16); - if (vid == 0 || vid > G_MAXUINT16) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Invalid format of VID:PID"); - return NULL; - } - if (tmp[0] != ':') { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Invalid format of VID:PID"); - return NULL; - } - pid = g_ascii_strtoull (tmp + 1, NULL, 16); - if (pid == 0 || pid > G_MAXUINT16) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Invalid format of VID:PID"); - return NULL; - } - - /* find device */ - usb_device = g_usb_context_find_by_vid_pid (usb_context, - (guint16) vid, - (guint16) pid, - error); - if (usb_device == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "no device matches for %04x:%04x", - (guint) vid, (guint) pid); - return NULL; - } - device = dfu_device_new (usb_device); - fu_device_set_quirks (FU_DEVICE (device), priv->quirks); - return device; - } - - /* auto-detect first device */ - devices = g_usb_context_get_devices (usb_context); - for (guint i = 0; i < devices->len; i++) { - GUsbDevice *usb_device = g_ptr_array_index (devices, i); - g_autoptr(DfuDevice) device = dfu_device_new (usb_device); - fu_device_set_quirks (FU_DEVICE (device), priv->quirks); - if (fu_device_probe (FU_DEVICE (device), NULL)) - return g_steal_pointer (&device); - } - - /* failed */ - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "no DFU devices found"); - return NULL; -} - -static gboolean -dfu_device_wait_for_replug (DfuToolPrivate *priv, DfuDevice *device, guint timeout, GError **error) -{ - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); - g_autoptr(GUsbDevice) usb_device2 = NULL; - g_autoptr(GUsbContext) usb_context = NULL; - - /* get all the DFU devices */ - usb_context = g_usb_context_new (error); - if (usb_context == NULL) - return FALSE; - - /* close */ - fu_device_close (FU_DEVICE (device), NULL); - - /* watch the device disappear and re-appear */ - usb_device2 = g_usb_context_wait_for_replug (usb_context, - usb_device, - FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE, - error); - if (usb_device2 == NULL) - return FALSE; - - /* re-open with new device set */ - fu_device_set_status (FU_DEVICE (device), FWUPD_STATUS_IDLE); - fu_usb_device_set_dev (FU_USB_DEVICE (device), usb_device2); - if (!fu_device_open (FU_DEVICE (device), error)) - return FALSE; - if (!dfu_device_refresh_and_clear (device, error)) - return FALSE; - - /* success */ - return TRUE; -} - -static GBytes * -dfu_tool_parse_hex_string (const gchar *val, GError **error) -{ - gsize result_size; - g_autofree guint8 *result = NULL; - - /* sanity check */ - if (val == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "nothing to parse"); - return NULL; - } - - /* parse each hex byte */ - result_size = strlen (val) / 2; - result = g_malloc (result_size); - for (guint i = 0; i < result_size; i++) { - gchar buf[3] = { "xx" }; - gchar *endptr = NULL; - guint64 tmp; - - /* copy two bytes and parse as hex */ - memcpy (buf, val + (i * 2), 2); - tmp = g_ascii_strtoull (buf, &endptr, 16); - if (tmp > 0xff || endptr[0] != '\0') { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "failed to parse '%s'", val); - return NULL; - } - result[i] = tmp; - } - return g_bytes_new (result, result_size); -} - -static guint -dfu_tool_bytes_replace (GBytes *data, GBytes *search, GBytes *replace) -{ - gsize data_sz; - gsize replace_sz; - gsize search_sz; - guint8 *data_buf; - guint8 *replace_buf; - guint8 *search_buf; - guint cnt = 0; - - data_buf = (gpointer) g_bytes_get_data (data, &data_sz); - search_buf = (gpointer) g_bytes_get_data (search, &search_sz); - replace_buf = (gpointer) g_bytes_get_data (replace, &replace_sz); - - g_return_val_if_fail (search_sz == replace_sz, FALSE); - - /* find and replace each one */ - for (gsize i = 0; i < data_sz - search_sz + 1; i++) { - if (memcmp (data_buf + i, search_buf, search_sz) == 0) { - g_print ("Replacing %" G_GSIZE_FORMAT " bytes @0x%04x\n", - replace_sz, (guint) i); - memcpy (data_buf + i, replace_buf, replace_sz); - i += replace_sz; - cnt++; - } - } - return cnt; -} - -static gboolean -dfu_tool_replace_data (DfuToolPrivate *priv, gchar **values, GError **error) -{ - guint cnt = 0; - g_autoptr(DfuFirmware) firmware = NULL; - g_autoptr(GFile) file = NULL; - g_autoptr(GBytes) data_search = NULL; - g_autoptr(GBytes) data_replace = NULL; - g_autoptr(GPtrArray) images = NULL; - - /* check args */ - if (g_strv_length (values) < 3) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Invalid arguments, expected FILE SEARCH REPLACE" - " -- e.g. `firmware.dfu deadbeef beefdead"); - return FALSE; - } - - /* open */ - file = g_file_new_for_path (values[0]); - firmware = dfu_firmware_new (); - if (!dfu_firmware_parse_file (firmware, file, - FWUPD_INSTALL_FLAG_NONE, - error)) { - return FALSE; - } - - /* parse hex values */ - data_search = dfu_tool_parse_hex_string (values[1], error); - if (data_search == NULL) - return FALSE; - data_replace = dfu_tool_parse_hex_string (values[2], error); - if (data_replace == NULL) - return FALSE; - if (g_bytes_get_size (data_search) != g_bytes_get_size (data_replace)) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "search and replace were different sizes"); - return FALSE; - } - - /* get each data segment */ - images = fu_firmware_get_images (FU_FIRMWARE (firmware)); - for (guint i = 0; i < images->len; i++) { - DfuImage *image = g_ptr_array_index (images, i); - GPtrArray *elements = dfu_image_get_elements (image); - for (guint j = 0; j < elements->len; j++) { - DfuElement *element = g_ptr_array_index (elements, j); - GBytes *contents = dfu_element_get_contents (element); - if (contents == NULL) - continue; - cnt += dfu_tool_bytes_replace (contents, data_search, data_replace); - } - } - - /* nothing done */ - if (cnt == 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "search string was not found"); - return FALSE; - } - - /* write out new file */ - return dfu_firmware_write_file (firmware, file, error); -} - -static void -fu_tool_action_changed_cb (FuDevice *device, GParamSpec *pspec, DfuToolPrivate *priv) -{ - g_print ("%s:\t%u%%\n", - fwupd_status_to_string (fu_device_get_status (device)), - fu_device_get_progress (device)); -} - -static gboolean -dfu_tool_read_alt (DfuToolPrivate *priv, gchar **values, GError **error) -{ - DfuTargetTransferFlags flags = DFU_TARGET_TRANSFER_FLAG_NONE; - g_autofree gchar *str_debug = NULL; - g_autoptr(DfuDevice) device = NULL; - g_autoptr(DfuFirmware) firmware = NULL; - g_autoptr(DfuImage) image = NULL; - g_autoptr(DfuTarget) target = NULL; - g_autoptr(FuDeviceLocker) locker = NULL; - g_autoptr(GFile) file = NULL; - - /* check args */ - if (g_strv_length (values) < 2) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Invalid arguments, expected " - "FILENAME DEVICE-ALT-NAME|DEVICE-ALT-ID"); - return FALSE; - } - - /* open correct device */ - device = dfu_tool_get_default_device (priv, error); - if (device == NULL) - return FALSE; - if (priv->transfer_size > 0) - dfu_device_set_transfer_size (device, priv->transfer_size); - locker = fu_device_locker_new (device, error); - if (locker == NULL) - return FALSE; - if (!dfu_device_refresh (device, error)) - return FALSE; - - /* set up progress */ - g_signal_connect (device, "notify::status", - G_CALLBACK (fu_tool_action_changed_cb), priv); - g_signal_connect (device, "notify::progress", - G_CALLBACK (fu_tool_action_changed_cb), priv); - - /* APP -> DFU */ - if (!fu_device_has_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { - g_debug ("detaching"); - if (!fu_device_detach (FU_DEVICE (device), error)) - return FALSE; - if (!dfu_device_wait_for_replug (priv, device, - FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE, - error)) - return FALSE; - } - - /* transfer */ - target = dfu_device_get_target_by_alt_name (device, - values[1], - NULL); - if (target == NULL) { - gchar *endptr; - guint64 tmp = g_ascii_strtoull (values[1], &endptr, 10); - if (tmp > 0xff || endptr[0] != '\0') { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Failed to parse alt-setting '%s'", - values[1]); - return FALSE; - } - target = dfu_device_get_target_by_alt_setting (device, - (guint8) tmp, - error); - if (target == NULL) - return FALSE; - } - - /* do transfer */ - image = dfu_target_upload (target, flags, error); - if (image == NULL) - return FALSE; - - /* do host reset */ - if (!fu_device_attach (FU_DEVICE (device), error)) - return FALSE; - if (!dfu_device_wait_for_replug (priv, device, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE, error)) - return FALSE; - - /* create new firmware object */ - firmware = dfu_firmware_new (); - dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_DFU); - fu_dfu_firmware_set_vid (FU_DFU_FIRMWARE (firmware), dfu_device_get_runtime_vid (device)); - fu_dfu_firmware_set_pid (FU_DFU_FIRMWARE (firmware), dfu_device_get_runtime_pid (device)); - fu_firmware_add_image (FU_FIRMWARE (firmware), FU_FIRMWARE_IMAGE (image)); - - /* save file */ - file = g_file_new_for_path (values[0]); - if (!dfu_firmware_write_file (firmware, file, error)) - return FALSE; - - /* print the new object */ - str_debug = fu_firmware_to_string (FU_FIRMWARE (firmware)); - g_debug ("DFU: %s", str_debug); - - /* success */ - g_print ("%u bytes successfully uploaded from device\n", - dfu_image_get_size (image)); - return TRUE; -} - -static gboolean -dfu_tool_read (DfuToolPrivate *priv, gchar **values, GError **error) -{ - DfuFirmwareFormat format; - DfuTargetTransferFlags flags = DFU_TARGET_TRANSFER_FLAG_NONE; - g_autofree gchar *str_debug = NULL; - g_autoptr(DfuDevice) device = NULL; - g_autoptr(DfuFirmware) firmware = NULL; - g_autoptr(FuDeviceLocker) locker = NULL; - g_autoptr(GFile) file = NULL; - - /* check args */ - if (g_strv_length (values) == 1) { - /* guess output format */ - if (g_str_has_suffix (values[0], ".dfu")) { - format = DFU_FIRMWARE_FORMAT_DFU; - } else if (g_str_has_suffix (values[0], ".bin") || - g_str_has_suffix (values[0], ".rom")) { - format = DFU_FIRMWARE_FORMAT_RAW; - } else { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Could not guess a file format"); - return FALSE; - } - } else if (g_strv_length (values) == 2) { - format = dfu_firmware_format_from_string (values[1]); - if (format == DFU_FIRMWARE_FORMAT_UNKNOWN) { - g_autoptr(GString) tmp = g_string_new (NULL); - for (guint i = 1; i < DFU_FIRMWARE_FORMAT_LAST; i++) { - if (tmp->len > 0) - g_string_append (tmp, "|"); - g_string_append (tmp, dfu_firmware_format_to_string (i)); - } - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "unknown format '%s', expected [%s]", - values[0], tmp->str); - return FALSE; - } - } else { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Invalid arguments, expected FILENAME [FORMAT]"); - return FALSE; - } - - /* open correct device */ - device = dfu_tool_get_default_device (priv, error); - if (device == NULL) - return FALSE; - locker = fu_device_locker_new (device, error); - if (locker == NULL) - return FALSE; - if (!dfu_device_refresh (device, error)) - return FALSE; - - /* APP -> DFU */ - if (!fu_device_has_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { - if (!fu_device_detach (FU_DEVICE (device), error)) - return FALSE; - if (!dfu_device_wait_for_replug (priv, device, - FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE, - error)) { - return FALSE; - } - } - - /* transfer */ - g_signal_connect (device, "notify::status", - G_CALLBACK (fu_tool_action_changed_cb), priv); - g_signal_connect (device, "notify::progress", - G_CALLBACK (fu_tool_action_changed_cb), priv); - firmware = dfu_device_upload (device, flags, error); - if (firmware == NULL) - return FALSE; - - /* do host reset */ - if (!fu_device_attach (FU_DEVICE (device), error)) - return FALSE; - if (!dfu_device_wait_for_replug (priv, device, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE, error)) - return FALSE; - - /* save file */ - file = g_file_new_for_path (values[0]); - dfu_firmware_set_format (firmware, format); - if (!dfu_firmware_write_file (firmware, file, error)) - return FALSE; - - /* print the new object */ - str_debug = fu_firmware_to_string (FU_FIRMWARE (firmware)); - g_debug ("DFU: %s", str_debug); - - /* success */ - g_print ("%u bytes successfully uploaded from device\n", - dfu_firmware_get_size (firmware)); - return TRUE; -} - -static gchar * -dfu_tool_get_device_string (DfuToolPrivate *priv, DfuDevice *device) -{ - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); - g_autoptr(FuDeviceLocker) locker = NULL; - - /* open if required, and get status */ - if (usb_device == NULL) { - return g_strdup_printf ("%04x:%04x [%s]", - dfu_device_get_runtime_vid (device), - dfu_device_get_runtime_pid (device), - "removed"); - } - if (!fu_usb_device_is_open (FU_USB_DEVICE (device))) { - g_autoptr(GError) error = NULL; - locker = fu_device_locker_new (device, &error); - if (locker == NULL) { - return g_strdup_printf ("%04x:%04x [%s]", - fu_usb_device_get_vid (FU_USB_DEVICE (device)), - fu_usb_device_get_pid (FU_USB_DEVICE (device)), - error->message); - } - if (!dfu_device_refresh (device, &error)) - return NULL; - } - return g_strdup_printf ("%04x:%04x [%s:%s]", - fu_usb_device_get_vid (FU_USB_DEVICE (device)), - fu_usb_device_get_pid (FU_USB_DEVICE (device)), - dfu_state_to_string (dfu_device_get_state (device)), - dfu_status_to_string (dfu_device_get_status (device))); -} - -static void -dfu_tool_device_added_cb (GUsbContext *context, - DfuDevice *device, - gpointer user_data) -{ - DfuToolPrivate *priv = (DfuToolPrivate *) user_data; - g_autofree gchar *tmp = dfu_tool_get_device_string (priv, device); - /* TRANSLATORS: this is when a device is hotplugged */ - dfu_tool_print_indent (_("Added"), tmp, 0); -} - -static void -dfu_tool_device_removed_cb (GUsbContext *context, - DfuDevice *device, - gpointer user_data) -{ - DfuToolPrivate *priv = (DfuToolPrivate *) user_data; - g_autofree gchar *tmp = dfu_tool_get_device_string (priv, device); - /* TRANSLATORS: this is when a device is hotplugged */ - dfu_tool_print_indent (_("Removed"), tmp, 0); -} - -static void -dfu_tool_device_changed_cb (GUsbContext *context, DfuDevice *device, gpointer user_data) -{ - DfuToolPrivate *priv = (DfuToolPrivate *) user_data; - g_autofree gchar *tmp = dfu_tool_get_device_string (priv, device); - /* TRANSLATORS: this is when a device is hotplugged */ - dfu_tool_print_indent (_("Changed"), tmp, 0); -} - -static void -dfu_tool_watch_cancelled_cb (GCancellable *cancellable, gpointer user_data) -{ - GMainLoop *loop = (GMainLoop *) user_data; - /* TRANSLATORS: this is when a device ctrl+c's a watch */ - g_print ("%s\n", _("Cancelled")); - g_main_loop_quit (loop); -} - -static gboolean -dfu_tool_watch (DfuToolPrivate *priv, gchar **values, GError **error) -{ - g_autoptr(GUsbContext) usb_context = NULL; - g_autoptr(GMainLoop) loop = NULL; - g_autoptr(GPtrArray) devices = NULL; - - /* get all the DFU devices */ - usb_context = g_usb_context_new (error); - if (usb_context == NULL) - return FALSE; - g_usb_context_enumerate (usb_context); - - /* print what's already attached */ - devices = g_usb_context_get_devices (usb_context); - for (guint i = 0; i < devices->len; i++) { - DfuDevice *device = g_ptr_array_index (devices, i); - dfu_tool_device_added_cb (usb_context, device, priv); - } - - /* watch for any hotplugged device */ - loop = g_main_loop_new (NULL, FALSE); - g_signal_connect (usb_context, "device-added", - G_CALLBACK (dfu_tool_device_added_cb), priv); - g_signal_connect (usb_context, "device-removed", - G_CALLBACK (dfu_tool_device_removed_cb), priv); - g_signal_connect (usb_context, "device-changed", - G_CALLBACK (dfu_tool_device_changed_cb), priv); - g_signal_connect (priv->cancellable, "cancelled", - G_CALLBACK (dfu_tool_watch_cancelled_cb), loop); - g_main_loop_run (loop); - return TRUE; -} - -static gboolean -dfu_tool_write_alt (DfuToolPrivate *priv, gchar **values, GError **error) -{ - DfuTargetTransferFlags flags = DFU_TARGET_TRANSFER_FLAG_VERIFY; - g_autofree gchar *str_debug = NULL; - g_autoptr(DfuDevice) device = NULL; - g_autoptr(DfuFirmware) firmware = NULL; - g_autoptr(DfuImage) image = NULL; - g_autoptr(DfuTarget) target = NULL; - g_autoptr(FuDeviceLocker) locker = NULL; - g_autoptr(GFile) file = NULL; - - /* check args */ - if (g_strv_length (values) < 2) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Invalid arguments, expected " - "FILENAME DEVICE-ALT-NAME|DEVICE-ALT-ID " - "[IMAGE-ALT-NAME|IMAGE-ALT-ID]"); - return FALSE; - } - - /* open file */ - firmware = dfu_firmware_new (); - file = g_file_new_for_path (values[0]); - if (!dfu_firmware_parse_file (firmware, file, - FWUPD_INSTALL_FLAG_NONE, - error)) - return FALSE; - - /* open correct device */ - device = dfu_tool_get_default_device (priv, error); - if (device == NULL) - return FALSE; - if (priv->transfer_size > 0) - dfu_device_set_transfer_size (device, priv->transfer_size); - locker = fu_device_locker_new (device, error); - if (locker == NULL) - return FALSE; - if (!dfu_device_refresh (device, error)) - return FALSE; - - /* set up progress */ - g_signal_connect (device, "notify::status", - G_CALLBACK (fu_tool_action_changed_cb), priv); - g_signal_connect (device, "notify::progress", - G_CALLBACK (fu_tool_action_changed_cb), priv); - - /* APP -> DFU */ - if (!fu_device_has_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { - g_debug ("detaching"); - if (!fu_device_detach (FU_DEVICE (device), error)) - return FALSE; - if (!dfu_device_wait_for_replug (priv, device, 5000, error)) - return FALSE; - } - - /* print the new object */ - str_debug = fu_firmware_to_string (FU_FIRMWARE (firmware)); - g_debug ("DFU: %s", str_debug); - - /* get correct target on device */ - target = dfu_device_get_target_by_alt_name (device, - values[1], - NULL); - if (target == NULL) { - gchar *endptr; - guint64 tmp = g_ascii_strtoull (values[1], &endptr, 10); - if (tmp > 0xff || endptr[0] != '\0') { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Failed to parse alt-setting '%s'", - values[1]); - return FALSE; - } - target = dfu_device_get_target_by_alt_setting (device, - (guint8) tmp, - error); - if (target == NULL) - return FALSE; - } - - /* allow overriding the firmware alt-setting */ - if (g_strv_length (values) > 2) { - image = DFU_IMAGE (fu_firmware_get_image_by_id (FU_FIRMWARE (firmware), values[2], NULL)); - if (image == NULL) { - gchar *endptr; - guint64 tmp = g_ascii_strtoull (values[2], &endptr, 10); - if (tmp > 0xff || endptr[0] != '\0') { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Failed to parse image alt-setting '%s'", - values[2]); - return FALSE; - } - image = DFU_IMAGE (fu_firmware_get_image_by_idx (FU_FIRMWARE (firmware), tmp, error)); - if (image == NULL) - return FALSE; - } - } else { - g_print ("WARNING: Using default firmware image\n"); - image = DFU_IMAGE (fu_firmware_get_image_default (FU_FIRMWARE (firmware), error)); - if (image == NULL) - return FALSE; - } - - /* transfer */ - if (!dfu_target_download (target, image, flags, error)) - return FALSE; - - /* do host reset */ - if (!fu_device_attach (FU_DEVICE (device), error)) - return FALSE; - if (!dfu_device_wait_for_replug (priv, device, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE, error)) - return FALSE; - - /* success */ - g_print ("%u bytes successfully downloaded to device\n", - dfu_image_get_size (image)); - return TRUE; -} - -static gboolean -dfu_tool_write (DfuToolPrivate *priv, gchar **values, GError **error) -{ - FwupdInstallFlags flags = FWUPD_INSTALL_FLAG_NONE; - g_autoptr(DfuDevice) device = NULL; - g_autoptr(GBytes) fw = NULL; - g_autoptr(FuDeviceLocker) locker = NULL; - - /* check args */ - if (g_strv_length (values) < 1) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Invalid arguments, expected FILENAME"); - return FALSE; - } - - /* open file */ - fw = fu_common_get_contents_bytes (values[0], error); - if (fw == NULL) - return FALSE; - - /* open correct device */ - device = dfu_tool_get_default_device (priv, error); - if (device == NULL) - return FALSE; - locker = fu_device_locker_new (device, error); - if (locker == NULL) - return FALSE; - if (!dfu_device_refresh (device, error)) - return FALSE; - - /* APP -> DFU */ - if (!fu_device_has_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { - if (!fu_device_detach (FU_DEVICE (device), error)) - return FALSE; - if (!dfu_device_wait_for_replug (priv, device, - FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE, - error)) { - return FALSE; - } - } - - /* allow wildcards */ - if (priv->force) - flags |= FWUPD_INSTALL_FLAG_FORCE; - - /* transfer */ - g_signal_connect (device, "notify::status", - G_CALLBACK (fu_tool_action_changed_cb), priv); - g_signal_connect (device, "notify::progress", - G_CALLBACK (fu_tool_action_changed_cb), priv); - if (!fu_device_write_firmware (FU_DEVICE (device), fw, flags, error)) - return FALSE; - - /* do host reset */ - if (!fu_device_attach (FU_DEVICE (device), error)) - return FALSE; - - if (dfu_device_has_attribute (device, DFU_DEVICE_ATTRIBUTE_MANIFEST_TOL)) { - if (!dfu_device_wait_for_replug (priv, device, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE, error)) - return FALSE; - } - - /* success */ - g_print ("%u bytes successfully downloaded to device\n", - (guint) g_bytes_get_size (fw)); - return TRUE; -} - -#ifdef HAVE_GIO_UNIX -static gboolean -dfu_tool_sigint_cb (gpointer user_data) -{ - DfuToolPrivate *priv = (DfuToolPrivate *) user_data; - g_debug ("Handling SIGINT"); - g_cancellable_cancel (priv->cancellable); - return FALSE; -} -#endif - -int -main (int argc, char *argv[]) -{ - gboolean ret; - gboolean verbose = FALSE; - gboolean version = FALSE; - g_autofree gchar *cmd_descriptions = NULL; - g_autoptr(DfuToolPrivate) priv = g_new0 (DfuToolPrivate, 1); - g_autoptr(GError) error = NULL; - g_autoptr(GOptionContext) context = NULL; - const GOptionEntry options[] = { - { "version", '\0', 0, G_OPTION_ARG_NONE, &version, - _("Print the version number"), NULL }, - { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, - _("Print verbose debug statements"), NULL }, - { "device", 'd', 0, G_OPTION_ARG_STRING, &priv->device_vid_pid, - _("Specify Vendor/Product ID(s) of DFU device"), "VID:PID" }, - { "transfer-size", 't', 0, G_OPTION_ARG_STRING, &priv->transfer_size, - _("Specify the number of bytes per USB transfer"), "BYTES" }, - { "force", '\0', 0, G_OPTION_ARG_NONE, &priv->force, - _("Force the action ignoring all warnings"), NULL }, - { NULL} - }; - - setlocale (LC_ALL, ""); - - bindtextdomain (GETTEXT_PACKAGE, FWUPD_LOCALEDIR); - bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); - textdomain (GETTEXT_PACKAGE); - - /* add commands */ - priv->cmd_array = g_ptr_array_new_with_free_func ((GDestroyNotify) dfu_tool_item_free); - dfu_tool_add (priv->cmd_array, - "read", - "FILENAME", - /* TRANSLATORS: command description */ - _("Read firmware from device into a file"), - dfu_tool_read); - dfu_tool_add (priv->cmd_array, - "read-alt", - "FILENAME DEVICE-ALT-NAME|DEVICE-ALT-ID", - /* TRANSLATORS: command description */ - _("Read firmware from one partition into a file"), - dfu_tool_read_alt); - dfu_tool_add (priv->cmd_array, - "write", - NULL, - /* TRANSLATORS: command description */ - _("Write firmware from file into device"), - dfu_tool_write); - dfu_tool_add (priv->cmd_array, - "write-alt", - "FILENAME DEVICE-ALT-NAME|DEVICE-ALT-ID [IMAGE-ALT-NAME|IMAGE-ALT-ID]", - /* TRANSLATORS: command description */ - _("Write firmware from file into one partition"), - dfu_tool_write_alt); - dfu_tool_add (priv->cmd_array, - "watch", - NULL, - /* TRANSLATORS: command description */ - _("Watch DFU devices being hotplugged"), - dfu_tool_watch); - dfu_tool_add (priv->cmd_array, - "replace-data", - NULL, - /* TRANSLATORS: command description */ - _("Replace data in an existing firmware file"), - dfu_tool_replace_data); - - /* use quirks */ - priv->quirks = fu_quirks_new (); - if (!fu_quirks_load (priv->quirks, FU_QUIRKS_LOAD_FLAG_NONE, &error)) { - /* TRANSLATORS: quirks are device-specific workarounds */ - g_print ("%s: %s\n", _("Failed to load quirks"), error->message); - return EXIT_FAILURE; - } - - /* do stuff on ctrl+c */ - priv->cancellable = g_cancellable_new (); -#ifdef HAVE_GIO_UNIX - g_unix_signal_add_full (G_PRIORITY_DEFAULT, - SIGINT, - dfu_tool_sigint_cb, - priv, - NULL); -#endif - - /* sort by command name */ - g_ptr_array_sort (priv->cmd_array, - (GCompareFunc) dfu_tool_sort_command_name_cb); - - /* get a list of the commands */ - context = g_option_context_new (NULL); - cmd_descriptions = dfu_tool_get_descriptions (priv->cmd_array); - g_option_context_set_summary (context, cmd_descriptions); - - /* TRANSLATORS: DFU stands for device firmware update */ - g_set_application_name (_("DFU Utility")); - g_option_context_add_main_entries (context, options, NULL); - ret = g_option_context_parse (context, &argc, &argv, &error); - if (!ret) { - /* TRANSLATORS: the user didn't read the man page */ - g_print ("%s: %s\n", _("Failed to parse arguments"), error->message); - return EXIT_FAILURE; - } - - /* set verbose? */ - if (verbose) - g_setenv ("G_MESSAGES_DEBUG", "all", FALSE); - - /* version */ - if (version) { - g_print ("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION); - return EXIT_SUCCESS; - } - - /* run the specified command */ - ret = dfu_tool_run (priv, argv[1], (gchar**) &argv[2], &error); - if (!ret) { - if (g_error_matches (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL)) { - g_autofree gchar *tmp = NULL; - tmp = g_option_context_get_help (context, TRUE, NULL); - g_print ("%s\n\n%s", error->message, tmp); - } else { - g_print ("%s\n", error->message); - } - return EXIT_FAILURE; - } - - /* success/ */ - return EXIT_SUCCESS; -} diff -Nru fwupd-1.4.5/plugins/dfu/dfu-tool.h2m fwupd-1.5.8/plugins/dfu/dfu-tool.h2m --- fwupd-1.4.5/plugins/dfu/dfu-tool.h2m 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/dfu-tool.h2m 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ -[DESCRIPTION] -.PP -This manual page documents briefly the \fBdfu-tool\fR command. -.PP -\fBdfu-tool\fR allows a user to write various kinds of -firmware onto devices supporting the USB Device Firmware Upgrade protocol. -This tool can be used to switch the device from the normal runtime mode -to `DFU mode' which allows the user to read and write firmware. -Either the whole device can be written in one operation, or individual -`targets' can be specified with the alternative name or number. -.PP -\fBdfu-tool\fR uses the libdfu shared -library to perform actions. -All synchronous actions can be safely cancelled and on failure will return -errors with both a type and a full textual description. -libdfu supports DFU 1.0, DFU 1.1 and the ST DfuSe vendor extension, and -handles many device `quirks' necessary for the real-world implementations -of DFU\&. -.PP -Additionally \fBdfu-tool\fR can be used to convert firmware -from various different formats, or to modify details about the elements, -images and metadata contained inside the firmware file. -For example, you can easily convert DFU 1.1 firmware into the -vendor-specific DfuSe format, convert a Intel HEX file into a raw file -padded to a specific size, or add new copyright and licensing information -to an existing file. -Fields such as the vendor and product IDs can be changed, and the firmware -elements can be encrypted and decrypted using various different methods. -Merging two DfuSe files together is also possible, although specifying -different alt-setting numbers before merging is a good idea to avoid -confusion. -.PP -Although \fBdfu-tool\fR tries to provide a large number of -easy-to-use commands, it may only be possible to do certain operations -using the libdfu library directly. -This is easier than it sounds, as the library is built with GObject -Introspection support making it usable in many languages such as C, -Javascript and Python. -Furthermore, using the library is a good idea if you want to perform -multiple operations on large firmware files, for instance, -converting from an Intel HEX file, padding to a certain size, setting -vendor and adding licensing information and then saving to a remote -location. diff -Nru fwupd-1.4.5/plugins/dfu/fu-dfu-common.c fwupd-1.5.8/plugins/dfu/fu-dfu-common.c --- fwupd-1.4.5/plugins/dfu/fu-dfu-common.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/fu-dfu-common.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2015 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +/** + * SECTION:fu-dfu-common + * @short_description: Common functions for DFU + * + * These helper objects allow converting from enum values to strings. + */ + +#include "config.h" + +#include + +#include "fu-dfu-common.h" + +/** + * fu_dfu_state_to_string: + * @state: a #FuDfuState, e.g. %FU_DFU_STATE_DFU_MANIFEST + * + * Converts an enumerated value to a string. + * + * Return value: a string + **/ +const gchar * +fu_dfu_state_to_string (FuDfuState state) +{ + if (state == FU_DFU_STATE_APP_IDLE) + return "appIDLE"; + if (state == FU_DFU_STATE_APP_DETACH) + return "appDETACH"; + if (state == FU_DFU_STATE_DFU_IDLE) + return "dfuIDLE"; + if (state == FU_DFU_STATE_DFU_DNLOAD_SYNC) + return "dfuDNLOAD-SYNC"; + if (state == FU_DFU_STATE_DFU_DNBUSY) + return "dfuDNBUSY"; + if (state == FU_DFU_STATE_DFU_DNLOAD_IDLE) + return "dfuDNLOAD-IDLE"; + if (state == FU_DFU_STATE_DFU_MANIFEST_SYNC) + return "dfuMANIFEST-SYNC"; + if (state == FU_DFU_STATE_DFU_MANIFEST) + return "dfuMANIFEST"; + if (state == FU_DFU_STATE_DFU_MANIFEST_WAIT_RESET) + return "dfuMANIFEST-WAIT-RESET"; + if (state == FU_DFU_STATE_DFU_UPLOAD_IDLE) + return "dfuUPLOAD-IDLE"; + if (state == FU_DFU_STATE_DFU_ERROR) + return "dfuERROR"; + return NULL; +} + +/** + * fu_dfu_status_to_string: + * @status: a #FuDfuStatus, e.g. %FU_DFU_STATUS_ERR_ERASE + * + * Converts an enumerated value to a string. + * + * Return value: a string + **/ +const gchar * +fu_dfu_status_to_string (FuDfuStatus status) +{ + if (status == FU_DFU_STATUS_OK) + return "OK"; + if (status == FU_DFU_STATUS_ERR_TARGET) + return "errTARGET"; + if (status == FU_DFU_STATUS_ERR_FILE) + return "errFILE"; + if (status == FU_DFU_STATUS_ERR_WRITE) + return "errwrite"; + if (status == FU_DFU_STATUS_ERR_ERASE) + return "errERASE"; + if (status == FU_DFU_STATUS_ERR_CHECK_ERASED) + return "errCHECK_ERASED"; + if (status == FU_DFU_STATUS_ERR_PROG) + return "errPROG"; + if (status == FU_DFU_STATUS_ERR_VERIFY) + return "errVERIFY"; + if (status == FU_DFU_STATUS_ERR_ADDRESS) + return "errADDRESS"; + if (status == FU_DFU_STATUS_ERR_NOTDONE) + return "errNOTDONE"; + if (status == FU_DFU_STATUS_ERR_FIRMWARE) + return "errFIRMWARE"; + if (status == FU_DFU_STATUS_ERR_VENDOR) + return "errVENDOR"; + if (status == FU_DFU_STATUS_ERR_USBR) + return "errUSBR"; + if (status == FU_DFU_STATUS_ERR_POR) + return "errPOR"; + if (status == FU_DFU_STATUS_ERR_UNKNOWN) + return "errUNKNOWN"; + if (status == FU_DFU_STATUS_ERR_STALLDPKT) + return "errSTALLDPKT"; + return NULL; +} + +/** + * fu_dfu_utils_bytes_join_array: + * @chunks: (element-type GBytes): bytes + * + * Creates a monolithic block of memory from an array of #GBytes. + * + * Return value: (transfer full): a new GBytes + **/ +GBytes * +fu_dfu_utils_bytes_join_array (GPtrArray *chunks) +{ + gsize total_size = 0; + guint32 offset = 0; + guint8 *buffer; + + /* get the size of all the chunks */ + for (guint i = 0; i < chunks->len; i++) { + GBytes *chunk_tmp = g_ptr_array_index (chunks, i); + total_size += g_bytes_get_size (chunk_tmp); + } + + /* copy them into a buffer */ + buffer = g_malloc0 (total_size); + for (guint i = 0; i < chunks->len; i++) { + const guint8 *chunk_data; + gsize chunk_size = 0; + GBytes *chunk_tmp = g_ptr_array_index (chunks, i); + chunk_data = g_bytes_get_data (chunk_tmp, &chunk_size); + if (chunk_size == 0) + continue; + memcpy (buffer + offset, chunk_data, chunk_size); + offset += chunk_size; + } + return g_bytes_new_take (buffer, total_size); +} diff -Nru fwupd-1.4.5/plugins/dfu/fu-dfu-common.h fwupd-1.5.8/plugins/dfu/fu-dfu-common.h --- fwupd-1.4.5/plugins/dfu/fu-dfu-common.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/fu-dfu-common.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2015 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +/** + * FuDfuRequest: + * @FU_DFU_REQUEST_DETACH: Detach + * @FU_DFU_REQUEST_DNLOAD: Download host-to-device + * @FU_DFU_REQUEST_UPLOAD: Upload device-to-host + * @FU_DFU_REQUEST_GETSTATUS: Get the device status + * @FU_DFU_REQUEST_CLRSTATUS: Clear the device status + * @FU_DFU_REQUEST_GETSTATE: Get the last set state + * @FU_DFU_REQUEST_ABORT: Abort the current transfer + * + * The DFU request kinds. + **/ +typedef enum { + FU_DFU_REQUEST_DETACH = 0x00, + FU_DFU_REQUEST_DNLOAD = 0x01, + FU_DFU_REQUEST_UPLOAD = 0x02, + FU_DFU_REQUEST_GETSTATUS = 0x03, + FU_DFU_REQUEST_CLRSTATUS = 0x04, + FU_DFU_REQUEST_GETSTATE = 0x05, + FU_DFU_REQUEST_ABORT = 0x06, + /*< private >*/ + FU_DFU_REQUEST_LAST +} FuDfuRequest; + +/** + * FuDfuStatus: + * @FU_DFU_STATUS_OK: No error condition is present + * @FU_DFU_STATUS_ERR_TARGET: File is not targeted for use by this device + * @FU_DFU_STATUS_ERR_FILE: File is for this device but fails a verification test + * @FU_DFU_STATUS_ERR_WRITE: Device is unable to write memory + * @FU_DFU_STATUS_ERR_ERASE: Memory erase function failed + * @FU_DFU_STATUS_ERR_CHECK_ERASED: Memory erase check failed + * @FU_DFU_STATUS_ERR_PROG: Program memory function failed + * @FU_DFU_STATUS_ERR_VERIFY: Programmed memory failed verification + * @FU_DFU_STATUS_ERR_ADDRESS: Cannot program memory due to received address that isout of range + * @FU_DFU_STATUS_ERR_NOTDONE: Received DFU_DNLOAD with wLength = 0 but data is incomplete + * @FU_DFU_STATUS_ERR_FIRMWARE: Device firmware is corrupt + * @FU_DFU_STATUS_ERR_VENDOR: iString indicates a vendor-specific error + * @FU_DFU_STATUS_ERR_USBR: Device detected unexpected USB reset signaling + * @FU_DFU_STATUS_ERR_POR: Device detected unexpected power on reset + * @FU_DFU_STATUS_ERR_UNKNOWN: Something unexpected went wrong + * @FU_DFU_STATUS_ERR_STALLDPKT: Device stalled an unexpected request + * + * The status enumerated kind. + **/ +typedef enum { + FU_DFU_STATUS_OK = 0x00, + FU_DFU_STATUS_ERR_TARGET = 0x01, + FU_DFU_STATUS_ERR_FILE = 0x02, + FU_DFU_STATUS_ERR_WRITE = 0x03, + FU_DFU_STATUS_ERR_ERASE = 0x04, + FU_DFU_STATUS_ERR_CHECK_ERASED = 0x05, + FU_DFU_STATUS_ERR_PROG = 0x06, + FU_DFU_STATUS_ERR_VERIFY = 0x07, + FU_DFU_STATUS_ERR_ADDRESS = 0x08, + FU_DFU_STATUS_ERR_NOTDONE = 0x09, + FU_DFU_STATUS_ERR_FIRMWARE = 0x0a, + FU_DFU_STATUS_ERR_VENDOR = 0x0b, + FU_DFU_STATUS_ERR_USBR = 0x0c, + FU_DFU_STATUS_ERR_POR = 0x0d, + FU_DFU_STATUS_ERR_UNKNOWN = 0x0e, + FU_DFU_STATUS_ERR_STALLDPKT = 0x0f, + /*< private >*/ + FU_DFU_STATUS_LAST +} FuDfuStatus; + +/** + * FuDfuState: + * @FU_DFU_STATE_APP_IDLE: State 0 + * @FU_DFU_STATE_APP_DETACH: State 1 + * @FU_DFU_STATE_DFU_IDLE: State 2 + * @FU_DFU_STATE_DFU_DNLOAD_SYNC: State 3 + * @FU_DFU_STATE_DFU_DNBUSY: State 4 + * @FU_DFU_STATE_DFU_DNLOAD_IDLE: State 5 + * @FU_DFU_STATE_DFU_MANIFEST_SYNC: State 6 + * @FU_DFU_STATE_DFU_MANIFEST: State 7 + * @FU_DFU_STATE_DFU_MANIFEST_WAIT_RESET: State 8 + * @FU_DFU_STATE_DFU_UPLOAD_IDLE: State 9 + * @FU_DFU_STATE_DFU_ERROR: State 10 + * + * The state enumerated kind. + **/ +typedef enum { + FU_DFU_STATE_APP_IDLE = 0x00, + FU_DFU_STATE_APP_DETACH = 0x01, + FU_DFU_STATE_DFU_IDLE = 0x02, + FU_DFU_STATE_DFU_DNLOAD_SYNC = 0x03, + FU_DFU_STATE_DFU_DNBUSY = 0x04, + FU_DFU_STATE_DFU_DNLOAD_IDLE = 0x05, + FU_DFU_STATE_DFU_MANIFEST_SYNC = 0x06, + FU_DFU_STATE_DFU_MANIFEST = 0x07, + FU_DFU_STATE_DFU_MANIFEST_WAIT_RESET = 0x08, + FU_DFU_STATE_DFU_UPLOAD_IDLE = 0x09, + FU_DFU_STATE_DFU_ERROR = 0x0a, + /*< private >*/ + FU_DFU_STATE_LAST +} FuDfuState; + +const gchar *fu_dfu_state_to_string (FuDfuState state); +const gchar *fu_dfu_status_to_string (FuDfuStatus status); + +/* helpers */ +GBytes *fu_dfu_utils_bytes_join_array (GPtrArray *chunks); diff -Nru fwupd-1.4.5/plugins/dfu/fu-dfu-device.c fwupd-1.5.8/plugins/dfu/fu-dfu-device.c --- fwupd-1.4.5/plugins/dfu/fu-dfu-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/fu-dfu-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,1951 @@ +/* + * Copyright (C) 2015 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +/** + * SECTION:fu-dfu-device + * @short_description: Object representing a DFU-capable device + * + * This object allows two things: + * + * - Downloading from the host to the device, optionally with + * verification using a DFU or DfuSe firmware file. + * + * - Uploading from the device to the host to a DFU or DfuSe firmware + * file. The file format is chosen automatically, with DfuSe being + * chosen if the device contains more than one target. + * + * See also: #FuDfuTarget, #FuDfuseFirmware + */ + +/** + * FU_QUIRKS_DFU_FLAGS: + * @key: the USB device ID, e.g. `USB\VID_0763&PID_2806` + * @value: a string, separated using `|`, e.g. `ignore-polltimeout|no-pid-change` + * + * Assigns optional quirks to use for a DFU device which does not follow the + * DFU 1.0 or 1.1 specification. The list of supported quirks is thus: + * + * * `none`: No device quirks + * * `attach-extra-reset`: Device needs resetting twice for attach + * * `attach-upload-download`: An upload or download is required for attach + * * `force-dfu-mode`: Force DFU mode + * * `ignore-polltimeout`: Ignore the device download timeout + * * `ignore-runtime`: Device has broken DFU runtime support + * * `ignore-upload`: Uploading from the device is broken + * * `no-fu-dfu-runtime`: No DFU runtime interface is provided + * * `no-get-status-upload`: Do not do GetStatus when uploading + * * `no-pid-change`: Accept the same VID:PID when changing modes + * * `use-any-interface`: Use any interface for DFU + * * `use-atmel-avr`: Device uses the ATMEL bootloader + * * `use-protocol-zero`: Fix up the protocol number + * * `legacy-protocol`: Use a legacy protocol version + * * `detach-for-attach`: Requires a FU_DFU_REQUEST_DETACH to attach + * * `absent-sector-size`: In absence of sector size, assume byte + * * `manifest-poll`: Requires polling via GetStatus in dfuManifest state + * * `no-bus-reset-attach`: Do not require a bus reset to attach to normal + * + * Default value: `none` + * + * Since: 1.0.1 + */ +#define FU_QUIRKS_DFU_FLAGS "Flags" + +/** + * FU_QUIRKS_DFU_FORCE_VERSION: + * @key: the USB device ID, e.g. `USB\VID_0763&PID_2806` + * @value: the uint16_t DFU version, encoded in base 16, e.g. `0110` + * + * Forces a specific DFU version for the hardware device. This is required + * if the device does not set, or sets incorrectly, items in the DFU functional + * descriptor. + * + * Since: 1.0.1 + */ +#define FU_QUIRKS_DFU_FORCE_VERSION "DfuForceVersion" + +#define DFU_DEVICE_DNLOAD_TIMEOUT_DEFAULT 5 /* ms */ + +#include "config.h" + +#include + +#include "fu-dfu-common.h" +#include "fu-dfu-device.h" +#include "fu-dfu-target-avr.h" +#include "fu-dfu-target-private.h" +#include "fu-dfu-target-stm.h" + +#include "fu-device-locker.h" +#include "fu-dfu-firmware-private.h" +#include "fu-dfuse-firmware.h" +#include "fu-firmware-common.h" + +#include "fwupd-error.h" + +static void fu_dfu_device_finalize (GObject *object); + +typedef struct { + FuDfuDeviceAttrs attributes; + FuDfuState state; + FuDfuStatus status; + GPtrArray *targets; + gboolean done_upload_or_download; + gboolean claimed_interface; + gchar *chip_id; + guint16 version; + guint16 force_version; + guint16 force_transfer_size; + guint16 runtime_pid; + guint16 runtime_vid; + guint16 runtime_release; + guint16 transfer_size; + guint8 iface_number; + guint dnload_timeout; + guint timeout_ms; +} FuDfuDevicePrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (FuDfuDevice, fu_dfu_device, FU_TYPE_USB_DEVICE) +#define GET_PRIVATE(o) (fu_dfu_device_get_instance_private (o)) + +static void fu_dfu_device_set_state (FuDfuDevice *self, FuDfuState state); + +static void +fu_dfu_device_to_string (FuDevice *device, guint idt, GString *str) +{ + FuDfuDevice *self = FU_DFU_DEVICE (device); + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + fu_common_string_append_kv (str, idt, "State", fu_dfu_state_to_string (priv->state)); + fu_common_string_append_kv (str, idt, "Status", fu_dfu_status_to_string (priv->status)); + fu_common_string_append_kb (str, idt, "DoneUploadOrDownload", priv->done_upload_or_download); + fu_common_string_append_kb (str, idt, "ClaimedInterface", priv->claimed_interface); + if (priv->chip_id != NULL) + fu_common_string_append_kv (str, idt, "ChipId", priv->chip_id); + fu_common_string_append_kx (str, idt, "Version", priv->version); + fu_common_string_append_kx (str, idt, "ForceVersion", priv->force_version); + if (priv->force_transfer_size != 0x0) { + fu_common_string_append_kx (str, idt, "ForceTransferSize", + priv->force_transfer_size); + } + fu_common_string_append_kx (str, idt, "RuntimePid", priv->runtime_pid); + fu_common_string_append_kx (str, idt, "RuntimeVid", priv->runtime_vid); + fu_common_string_append_kx (str, idt, "RuntimeRelease", priv->runtime_release); + fu_common_string_append_kx (str, idt, "TransferSize", priv->transfer_size); + fu_common_string_append_kx (str, idt, "IfaceNumber", priv->iface_number); + fu_common_string_append_kx (str, idt, "DnloadTimeout", priv->dnload_timeout); + fu_common_string_append_kx (str, idt, "TimeoutMs", priv->timeout_ms); + for (guint i = 0; i < priv->targets->len; i++) { + FuDfuTarget *target = g_ptr_array_index (priv->targets, i); + fu_dfu_target_to_string (target, idt + 1, str); + } +} + +/** + * fu_dfu_device_get_transfer_size: + * @device: a #GUsbDevice + * + * Gets the transfer size in bytes. + * + * Return value: packet size, or 0 for unknown + **/ +guint16 +fu_dfu_device_get_transfer_size (FuDfuDevice *self) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DFU_DEVICE (self), 0xffff); + return priv->transfer_size; +} + +/** + * fu_dfu_device_get_version: + * @self: a #FuDfuDevice + * + * Gets the DFU specification version supported by the device. + * + * Return value: integer, or 0 for unknown, e.g. %DFU_VERSION_DFU_1_1 + **/ +guint16 +fu_dfu_device_get_version (FuDfuDevice *self) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DFU_DEVICE (self), 0xffff); + return priv->version; +} + +/** + * fu_dfu_device_get_download_timeout: + * @self: a #FuDfuDevice + * + * Gets the download timeout in ms. + * + * Return value: delay, or 0 for unknown + **/ +guint +fu_dfu_device_get_download_timeout (FuDfuDevice *self) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DFU_DEVICE (self), 0); + return priv->dnload_timeout; +} + +/** + * fu_dfu_device_set_transfer_size: + * @self: a #FuDfuDevice + * @transfer_size: maximum packet size + * + * Sets the transfer size in bytes. + **/ +void +fu_dfu_device_set_transfer_size (FuDfuDevice *self, guint16 transfer_size) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_DFU_DEVICE (self)); + priv->transfer_size = transfer_size; +} + +typedef struct __attribute__((packed)) { + guint8 bLength; + guint8 bDescriptorType; + guint8 bmAttributes; + guint16 wDetachTimeOut; + guint16 wTransferSize; + guint16 bcdDFUVersion; +} DfuFuncDescriptor; + +static gboolean +fu_dfu_device_parse_iface_data (FuDfuDevice *self, GBytes *iface_data, GError **error) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + DfuFuncDescriptor desc = { 0x0 }; + const guint8 *buf; + gsize sz; + + /* parse the functional descriptor */ + buf = g_bytes_get_data (iface_data, &sz); + if (sz == sizeof(DfuFuncDescriptor)) { + memcpy (&desc, buf, sz); + } else if (sz > sizeof(DfuFuncDescriptor)) { + g_debug ("DFU interface with %" G_GSIZE_FORMAT " bytes vendor data", + sz - sizeof(DfuFuncDescriptor)); + memcpy (&desc, buf, sizeof(DfuFuncDescriptor)); + } else if (sz == sizeof(DfuFuncDescriptor) - 2) { + g_warning ("truncated DFU interface data, no bcdDFUVersion"); + memcpy (&desc, buf, sz); + desc.bcdDFUVersion = DFU_VERSION_DFU_1_1; + } else { + g_autoptr(GString) bufstr = g_string_new (NULL); + for (gsize i = 0; i < sz; i++) + g_string_append_printf (bufstr, "%02x ", buf[i]); + if (bufstr->len > 0) + g_string_truncate (bufstr, bufstr->len - 1); + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "interface found, but not the correct length for " + "functional data: %" G_GSIZE_FORMAT " bytes: %s", + sz, bufstr->str); + return FALSE; + } + + /* get transfer size and version */ + priv->transfer_size = GUINT16_FROM_LE (desc.wTransferSize); + priv->version = GUINT16_FROM_LE (desc.bcdDFUVersion); + + /* ST-specific */ + if (priv->version == DFU_VERSION_DFUSE && + desc.bmAttributes & FU_DFU_DEVICE_ATTR_CAN_ACCELERATE) + priv->transfer_size = 0x1000; + + /* get attributes about the DFU operation */ + priv->attributes = desc.bmAttributes; + return TRUE; +} + +static void +fu_dfu_device_guess_state_from_iface (FuDfuDevice *self, GUsbInterface *iface) +{ + /* some devices use the wrong interface */ + if (fu_device_has_custom_flag (FU_DEVICE (self), "force-dfu-mode")) { + g_debug ("quirking device into DFU mode"); + fu_dfu_device_set_state (self, FU_DFU_STATE_DFU_IDLE); + return; + } + + /* runtime */ + if (g_usb_interface_get_protocol (iface) == 0x01) { + fu_dfu_device_set_state (self, FU_DFU_STATE_APP_IDLE); + return; + } + + /* DFU */ + if (g_usb_interface_get_protocol (iface) == 0x02) { + fu_dfu_device_set_state (self, FU_DFU_STATE_DFU_IDLE); + return; + } + g_warning ("unable to guess initial device state from interface %u", + g_usb_interface_get_protocol (iface)); +} + +static gboolean +fu_dfu_device_add_targets (FuDfuDevice *self, GError **error) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + g_autoptr(GPtrArray) ifaces = NULL; + + /* add all DFU-capable targets */ + ifaces = g_usb_device_get_interfaces (usb_device, error); + if (ifaces == NULL) + return FALSE; + g_ptr_array_set_size (priv->targets, 0); + for (guint i = 0; i < ifaces->len; i++) { + GBytes *iface_data = NULL; + FuDfuTarget *target; + g_autoptr(GError) error_local = NULL; + + GUsbInterface *iface = g_ptr_array_index (ifaces, i); + + /* some devices don't use the right class and subclass */ + if (!fu_device_has_custom_flag (FU_DEVICE (self), "use-any-interface")) { + if (g_usb_interface_get_class (iface) != G_USB_DEVICE_CLASS_APPLICATION_SPECIFIC) + continue; + if (g_usb_interface_get_subclass (iface) != 0x01) + continue; + } + /* parse any interface data */ + iface_data = g_usb_interface_get_extra (iface); + if (g_bytes_get_size (iface_data) > 0) { + if (!fu_dfu_device_parse_iface_data (self, iface_data, &error_local)) { + g_warning ("failed to parse interface data for %04x:%04x: %s", + g_usb_device_get_vid (usb_device), + g_usb_device_get_pid (usb_device), + error_local->message); + continue; + } + } else { + priv->attributes |= FU_DFU_DEVICE_ATTR_CAN_DOWNLOAD | + FU_DFU_DEVICE_ATTR_CAN_UPLOAD; + } + + /* fix up the version */ + if (priv->force_version > 0) + priv->version = priv->force_version; + if (priv->version == DFU_VERSION_DFU_1_0 || + priv->version == DFU_VERSION_DFU_1_1) { + g_debug ("DFU v1.1"); + } else if (priv->version == DFU_VERSION_ATMEL_AVR) { + g_debug ("AVR-DFU support"); + priv->version = DFU_VERSION_ATMEL_AVR; + } else if (priv->version == DFU_VERSION_DFUSE) { + g_debug ("STM-DFU support"); + } else if (priv->version == 0x0101) { + g_debug ("DFU v1.1 assumed"); + priv->version = DFU_VERSION_DFU_1_1; + } else { + g_warning ("DFU version 0x%04x invalid, v1.1 assumed", priv->version); + priv->version = DFU_VERSION_DFU_1_1; + } + + /* set expected protocol */ + if (priv->version == DFU_VERSION_DFUSE) { + fu_device_add_protocol (FU_DEVICE (self), "com.st.dfuse"); + } else { + fu_device_add_protocol (FU_DEVICE (self), "org.usb.dfu"); + } + + /* fix up the transfer size */ + if (priv->force_transfer_size != 0x0) { + priv->transfer_size = priv->force_transfer_size; + g_debug ("forcing DFU transfer size 0x%04x bytes", priv->transfer_size); + } else if (priv->transfer_size == 0xffff) { + priv->transfer_size = 0x0400; + g_debug ("DFU transfer size unspecified, guessing"); + } else if (priv->transfer_size == 0x0) { + g_warning ("DFU transfer size invalid, using default"); + priv->transfer_size = 64; + } else { + g_debug ("using DFU transfer size 0x%04x bytes", + priv->transfer_size); + } + + /* create a target of the required type */ + switch (priv->version) { + case DFU_VERSION_DFUSE: + target = fu_dfu_target_stm_new (); + break; + case DFU_VERSION_ATMEL_AVR: + target = fu_dfu_target_avr_new (); + break; + default: + target = fu_dfu_target_new (); + break; + } + fu_dfu_target_set_device (target, self); + fu_dfu_target_set_alt_idx (target, g_usb_interface_get_index (iface)); + fu_dfu_target_set_alt_setting (target, g_usb_interface_get_alternate (iface)); + + /* add target */ + priv->iface_number = g_usb_interface_get_number (iface); + g_ptr_array_add (priv->targets, target); + fu_dfu_device_guess_state_from_iface (self, iface); + } + + /* save for reset */ + if (priv->state == FU_DFU_STATE_APP_IDLE || + fu_device_has_custom_flag (FU_DEVICE (self), "no-pid-change")) { + priv->runtime_vid = g_usb_device_get_vid (usb_device); + priv->runtime_pid = g_usb_device_get_pid (usb_device); + priv->runtime_release = g_usb_device_get_release (usb_device); + } + + /* the device has no DFU runtime, so cheat */ + if (priv->targets->len == 0 && + fu_device_has_custom_flag (FU_DEVICE (self), "no-fu-dfu-runtime")) { + g_debug ("no DFU runtime, so faking device"); + fu_dfu_device_set_state (self, FU_DFU_STATE_APP_IDLE); + priv->iface_number = 0xff; + priv->runtime_vid = g_usb_device_get_vid (usb_device); + priv->runtime_pid = g_usb_device_get_pid (usb_device); + priv->runtime_release = g_usb_device_get_release (usb_device); + priv->attributes = FU_DFU_DEVICE_ATTR_CAN_DOWNLOAD | + FU_DFU_DEVICE_ATTR_CAN_UPLOAD; + return TRUE; + } + + /* no targets */ + if (priv->targets->len == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "no DFU interfaces"); + return FALSE; + } + + /* the device upload is broken */ + if (fu_device_has_custom_flag (FU_DEVICE (self), "ignore-upload")) + priv->attributes &= ~FU_DFU_DEVICE_ATTR_CAN_UPLOAD; + + return TRUE; +} + +/** + * fu_dfu_device_can_upload: + * @self: a #FuDfuDevice + * + * Gets if the device can upload. + * + * Return value: %TRUE if the device can upload from device to host + **/ +gboolean +fu_dfu_device_can_upload (FuDfuDevice *self) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DFU_DEVICE (self), FALSE); + return (priv->attributes & FU_DFU_DEVICE_ATTR_CAN_UPLOAD) > 0; +} + +/** + * fu_dfu_device_can_download: + * @self: a #FuDfuDevice + * + * Gets if the device can download. + * + * Return value: %TRUE if the device can download from host to device + **/ +gboolean +fu_dfu_device_can_download (FuDfuDevice *self) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DFU_DEVICE (self), FALSE); + return (priv->attributes & FU_DFU_DEVICE_ATTR_CAN_DOWNLOAD) > 0; +} + +/** + * fu_dfu_device_set_timeout: + * @self: a #FuDfuDevice + * @timeout_ms: the timeout in ms + * + * Sets the USB timeout to use when contacting the USB device. + **/ +void +fu_dfu_device_set_timeout (FuDfuDevice *self, guint timeout_ms) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_DFU_DEVICE (self)); + priv->timeout_ms = timeout_ms; +} + +/** + * fu_dfu_device_get_timeout: + * @device: a #FuDfuDevice + * + * Gets the device timeout. + * + * Return value: enumerated timeout in ms + **/ +guint +fu_dfu_device_get_timeout (FuDfuDevice *self) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DFU_DEVICE (self), 0); + return priv->timeout_ms; +} + +/** + * fu_dfu_device_get_state: + * @device: a #FuDfuDevice + * + * Gets the device state. + * + * Return value: enumerated state, e.g. %FU_DFU_STATE_DFU_UPLOAD_IDLE + **/ +FuDfuState +fu_dfu_device_get_state (FuDfuDevice *self) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DFU_DEVICE (self), 0); + return priv->state; +} + +/** + * fu_dfu_device_get_status: + * @device: a #GUsbDevice + * + * Gets the device status. + * + * Return value: enumerated status, e.g. %FU_DFU_STATUS_ERR_ADDRESS + **/ +FuDfuStatus +fu_dfu_device_get_status (FuDfuDevice *self) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DFU_DEVICE (self), 0); + return priv->status; +} + +/** + * fu_dfu_device_has_attribute: (skip) + * @self: a #FuDfuDevice + * @attribute: A #FuDfuDeviceAttrs, e.g. %FU_DFU_DEVICE_ATTR_CAN_DOWNLOAD + * + * Returns if an attribute set for the device. + * + * Return value: %TRUE if the attribute is set + **/ +gboolean +fu_dfu_device_has_attribute (FuDfuDevice *self, FuDfuDeviceAttrs attribute) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DFU_DEVICE (self), FALSE); + return (priv->attributes & attribute) > 0; +} + +/** + * fu_dfu_device_remove_attribute: (skip) + * @self: a #FuDfuDevice + * @attribute: A #FuDfuDeviceAttrs, e.g. %FU_DFU_DEVICE_ATTR_CAN_DOWNLOAD + * + * Removes an attribute from the device. + **/ +void +fu_dfu_device_remove_attribute (FuDfuDevice *self, FuDfuDeviceAttrs attribute) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_DFU_DEVICE (self)); + priv->attributes &= ~attribute; +} + +/** + * fu_dfu_device_new: + * + * Creates a new DFU device object. + * + * Return value: a new #FuDfuDevice + **/ +FuDfuDevice * +fu_dfu_device_new (GUsbDevice *usb_device) +{ + FuDfuDevice *self; + self = g_object_new (FU_TYPE_DFU_DEVICE, + "usb-device", usb_device, + NULL); + return self; +} + +/** + * fu_dfu_device_get_targets: + * @self: a #FuDfuDevice + * + * Gets all the targets for this device. + * + * Return value: (transfer none) (element-type FuDfuTarget): #FuDfuTarget, or %NULL + **/ +GPtrArray * +fu_dfu_device_get_targets (FuDfuDevice *self) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DFU_DEVICE (self), NULL); + return priv->targets; +} + +/** + * fu_dfu_device_get_target_by_alt_setting: + * @self: a #FuDfuDevice + * @alt_setting: the setting used to find + * @error: a #GError, or %NULL + * + * Gets a target with a specific alternative setting. + * + * Return value: (transfer full): a #FuDfuTarget, or %NULL + **/ +FuDfuTarget * +fu_dfu_device_get_target_by_alt_setting (FuDfuDevice *self, + guint8 alt_setting, + GError **error) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + + g_return_val_if_fail (FU_IS_DFU_DEVICE (self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* find by ID */ + for (guint i = 0; i < priv->targets->len; i++) { + FuDfuTarget *target = g_ptr_array_index (priv->targets, i); + if (fu_dfu_target_get_alt_setting (target) == alt_setting) + return g_object_ref (target); + } + + /* failed */ + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "No target with alt-setting %i", + alt_setting); + return NULL; +} + +/** + * fu_dfu_device_get_target_by_alt_name: + * @self: a #FuDfuDevice + * @alt_name: the name used to find + * @error: a #GError, or %NULL + * + * Gets a target with a specific alternative name. + * + * Return value: (transfer full): a #FuDfuTarget, or %NULL + **/ +FuDfuTarget * +fu_dfu_device_get_target_by_alt_name (FuDfuDevice *self, + const gchar *alt_name, + GError **error) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + + g_return_val_if_fail (FU_IS_DFU_DEVICE (self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* find by ID */ + for (guint i = 0; i < priv->targets->len; i++) { + FuDfuTarget *target = g_ptr_array_index (priv->targets, i); + if (g_strcmp0 (fu_dfu_target_get_alt_name (target, NULL), alt_name) == 0) + return g_object_ref (target); + } + + /* failed */ + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "No target with alt-name %s", + alt_name); + return NULL; +} + +/** + * fu_dfu_device_get_platform_id: + * @self: a #FuDfuDevice + * + * Gets the platform ID which normally corresponds to the port in some way. + * + * Return value: string or %NULL + **/ +const gchar * +fu_dfu_device_get_platform_id (FuDfuDevice *self) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + g_return_val_if_fail (FU_IS_DFU_DEVICE (self), NULL); + return g_usb_device_get_platform_id (usb_device); +} + +/** + * fu_dfu_device_get_runtime_vid: + * @self: a #FuDfuDevice + * + * Gets the runtime vendor ID. + * + * Return value: vendor ID, or 0xffff for unknown + **/ +guint16 +fu_dfu_device_get_runtime_vid (FuDfuDevice *self) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DFU_DEVICE (self), 0xffff); + return priv->runtime_vid; +} + +/** + * fu_dfu_device_get_runtime_pid: + * @self: a #FuDfuDevice + * + * Gets the runtime product ID. + * + * Return value: product ID, or 0xffff for unknown + **/ +guint16 +fu_dfu_device_get_runtime_pid (FuDfuDevice *self) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DFU_DEVICE (self), 0xffff); + return priv->runtime_pid; +} + +/** + * fu_dfu_device_get_runtime_release: + * @self: a #FuDfuDevice + * + * Gets the runtime release number in BCD format. + * + * Return value: release number, or 0xffff for unknown + **/ +guint16 +fu_dfu_device_get_runtime_release (FuDfuDevice *self) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DFU_DEVICE (self), 0xffff); + return priv->runtime_release; +} + +const gchar * +fu_dfu_device_get_chip_id (FuDfuDevice *self) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DFU_DEVICE (self), NULL); + return priv->chip_id; +} + +void +fu_dfu_device_set_chip_id (FuDfuDevice *self, const gchar *chip_id) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_DFU_DEVICE (self)); + g_debug ("chip ID set to: %s", chip_id); + priv->chip_id = g_strdup (chip_id); +} + +static void +fu_dfu_device_set_state (FuDfuDevice *self, FuDfuState state) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + if (priv->state == state) + return; + priv->state = state; + + /* set bootloader status */ + if (state == FU_DFU_STATE_APP_IDLE || + state == FU_DFU_STATE_APP_DETACH) { + fu_device_remove_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + } else { + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + } +} + +static void +fu_dfu_device_set_status (FuDfuDevice *self, FuDfuStatus status) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + if (priv->status == status) + return; + priv->status = status; +} + +gboolean +fu_dfu_device_ensure_interface (FuDfuDevice *self, GError **error) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + g_autoptr(GError) error_local = NULL; + + /* already done */ + if (priv->claimed_interface) + return TRUE; + + /* nothing set */ + if (priv->iface_number == 0xff) + return TRUE; + + /* claim, without detaching kernel driver */ + if (!g_usb_device_claim_interface (usb_device, + (gint) priv->iface_number, + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + &error_local)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "cannot claim interface %i: %s", + priv->iface_number, error_local->message); + return FALSE; + } + + /* success */ + priv->claimed_interface = TRUE; + return TRUE; +} + +/** + * fu_dfu_device_refresh_and_clear: + * @self: a #FuDfuDevice + * @error: a #GError, or %NULL + * + * Refreshes the cached properties on the DFU device. If there are any transers + * in progress they are cancelled, and if there are any pending errors they are + * cancelled. + * + * Return value: %TRUE for success + **/ +gboolean +fu_dfu_device_refresh_and_clear (FuDfuDevice *self, GError **error) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + if (!fu_dfu_device_refresh (self, error)) + return FALSE; + switch (priv->state) { + case FU_DFU_STATE_DFU_UPLOAD_IDLE: + case FU_DFU_STATE_DFU_DNLOAD_IDLE: + case FU_DFU_STATE_DFU_DNLOAD_SYNC: + g_debug ("aborting transfer %s", fu_dfu_status_to_string (priv->status)); + if (!fu_dfu_device_abort (self, error)) + return FALSE; + break; + case FU_DFU_STATE_DFU_ERROR: + g_debug ("clearing error %s", fu_dfu_status_to_string (priv->status)); + if (!fu_dfu_device_clear_status (self, error)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +/** + * fu_dfu_device_refresh: + * @self: a #FuDfuDevice + * @error: a #GError, or %NULL + * + * Refreshes the cached properties on the DFU device. + * + * Return value: %TRUE for success + **/ +gboolean +fu_dfu_device_refresh (FuDfuDevice *self, GError **error) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + gsize actual_length = 0; + guint8 buf[6]; + g_autoptr(GError) error_local = NULL; + + g_return_val_if_fail (FU_IS_DFU_DEVICE (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* no backing USB device */ + if (usb_device == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to refresh: no GUsbDevice for %s", + fu_dfu_device_get_platform_id (self)); + return FALSE; + } + + /* the device has no DFU runtime, so cheat */ + if (priv->state == FU_DFU_STATE_APP_IDLE && + fu_device_has_custom_flag (FU_DEVICE (self), "no-fu-dfu-runtime")) + return TRUE; + + /* ensure interface is claimed */ + if (!fu_dfu_device_ensure_interface (self, error)) + return FALSE; + + /* Device that cannot communicate via the USB after the + * Manifestation phase indicated this limitation to the + * host by clearing bmAttributes bit bitManifestationTolerant. + * so we assume the operation was successful */ + if (priv->state == FU_DFU_STATE_DFU_MANIFEST && + !(priv->attributes & FU_DFU_DEVICE_ATTR_MANIFEST_TOL)) + return TRUE; + + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, + G_USB_DEVICE_REQUEST_TYPE_CLASS, + G_USB_DEVICE_RECIPIENT_INTERFACE, + FU_DFU_REQUEST_GETSTATUS, + 0, + priv->iface_number, + buf, sizeof(buf), &actual_length, + priv->timeout_ms, + NULL, /* cancellable */ + &error_local)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "cannot get device state: %s", + error_local->message); + return FALSE; + } + if (actual_length != 6) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "cannot get device status, invalid size: %04x", + (guint) actual_length); + return FALSE; + } + + /* some devices use the wrong state value */ + if (fu_device_has_custom_flag (FU_DEVICE (self), "force-dfu-mode") && + fu_dfu_device_get_state (self) != FU_DFU_STATE_DFU_IDLE) { + g_debug ("quirking device into DFU mode"); + fu_dfu_device_set_state (self, FU_DFU_STATE_DFU_IDLE); + } else { + fu_dfu_device_set_state (self, buf[4]); + } + + /* status or state changed */ + fu_dfu_device_set_status (self, buf[0]); + if (fu_device_has_custom_flag (FU_DEVICE (self), "ignore-polltimeout")) { + priv->dnload_timeout = DFU_DEVICE_DNLOAD_TIMEOUT_DEFAULT; + } else { + priv->dnload_timeout = buf[1] + + (((guint32) buf[2]) << 8) + + (((guint32) buf[3]) << 16); + if (priv->dnload_timeout == 0) { + priv->dnload_timeout = DFU_DEVICE_DNLOAD_TIMEOUT_DEFAULT; + g_debug ("no dnload-timeout, using default of %ums", + priv->dnload_timeout); + } + } + g_debug ("refreshed status=%s and state=%s (dnload=%u)", + fu_dfu_status_to_string (priv->status), + fu_dfu_state_to_string (priv->state), + priv->dnload_timeout); + return TRUE; +} + +static gboolean +fu_dfu_device_request_detach (FuDfuDevice *self, GError **error) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + const guint16 timeout_reset_ms = 1000; + g_autoptr(GError) error_local = NULL; + + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_CLASS, + G_USB_DEVICE_RECIPIENT_INTERFACE, + FU_DFU_REQUEST_DETACH, + timeout_reset_ms, + priv->iface_number, + NULL, 0, NULL, + priv->timeout_ms, + NULL, /* cancellable */ + &error_local)) { + /* some devices just reboot and stall the endpoint :/ */ + if (g_error_matches (error_local, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_NOT_SUPPORTED) || + g_error_matches (error_local, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_FAILED)) { + g_debug ("ignoring while detaching: %s", error_local->message); + } else { + /* refresh the error code */ + fu_dfu_device_error_fixup (self, &error_local); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "cannot detach device: %s", + error_local->message); + return FALSE; + } + } + return TRUE; +} + +static gboolean +fu_dfu_device_reload (FuDevice *device, GError **error) +{ + FuDfuDevice *self = FU_DFU_DEVICE (device); + return fu_dfu_device_refresh_and_clear (self, error); +} + +static gboolean +fu_dfu_device_detach (FuDevice *device, GError **error) +{ + FuDfuDevice *self = FU_DFU_DEVICE (device); + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + + g_return_val_if_fail (FU_IS_DFU_DEVICE (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* already in DFU mode */ + if (!fu_dfu_device_refresh_and_clear (self, error)) + return FALSE; + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) + return TRUE; + + /* no backing USB device */ + if (usb_device == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to detach: no GUsbDevice for %s", + fu_dfu_device_get_platform_id (self)); + return FALSE; + } + + /* the device has no DFU runtime, so cheat */ + if (priv->state == FU_DFU_STATE_APP_IDLE && + fu_device_has_custom_flag (FU_DEVICE (self), "no-fu-dfu-runtime")) + return TRUE; + + /* ensure interface is claimed */ + if (!fu_dfu_device_ensure_interface (self, error)) + return FALSE; + + /* inform UI there's going to be a detach:attach */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + if (!fu_dfu_device_request_detach (self, error)) + return FALSE; + + /* do a host reset */ + if ((priv->attributes & FU_DFU_DEVICE_ATTR_WILL_DETACH) == 0) { + g_debug ("doing device reset as host will not self-reset"); + if (!fu_dfu_device_reset (self, error)) + return FALSE; + } + + /* success */ + priv->force_version = 0x0; + fu_device_set_status (device, FWUPD_STATUS_IDLE); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + return TRUE; +} + +/** + * fu_dfu_device_abort: + * @self: a #FuDfuDevice + * @error: a #GError, or %NULL + * + * Aborts any upload or download in progress. + * + * Return value: %TRUE for success + **/ +gboolean +fu_dfu_device_abort (FuDfuDevice *self, GError **error) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + g_autoptr(GError) error_local = NULL; + + g_return_val_if_fail (FU_IS_DFU_DEVICE (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* no backing USB device */ + if (usb_device == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to abort: no GUsbDevice for %s", + fu_dfu_device_get_platform_id (self)); + return FALSE; + } + + /* the device has no DFU runtime, so cheat */ + if (priv->state == FU_DFU_STATE_APP_IDLE && + fu_device_has_custom_flag (FU_DEVICE (self), "no-fu-dfu-runtime")) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "not supported as no DFU runtime"); + return FALSE; + } + + /* ensure interface is claimed */ + if (!fu_dfu_device_ensure_interface (self, error)) + return FALSE; + + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_CLASS, + G_USB_DEVICE_RECIPIENT_INTERFACE, + FU_DFU_REQUEST_ABORT, + 0, + priv->iface_number, + NULL, 0, NULL, + priv->timeout_ms, + NULL, /* cancellable */ + &error_local)) { + /* refresh the error code */ + fu_dfu_device_error_fixup (self, &error_local); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "cannot abort device: %s", + error_local->message); + return FALSE; + } + + return TRUE; +} + +/** + * fu_dfu_device_clear_status: + * @self: a #FuDfuDevice + * @error: a #GError, or %NULL + * + * Clears any error status on the DFU device. + * + * Return value: %TRUE for success + **/ +gboolean +fu_dfu_device_clear_status (FuDfuDevice *self, GError **error) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + g_autoptr(GError) error_local = NULL; + + g_return_val_if_fail (FU_IS_DFU_DEVICE (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* no backing USB device */ + if (usb_device == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to clear status: no GUsbDevice for %s", + fu_dfu_device_get_platform_id (self)); + return FALSE; + } + + /* the device has no DFU runtime, so cheat */ + if (priv->state == FU_DFU_STATE_APP_IDLE && + fu_device_has_custom_flag (FU_DEVICE (self), "no-fu-dfu-runtime")) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "not supported as no DFU runtime"); + return FALSE; + } + + /* ensure interface is claimed */ + if (!fu_dfu_device_ensure_interface (self, error)) + return FALSE; + + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_CLASS, + G_USB_DEVICE_RECIPIENT_INTERFACE, + FU_DFU_REQUEST_CLRSTATUS, + 0, + priv->iface_number, + NULL, 0, NULL, + priv->timeout_ms, + NULL, /* cancellable */ + &error_local)) { + /* refresh the error code */ + fu_dfu_device_error_fixup (self, &error_local); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "cannot clear status on the device: %s", + error_local->message); + return FALSE; + } + return TRUE; +} + +/** + * fu_dfu_device_get_interface: + * @self: a #FuDfuDevice + * + * Gets the interface number. + **/ +guint8 +fu_dfu_device_get_interface (FuDfuDevice *self) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DFU_DEVICE (self), 0xff); + return priv->iface_number; +} + +/** + * fu_dfu_device_open: + * @self: a #FuDfuDevice + * @error: a #GError, or %NULL + * + * Opens a DFU-capable device. + * + * Return value: %TRUE for success + **/ +static gboolean +fu_dfu_device_open (FuDevice *device, GError **error) +{ + FuDfuDevice *self = FU_DFU_DEVICE (device); + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + GPtrArray *targets = fu_dfu_device_get_targets (self); + + g_return_val_if_fail (FU_IS_DFU_DEVICE (device), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* FuUsbDevice->open */ + if (!FU_DEVICE_CLASS (fu_dfu_device_parent_class)->open (device, error)) + return FALSE; + + /* the device has no DFU runtime, so cheat */ + if (priv->state == FU_DFU_STATE_APP_IDLE && + fu_device_has_custom_flag (device, "no-fu-dfu-runtime")) { + fu_dfu_device_set_state (self, FU_DFU_STATE_APP_IDLE); + priv->status = FU_DFU_STATUS_OK; + } + + /* GD32VF103 encodes the serial number in UTF-8 (rather than UTF-16) + * and also uses the first two bytes as the model identifier */ + if (fu_device_has_custom_flag (FU_DEVICE (device), "gd32")) { +#if G_USB_CHECK_VERSION(0,3,6) + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + const guint8 *buf; + gsize bufsz = 0; + guint16 langid = G_USB_DEVICE_LANGID_ENGLISH_UNITED_STATES; + guint8 idx = g_usb_device_get_serial_number_index (usb_device); + g_autofree gchar *chip_id = NULL; + g_autofree gchar *serial_str = NULL; + g_autoptr(GBytes) serial_blob = NULL; + serial_blob = g_usb_device_get_string_descriptor_bytes (usb_device, + idx, + langid, + error); + if (serial_blob == NULL) + return FALSE; + if (g_getenv ("FWUPD_DFU_VERBOSE") != NULL) + fu_common_dump_bytes (G_LOG_DOMAIN, "GD32 serial", serial_blob); + buf = g_bytes_get_data (serial_blob, &bufsz); + if (bufsz < 2) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "GD32 serial number invalid"); + return FALSE; + } + + /* ID is first two bytes */ + chip_id = g_strdup_printf ("%02x%02x", buf[0], buf[1]); + fu_dfu_device_set_chip_id (self, chip_id); + + /* serial number follows */ + serial_str = g_strndup ((const gchar *) buf + 2, bufsz - 2); + fu_device_set_serial (FU_DEVICE (device), serial_str); +#else + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "GUsb version %s too old to support GD32, " + "fwupd needs to be rebuilt against 0.3.6 or later", + g_usb_version_string ()); + return FALSE; +#endif + } + + /* set up target ready for use */ + for (guint j = 0; j < targets->len; j++) { + FuDfuTarget *target = g_ptr_array_index (targets, j); + if (!fu_dfu_target_setup (target, error)) + return FALSE; + } + + /* success */ + return TRUE; +} + +/** + * fu_dfu_device_close: + * @self: a #FuDfuDevice + * @error: a #GError, or %NULL + * + * Closes a DFU device. + * + * Return value: %TRUE for success + **/ +static gboolean +fu_dfu_device_close (FuDevice *device, GError **error) +{ + FuDfuDevice *self = FU_DFU_DEVICE (device); + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + + /* release interface */ + if (priv->claimed_interface) { + g_autoptr(GError) error_local = NULL; + if (!g_usb_device_release_interface (usb_device, + (gint) priv->iface_number, + 0, &error_local)) { + g_warning ("failed to release interface: %s", + error_local->message); + } + priv->claimed_interface = FALSE; + } + + /* FuUsbDevice->close */ + return FU_DEVICE_CLASS (fu_dfu_device_parent_class)->close (device, error); +} + +static gboolean +fu_dfu_device_probe (FuDevice *device, GError **error) +{ + FuDfuDevice *self = FU_DFU_DEVICE (device); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + + /* FuUsbDevice->probe */ + if (!FU_DEVICE_CLASS (fu_dfu_device_parent_class)->probe (device, error)) + return FALSE; + + /* add all the targets */ + if (!fu_dfu_device_add_targets (self, error)) { + g_prefix_error (error, "%04x:%04x is not supported: ", + g_usb_device_get_vid (usb_device), + g_usb_device_get_pid (usb_device)); + return FALSE; + } + + /* check capabilities */ + if (!fu_dfu_device_can_download (self)) { + g_warning ("%04x:%04x is missing download capability", + g_usb_device_get_vid (usb_device), + g_usb_device_get_pid (usb_device)); + } + + /* hardware from Jabra literally reboots if you try to retry a failed + * write -- there's no way to avoid blocking the daemon like this... */ + if (fu_device_has_custom_flag (device, "attach-extra-reset")) + fu_device_sleep_with_progress (device, 10); /* seconds */ + + /* success */ + return TRUE; +} + +/** + * fu_dfu_device_reset: + * @self: a #FuDfuDevice + * @error: a #GError, or %NULL + * + * Resets the USB device. + * + * Return value: %TRUE for success + **/ +gboolean +fu_dfu_device_reset (FuDfuDevice *self, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + g_autoptr(GError) error_local = NULL; + g_autoptr(GTimer) timer = g_timer_new (); + + g_return_val_if_fail (FU_IS_DFU_DEVICE (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* no backing USB device */ + if (usb_device == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to reset: no GUsbDevice for %s", + fu_dfu_device_get_platform_id (self)); + return FALSE; + } + + if (!g_usb_device_reset (usb_device, &error_local)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "cannot reset USB device: %s [%i]", + error_local->message, + error_local->code); + return FALSE; + } + g_debug ("reset took %.2lfms", g_timer_elapsed (timer, NULL) * 1000); + return TRUE; +} + +static gboolean +fu_dfu_device_attach (FuDevice *device, GError **error) +{ + FuDfuDevice *self = FU_DFU_DEVICE (device); + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + g_autoptr(FuDfuTarget) target = NULL; + + g_return_val_if_fail (FU_IS_DFU_DEVICE (device), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* already in runtime mode */ + if (!fu_dfu_device_refresh_and_clear (self, error)) + return FALSE; + if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) + return TRUE; + + /* inform UI there's going to be a re-attach */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + + /* handle weirdness */ + if (fu_device_has_custom_flag (device, "detach-for-attach")) { + if (!fu_dfu_device_request_detach (self, error)) + return FALSE; + fu_device_set_status (device, FWUPD_STATUS_IDLE); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + return TRUE; + } + + /* handle m-stack DFU bootloaders */ + if (!priv->done_upload_or_download && + fu_device_has_custom_flag (device, "attach-upload-download")) { + g_autoptr(GBytes) chunk = NULL; + g_autoptr(FuDfuTarget) target_zero = NULL; + g_debug ("doing dummy upload to work around m-stack quirk"); + target_zero = fu_dfu_device_get_target_by_alt_setting (self, 0, error); + if (target_zero == NULL) + return FALSE; + chunk = fu_dfu_target_upload_chunk (target_zero, 0, 0, error); + if (chunk == NULL) + return FALSE; + } + + /* get default target */ + target = fu_dfu_device_get_target_by_alt_setting (self, 0, error); + if (target == NULL) + return FALSE; + + /* normal DFU mode just needs a bus reset */ + if (fu_device_has_custom_flag (device, "no-bus-reset-attach") && + fu_dfu_device_has_attribute (self, FU_DFU_DEVICE_ATTR_WILL_DETACH)) + g_debug ("Bus reset is not required. Device will reboot to normal"); + else if (!fu_dfu_target_attach (target, error)) + return FALSE; + + /* success */ + priv->force_version = 0x0; + fu_device_set_status (device, FWUPD_STATUS_IDLE); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + return TRUE; +} + +static void +fu_dfu_device_percentage_cb (FuDfuTarget *target, guint percentage, FuDfuDevice *self) +{ + fu_device_set_progress (FU_DEVICE (self), percentage); +} + +static void +fu_dfu_device_action_cb (FuDfuTarget *target, FwupdStatus action, FuDfuDevice *self) +{ + fu_device_set_status (FU_DEVICE (self), action); +} + +/** + * fu_dfu_device_upload: + * @self: a #FuDfuDevice + * @flags: flags to use, e.g. %DFU_TARGET_TRANSFER_FLAG_VERIFY + * @error: a #GError, or %NULL + * + * Uploads firmware from the target to the host. + * + * Return value: (transfer full): the uploaded firmware, or %NULL for error + **/ +FuFirmware * +fu_dfu_device_upload (FuDfuDevice *self, + FuDfuTargetTransferFlags flags, + GError **error) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + g_autoptr(FuFirmware) firmware = NULL; + + /* no backing USB device */ + if (usb_device == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to upload: no GUsbDevice for %s", + fu_dfu_device_get_platform_id (self)); + return NULL; + } + + /* ensure interface is claimed */ + if (!fu_dfu_device_ensure_interface (self, error)) + return NULL; + + /* choose the most appropriate type */ + if (priv->targets->len > 1) { + firmware = fu_dfuse_firmware_new (); + g_debug ("switching to DefuSe automatically"); + } else { + firmware = fu_dfu_firmware_new (); + } + fu_dfu_firmware_set_vid (FU_DFU_FIRMWARE (firmware), priv->runtime_vid); + fu_dfu_firmware_set_pid (FU_DFU_FIRMWARE (firmware), priv->runtime_pid); + fu_dfu_firmware_set_release (FU_DFU_FIRMWARE (firmware), 0xffff); + + /* upload from each target */ + for (guint i = 0; i < priv->targets->len; i++) { + FuDfuTarget *target; + const gchar *alt_name; + gulong id1; + gulong id2; + + /* upload to target and proxy signals */ + target = g_ptr_array_index (priv->targets, i); + + /* ignore some target types */ + alt_name = fu_dfu_target_get_alt_name_for_display (target, NULL); + if (g_strcmp0 (alt_name, "Option Bytes") == 0) { + g_debug ("ignoring target %s", alt_name); + continue; + } + + id1 = g_signal_connect (target, "percentage-changed", + G_CALLBACK (fu_dfu_device_percentage_cb), self); + id2 = g_signal_connect (target, "action-changed", + G_CALLBACK (fu_dfu_device_action_cb), self); + if (!fu_dfu_target_upload (target, + firmware, + DFU_TARGET_TRANSFER_FLAG_NONE, + error)) + return NULL; + g_signal_handler_disconnect (target, id1); + g_signal_handler_disconnect (target, id2); + } + + /* do not do the dummy upload for quirked devices */ + priv->done_upload_or_download = TRUE; + + /* success */ + fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_IDLE); + return g_object_ref (firmware); +} + +static gboolean +fu_dfu_device_id_compatible (guint16 id_file, guint16 id_runtime, guint16 id_dev) +{ + /* file doesn't specify */ + if (id_file == 0xffff) + return TRUE; + + /* runtime matches */ + if (id_runtime != 0xffff && id_file == id_runtime) + return TRUE; + + /* bootloader matches */ + if (id_dev != 0xffff && id_file == id_dev) + return TRUE; + + /* nothing */ + return FALSE; +} + +static gboolean +fu_dfu_device_download (FuDfuDevice *self, + FuFirmware *firmware, + FuDfuTargetTransferFlags flags, + GError **error) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + gboolean ret; + g_autoptr(GPtrArray) images = NULL; + guint16 firmware_pid = 0xffff; + guint16 firmware_vid = 0xffff; + + /* no backing USB device */ + if (usb_device == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to download: no GUsbDevice for %s", + fu_dfu_device_get_platform_id (self)); + return FALSE; + } + + /* ensure interface is claimed */ + if (!fu_dfu_device_ensure_interface (self, error)) + return FALSE; + + /* firmware supports footer? */ + if (FU_IS_DFU_FIRMWARE (firmware)) { + firmware_vid = fu_dfu_firmware_get_vid (FU_DFU_FIRMWARE (firmware)); + firmware_pid = fu_dfu_firmware_get_pid (FU_DFU_FIRMWARE (firmware)); + } + + /* do we allow wildcard VID:PID matches */ + if ((flags & DFU_TARGET_TRANSFER_FLAG_WILDCARD_VID) == 0) { + if (firmware_vid == 0xffff) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "firmware vendor ID not specified"); + return FALSE; + } + } + if ((flags & DFU_TARGET_TRANSFER_FLAG_WILDCARD_PID) == 0) { + if (firmware_pid == 0xffff) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "firmware product ID not specified"); + return FALSE; + } + } + + /* check vendor matches */ + if (priv->runtime_vid != 0xffff) { + if (!fu_dfu_device_id_compatible (firmware_vid, priv->runtime_vid, + fu_usb_device_get_vid (FU_USB_DEVICE (self)))) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "vendor ID incorrect, expected 0x%04x " + "got 0x%04x and 0x%04x\n", + firmware_vid, + priv->runtime_vid, + fu_usb_device_get_vid (FU_USB_DEVICE (self))); + return FALSE; + } + } + + /* check product matches */ + if (priv->runtime_pid != 0xffff) { + if (!fu_dfu_device_id_compatible (firmware_pid, priv->runtime_pid, + fu_usb_device_get_pid (FU_USB_DEVICE (self)))) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "product ID incorrect, expected 0x%04x " + "got 0x%04x and 0x%04x", + firmware_pid, + priv->runtime_pid, + fu_usb_device_get_pid (FU_USB_DEVICE (self))); + return FALSE; + } + } + + /* download each target */ + images = fu_firmware_get_images (firmware); + if (images->len == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "no images in firmware file"); + return FALSE; + } + for (guint i = 0; i < images->len; i++) { + FuFirmwareImage *image = g_ptr_array_index (images, i); + FuDfuTargetTransferFlags flags_local = DFU_TARGET_TRANSFER_FLAG_NONE; + const gchar *alt_name; + guint8 alt; + gulong id1; + gulong id2; + g_autoptr(FuDfuTarget) target_tmp = NULL; + g_autoptr(GError) error_local = NULL; + + alt = fu_firmware_image_get_idx (image); + target_tmp = fu_dfu_device_get_target_by_alt_setting (self, alt, error); + if (target_tmp == NULL) + return FALSE; + + /* we don't actually need to print this */ + alt_name = fu_dfu_target_get_alt_name (target_tmp, &error_local); + if (alt_name == NULL) { + if (g_error_matches (error_local, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND)) { + alt_name = "unknown"; + } else { + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; + } + } + g_debug ("downloading to target: %s", alt_name); + + /* download onto target */ + if (flags & DFU_TARGET_TRANSFER_FLAG_VERIFY) + flags_local = DFU_TARGET_TRANSFER_FLAG_VERIFY; + if (!FU_IS_DFU_FIRMWARE (firmware) || + fu_dfu_firmware_get_version (FU_DFU_FIRMWARE (firmware)) == 0x0) + flags_local |= DFU_TARGET_TRANSFER_FLAG_ADDR_HEURISTIC; + id1 = g_signal_connect (target_tmp, "percentage-changed", + G_CALLBACK (fu_dfu_device_percentage_cb), self); + id2 = g_signal_connect (target_tmp, "action-changed", + G_CALLBACK (fu_dfu_device_action_cb), self); + ret = fu_dfu_target_download (target_tmp, image, flags_local, error); + g_signal_handler_disconnect (target_tmp, id1); + g_signal_handler_disconnect (target_tmp, id2); + if (!ret) + return FALSE; + } + + /* do not do the dummy upload for quirked devices */ + priv->done_upload_or_download = TRUE; + + /* success */ + fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_IDLE); + return TRUE; +} + +void +fu_dfu_device_error_fixup (FuDfuDevice *self, GError **error) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + + /* sad panda */ + if (error == NULL) + return; + + /* not the right error to query */ + if (!g_error_matches (*error, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_NOT_SUPPORTED)) + return; + + /* get the status */ + if (!fu_dfu_device_refresh (self, NULL)) + return; + + /* not in an error state */ + if (priv->state != FU_DFU_STATE_DFU_ERROR) + return; + + /* prefix the error */ + switch (priv->status) { + case FU_DFU_STATUS_OK: + /* ignore */ + break; + case FU_DFU_STATUS_ERR_VENDOR: + g_prefix_error (error, "read protection is active: "); + break; + default: + g_prefix_error (error, "[%s,%s]: ", + fu_dfu_state_to_string (priv->state), + fu_dfu_status_to_string (priv->status)); + break; + } +} + +static GBytes * +fu_dfu_device_dump_firmware (FuDevice *device, GError **error) +{ + FuDfuDevice *self = FU_DFU_DEVICE (device); + g_autoptr(FuFirmware) firmware = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; + + /* require detach -> attach */ + locker = fu_device_locker_new_full (device, + (FuDeviceLockerFunc) fu_device_detach, + (FuDeviceLockerFunc) fu_device_attach, + error); + if (locker == NULL) + return NULL; + + /* get data from hardware */ + g_debug ("uploading from device->host"); + if (!fu_dfu_device_refresh_and_clear (self, error)) + return NULL; + firmware = fu_dfu_device_upload (self, DFU_TARGET_TRANSFER_FLAG_NONE, error); + if (firmware == NULL) + return NULL; + + /* get the checksum */ + return fu_firmware_write (firmware, error); +} + +static FuFirmware * +fu_dfu_device_prepare_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + return fu_firmware_new_from_gtypes (fw, flags, error, + FU_TYPE_DFUSE_FIRMWARE, + FU_TYPE_DFU_FIRMWARE, + FU_TYPE_FIRMWARE, + G_TYPE_INVALID); +} + +static gboolean +fu_dfu_device_write_firmware (FuDevice *device, + FuFirmware *firmware, + FwupdInstallFlags flags, + GError **error) +{ + FuDfuDevice *self = FU_DFU_DEVICE (device); + FuDfuTargetTransferFlags transfer_flags = DFU_TARGET_TRANSFER_FLAG_VERIFY; + + /* open it */ + if (!fu_dfu_device_refresh_and_clear (self, error)) + return FALSE; + if (flags & FWUPD_INSTALL_FLAG_IGNORE_VID_PID) { + transfer_flags |= DFU_TARGET_TRANSFER_FLAG_WILDCARD_VID; + transfer_flags |= DFU_TARGET_TRANSFER_FLAG_WILDCARD_PID; + } + + /* hit hardware */ + return fu_dfu_device_download (self, firmware, transfer_flags, error); +} + +static gboolean +fu_dfu_device_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + FuDfuDevice *self = FU_DFU_DEVICE (device); + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + + if (g_strcmp0 (key, FU_QUIRKS_DFU_FORCE_VERSION) == 0) { + if (value != NULL) { + gsize valuesz = strlen (value); + return fu_firmware_strparse_uint16_safe (value, valuesz, 0, + &priv->force_version, + error); + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid DFU version"); + return FALSE; + } + if (g_strcmp0 (key, "DfuForceTimeout") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp < G_MAXUINT) { + priv->timeout_ms = tmp; + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid DFU timeout"); + return FALSE; + } + if (g_strcmp0 (key, "DfuForceTransferSize") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp < G_MAXUINT16) { + priv->force_transfer_size = tmp; + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid DFU transfer size"); + return FALSE; + } + if (g_strcmp0 (key, "DfuAltName") == 0) { + fu_dfu_device_set_chip_id (self, value); + return TRUE; + } + + /* failed */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; +} + +/** + * fu_dfu_device_get_attributes_as_string: (skip) + * @self: a #FuDfuDevice + * + * Gets a string describing the attributes for a device. + * + * Return value: a string, possibly empty + **/ +gchar * +fu_dfu_device_get_attributes_as_string (FuDfuDevice *self) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + GString *str; + + /* just append to a string */ + str = g_string_new (""); + if (priv->attributes & FU_DFU_DEVICE_ATTR_CAN_DOWNLOAD) + g_string_append_printf (str, "can-download|"); + if (priv->attributes & FU_DFU_DEVICE_ATTR_CAN_UPLOAD) + g_string_append_printf (str, "can-upload|"); + if (priv->attributes & FU_DFU_DEVICE_ATTR_MANIFEST_TOL) + g_string_append_printf (str, "manifest-tol|"); + if (priv->attributes & FU_DFU_DEVICE_ATTR_WILL_DETACH) + g_string_append_printf (str, "will-detach|"); + if (priv->attributes & FU_DFU_DEVICE_ATTR_CAN_ACCELERATE) + g_string_append_printf (str, "can-accelerate|"); + + /* remove trailing pipe */ + g_string_truncate (str, str->len - 1); + return g_string_free (str, FALSE); +} + +static void +fu_dfu_device_finalize (GObject *object) +{ + FuDfuDevice *self = FU_DFU_DEVICE (object); + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + + g_free (priv->chip_id); + g_ptr_array_unref (priv->targets); + + G_OBJECT_CLASS (fu_dfu_device_parent_class)->finalize (object); +} + +static void +fu_dfu_device_class_init (FuDfuDeviceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + klass_device->set_quirk_kv = fu_dfu_device_set_quirk_kv; + klass_device->to_string = fu_dfu_device_to_string; + klass_device->dump_firmware = fu_dfu_device_dump_firmware; + klass_device->write_firmware = fu_dfu_device_write_firmware; + klass_device->prepare_firmware = fu_dfu_device_prepare_firmware; + klass_device->attach = fu_dfu_device_attach; + klass_device->detach = fu_dfu_device_detach; + klass_device->reload = fu_dfu_device_reload; + klass_device->open = fu_dfu_device_open; + klass_device->close = fu_dfu_device_close; + klass_device->probe = fu_dfu_device_probe; + object_class->finalize = fu_dfu_device_finalize; +} + +static void +fu_dfu_device_init (FuDfuDevice *self) +{ + FuDfuDevicePrivate *priv = GET_PRIVATE (self); + priv->iface_number = 0xff; + priv->runtime_pid = 0xffff; + priv->runtime_vid = 0xffff; + priv->runtime_release = 0xffff; + priv->state = FU_DFU_STATE_APP_IDLE; + priv->status = FU_DFU_STATUS_OK; + priv->targets = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + priv->timeout_ms = 1500; + priv->transfer_size = 64; + fu_device_add_icon (FU_DEVICE (self), "drive-harddisk-usb"); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_ADD_COUNTERPART_GUIDS); + fu_device_add_internal_flag (FU_DEVICE (self), FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID); + fu_device_set_remove_delay (FU_DEVICE (self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); +} diff -Nru fwupd-1.4.5/plugins/dfu/fu-dfu-device.h fwupd-1.5.8/plugins/dfu/fu-dfu-device.h --- fwupd-1.4.5/plugins/dfu/fu-dfu-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/fu-dfu-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2015 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include +#include +#include + +#include "fu-usb-device.h" + +#include "fu-dfu-common.h" +#include "fu-dfu-target.h" + +#define FU_TYPE_DFU_DEVICE (fu_dfu_device_get_type ()) +G_DECLARE_DERIVABLE_TYPE (FuDfuDevice, fu_dfu_device, FU, DFU_DEVICE, FuUsbDevice) + +/** + * FuDfuDeviceAttrs: + * @FU_DFU_DEVICE_ATTR_NONE: No attributes set + * @FU_DFU_DEVICE_ATTR_CAN_DOWNLOAD: Can download from host->device + * @FU_DFU_DEVICE_ATTR_CAN_UPLOAD: Can upload from device->host + * @FU_DFU_DEVICE_ATTR_MANIFEST_TOL: Can answer GetStatus in manifest + * @FU_DFU_DEVICE_ATTR_WILL_DETACH: Will self-detach + * @FU_DFU_DEVICE_ATTR_CAN_ACCELERATE: Use a larger transfer size for speed + * + * The device DFU attributes. + **/ +typedef enum { + FU_DFU_DEVICE_ATTR_NONE = 0, + FU_DFU_DEVICE_ATTR_CAN_DOWNLOAD = (1 << 0), + FU_DFU_DEVICE_ATTR_CAN_UPLOAD = (1 << 1), + FU_DFU_DEVICE_ATTR_MANIFEST_TOL = (1 << 2), + FU_DFU_DEVICE_ATTR_WILL_DETACH = (1 << 3), + FU_DFU_DEVICE_ATTR_CAN_ACCELERATE = (1 << 7), + /*< private >*/ + FU_DFU_DEVICE_ATTR_LAST +} FuDfuDeviceAttrs; + +struct _FuDfuDeviceClass +{ + FuUsbDeviceClass parent_class; +}; + +FuDfuDevice *fu_dfu_device_new (GUsbDevice *usb_device); +const gchar *fu_dfu_device_get_platform_id (FuDfuDevice *self); +GPtrArray *fu_dfu_device_get_targets (FuDfuDevice *self); +FuDfuTarget *fu_dfu_device_get_target_by_alt_setting(FuDfuDevice *self, + guint8 alt_setting, + GError **error); +FuDfuTarget *fu_dfu_device_get_target_by_alt_name (FuDfuDevice *self, + const gchar *alt_name, + GError **error); +const gchar *fu_dfu_device_get_chip_id (FuDfuDevice *self); +void fu_dfu_device_set_chip_id (FuDfuDevice *self, + const gchar *chip_id); +guint16 fu_dfu_device_get_runtime_vid (FuDfuDevice *self); +guint16 fu_dfu_device_get_runtime_pid (FuDfuDevice *self); +guint16 fu_dfu_device_get_runtime_release (FuDfuDevice *self); +gboolean fu_dfu_device_reset (FuDfuDevice *self, + GError **error); +FuFirmware *fu_dfu_device_upload (FuDfuDevice *self, + FuDfuTargetTransferFlags flags, + GError **error); +gboolean fu_dfu_device_refresh (FuDfuDevice *self, + GError **error); +gboolean fu_dfu_device_refresh_and_clear (FuDfuDevice *self, + GError **error); +gboolean fu_dfu_device_abort (FuDfuDevice *self, + GError **error); +gboolean fu_dfu_device_clear_status (FuDfuDevice *self, + GError **error); + +guint8 fu_dfu_device_get_interface (FuDfuDevice *self); +FuDfuState fu_dfu_device_get_state (FuDfuDevice *self); +FuDfuStatus fu_dfu_device_get_status (FuDfuDevice *self); +guint16 fu_dfu_device_get_transfer_size (FuDfuDevice *self); +guint16 fu_dfu_device_get_version (FuDfuDevice *self); +guint fu_dfu_device_get_timeout (FuDfuDevice *self); +gboolean fu_dfu_device_can_upload (FuDfuDevice *self); +gboolean fu_dfu_device_can_download (FuDfuDevice *self); + +gboolean fu_dfu_device_has_attribute (FuDfuDevice *self, + FuDfuDeviceAttrs attribute); +void fu_dfu_device_remove_attribute (FuDfuDevice *self, + FuDfuDeviceAttrs attribute); + +void fu_dfu_device_set_transfer_size (FuDfuDevice *self, + guint16 transfer_size); +void fu_dfu_device_set_timeout (FuDfuDevice *self, + guint timeout_ms); +void fu_dfu_device_error_fixup (FuDfuDevice *self, + GError **error); +guint fu_dfu_device_get_download_timeout (FuDfuDevice *self); +gchar *fu_dfu_device_get_attributes_as_string (FuDfuDevice *self); +gboolean fu_dfu_device_ensure_interface (FuDfuDevice *self, + GError **error); diff -Nru fwupd-1.4.5/plugins/dfu/fu-dfu-sector.c fwupd-1.5.8/plugins/dfu/fu-dfu-sector.c --- fwupd-1.4.5/plugins/dfu/fu-dfu-sector.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/fu-dfu-sector.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2015 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +/** + * SECTION:fu-dfu-sector + * @short_description: Object representing a sector on a chip + * + * This object represents an sector of memory at a specific address on the + * device itself. + * + * This allows relocatable data segments to be stored in different + * locations on the device itself. + * + * You can think of these objects as flash segments on devices, where a + * complete block can be erased and then written to. + * + * See also: #DfuElement + */ + +#include "config.h" + +#include +#include + +#include "fu-dfu-common.h" +#include "fu-dfu-sector.h" + +typedef struct { + guint32 address; + guint32 size; + guint32 size_left; + guint16 zone; + guint16 number; + FuDfuSectorCap cap; +} FuDfuSectorPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (FuDfuSector, fu_dfu_sector, G_TYPE_OBJECT) +#define GET_PRIVATE(o) (fu_dfu_sector_get_instance_private (o)) + +static void +fu_dfu_sector_class_init (FuDfuSectorClass *klass) +{ +} + +static void +fu_dfu_sector_init (FuDfuSector *self) +{ +} + +/** + * fu_dfu_sector_new: (skip) + * address: the address for the sector + * size: the size of this sector + * size_left: the size of the rest of the sector + * zone: the zone of memory the setor belongs + * number: the sector number in the zone + * cap: the #FuDfuSectorCap + * + * Creates a new DFU sector object. + * + * Return value: a new #FuDfuSector + **/ +FuDfuSector * +fu_dfu_sector_new (guint32 address, guint32 size, guint32 size_left, + guint16 zone, guint16 number, FuDfuSectorCap cap) +{ + FuDfuSectorPrivate *priv; + FuDfuSector *self; + self = g_object_new (FU_TYPE_DFU_SECTOR, NULL); + priv = GET_PRIVATE (self); + priv->address = address; + priv->size = size; + priv->size_left = size_left; + priv->zone = zone; + priv->number = number; + priv->cap = cap; + return self; +} + +/** + * fu_dfu_sector_get_address: + * @self: a #FuDfuSector + * + * Gets the alternate setting. + * + * Return value: integer, or 0x00 for unset + **/ +guint32 +fu_dfu_sector_get_address (FuDfuSector *self) +{ + FuDfuSectorPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DFU_SECTOR (self), 0x00); + return priv->address; +} + +/** + * fu_dfu_sector_get_size: + * @self: a #FuDfuSector + * + * Gets the sector size. + * + * Return value: integer, or 0x00 for unset + **/ +guint32 +fu_dfu_sector_get_size (FuDfuSector *self) +{ + FuDfuSectorPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DFU_SECTOR (self), 0x00); + return priv->size; +} + +/** + * fu_dfu_sector_get_size_left: + * @self: a #FuDfuSector + * + * Gets the size of the rest of the sector. + * + * Return value: integer, or 0x00 for unset + **/ +guint32 +fu_dfu_sector_get_size_left (FuDfuSector *self) +{ + FuDfuSectorPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DFU_SECTOR (self), 0x00); + return priv->size_left; +} + +/** + * fu_dfu_sector_get_zone: + * @self: a #FuDfuSector + * + * Gets the sector zone number. + * + * Return value: integer, or 0x00 for unset + **/ +guint16 +fu_dfu_sector_get_zone (FuDfuSector *self) +{ + FuDfuSectorPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DFU_SECTOR (self), 0x00); + return priv->zone; +} + +/** + * fu_dfu_sector_get_number: + * @self: a #FuDfuSector + * + * Gets the sector index number. + * + * Return value: integer, or 0x00 for unset + **/ +guint16 +fu_dfu_sector_get_number (FuDfuSector *self) +{ + FuDfuSectorPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DFU_SECTOR (self), 0x00); + return priv->number; +} + +/** + * fu_dfu_sector_get_id: + * @self: a #FuDfuSector + * + * Gets the sector ID which is a combination of the zone and sector number. + * You can use this number to check if the segment is the 'same' as the last + * written or read sector. + * + * Return value: integer ID, or 0x00 for unset + **/ +guint32 +fu_dfu_sector_get_id (FuDfuSector *self) +{ + FuDfuSectorPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DFU_SECTOR (self), 0x00); + return (((guint32) priv->zone) << 16) | priv->number; +} + +/** + * fu_dfu_sector_has_cap: + * @self: a #FuDfuSector + * @cap: a #FuDfuSectorCap, e.g. %DFU_SECTOR_CAP_ERASEABLE + * + * Finds out if the sector has the required capability. + * + * Return value: %TRUE if the sector has the capabilily + **/ +gboolean +fu_dfu_sector_has_cap (FuDfuSector *self, FuDfuSectorCap cap) +{ + FuDfuSectorPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DFU_SECTOR (self), FALSE); + return (priv->cap & cap) > 0; +} + +static gchar * +fu_dfu_sector_cap_to_string (FuDfuSectorCap cap) +{ + GString *str = g_string_new (NULL); + if (cap & DFU_SECTOR_CAP_READABLE) + g_string_append (str, "R"); + if (cap & DFU_SECTOR_CAP_ERASEABLE) + g_string_append (str, "E"); + if (cap & DFU_SECTOR_CAP_WRITEABLE) + g_string_append (str, "W"); + return g_string_free (str, FALSE); +} + +/** + * fu_dfu_sector_to_string: + * @self: a #FuDfuSector + * + * Returns a string representation of the object. + * + * Return value: NULL terminated string, or %NULL for invalid + **/ +gchar * +fu_dfu_sector_to_string (FuDfuSector *self) +{ + FuDfuSectorPrivate *priv = GET_PRIVATE (self); + GString *str; + g_autofree gchar *caps_str = NULL; + + g_return_val_if_fail (FU_IS_DFU_SECTOR (self), NULL); + + str = g_string_new (""); + caps_str = fu_dfu_sector_cap_to_string (priv->cap); + g_string_append_printf (str, + "Zone:%i, Sec#:%i, Addr:0x%08x, " + "Size:0x%04x, Caps:0x%01x [%s]", + priv->zone, priv->number, priv->address, + priv->size, priv->cap, caps_str); + return g_string_free (str, FALSE); +} diff -Nru fwupd-1.4.5/plugins/dfu/fu-dfu-sector.h fwupd-1.5.8/plugins/dfu/fu-dfu-sector.h --- fwupd-1.4.5/plugins/dfu/fu-dfu-sector.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/fu-dfu-sector.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2015 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include +#include + +#define FU_TYPE_DFU_SECTOR (fu_dfu_sector_get_type ()) +G_DECLARE_DERIVABLE_TYPE (FuDfuSector, fu_dfu_sector, FU, DFU_SECTOR, GObject) + +struct _FuDfuSectorClass +{ + GObjectClass parent_class; +}; + +/** + * FuDfuSectorCap: + * @DFU_SECTOR_CAP_NONE: No operations possible + * @DFU_SECTOR_CAP_READABLE: Sector can be read + * @DFU_SECTOR_CAP_WRITEABLE: Sector can be written + * @DFU_SECTOR_CAP_ERASEABLE: Sector can be erased + * + * The flags indicating what the sector can do. + **/ +typedef enum { + DFU_SECTOR_CAP_NONE = 0, + DFU_SECTOR_CAP_READABLE = 1 << 0, + DFU_SECTOR_CAP_WRITEABLE = 1 << 1, + DFU_SECTOR_CAP_ERASEABLE = 1 << 2, + /*< private >*/ + DFU_SECTOR_CAP_LAST +} FuDfuSectorCap; + +FuDfuSector *fu_dfu_sector_new (guint32 address, + guint32 size, + guint32 size_left, + guint16 zone, + guint16 number, + FuDfuSectorCap cap); +guint32 fu_dfu_sector_get_id (FuDfuSector *self); +guint32 fu_dfu_sector_get_address (FuDfuSector *self); +guint32 fu_dfu_sector_get_size (FuDfuSector *self); +guint32 fu_dfu_sector_get_size_left (FuDfuSector *self); +guint16 fu_dfu_sector_get_zone (FuDfuSector *self); +guint16 fu_dfu_sector_get_number (FuDfuSector *self); +gboolean fu_dfu_sector_has_cap (FuDfuSector *self, + FuDfuSectorCap cap); +gchar *fu_dfu_sector_to_string (FuDfuSector *self); diff -Nru fwupd-1.4.5/plugins/dfu/fu-dfu-self-test.c fwupd-1.5.8/plugins/dfu/fu-dfu-self-test.c --- fwupd-1.4.5/plugins/dfu/fu-dfu-self-test.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/fu-dfu-self-test.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2015 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-dfu-device.h" +#include "fu-dfu-sector.h" +#include "fu-dfu-target-private.h" + +#include "fu-common.h" + +static void +fu_dfu_enums_func (void) +{ + for (guint i = 0; i < FU_DFU_STATE_LAST; i++) + g_assert_cmpstr (fu_dfu_state_to_string (i), !=, NULL); + for (guint i = 0; i < FU_DFU_STATUS_LAST; i++) + g_assert_cmpstr (fu_dfu_status_to_string (i), !=, NULL); +} + +static gboolean +fu_test_compare_lines (const gchar *txt1, const gchar *txt2, GError **error) +{ + g_autofree gchar *output = NULL; + if (g_strcmp0 (txt1, txt2) == 0) + return TRUE; + if (fu_common_fnmatch (txt2, txt1)) + return TRUE; + if (!g_file_set_contents ("/tmp/a", txt1, -1, error)) + return FALSE; + if (!g_file_set_contents ("/tmp/b", txt2, -1, error)) + return FALSE; + if (!g_spawn_command_line_sync ("diff -urNp /tmp/b /tmp/a", + &output, NULL, NULL, error)) + return FALSE; + g_set_error_literal (error, 1, 0, output); + return FALSE; +} + +static gchar * +fu_dfu_target_sectors_to_string (FuDfuTarget *target) +{ + GPtrArray *sectors; + GString *str; + + str = g_string_new (""); + sectors = fu_dfu_target_get_sectors (target); + for (guint i = 0; i < sectors->len; i++) { + FuDfuSector *sector = g_ptr_array_index (sectors, i); + g_autofree gchar *tmp = fu_dfu_sector_to_string (sector); + g_string_append_printf (str, "%s\n", tmp); + } + if (str->len > 0) + g_string_truncate (str, str->len - 1); + return g_string_free (str, FALSE); +} + +static void +fu_dfu_target_dfuse_func (void) +{ + gboolean ret; + gchar *tmp; + g_autoptr(FuDfuDevice) device = fu_dfu_device_new (NULL); + g_autoptr(FuDfuTarget) target = NULL; + g_autoptr(GError) error = NULL; + + /* NULL */ + target = g_object_new (FU_TYPE_DFU_TARGET, NULL); + fu_dfu_target_set_device (target, device); + ret = fu_dfu_target_parse_sectors (target, NULL, &error); + g_assert_no_error (error); + g_assert (ret); + tmp = fu_dfu_target_sectors_to_string (target); + g_assert_cmpstr (tmp, ==, ""); + g_free (tmp); + + /* no addresses */ + ret = fu_dfu_target_parse_sectors (target, "@Flash3", &error); + g_assert_no_error (error); + g_assert (ret); + tmp = fu_dfu_target_sectors_to_string (target); + g_assert_cmpstr (tmp, ==, ""); + g_free (tmp); + + /* one sector, no space */ + ret = fu_dfu_target_parse_sectors (target, "@Internal Flash /0x08000000/2*001Ka", &error); + g_assert_no_error (error); + g_assert (ret); + tmp = fu_dfu_target_sectors_to_string (target); + ret = fu_test_compare_lines (tmp, + "Zone:0, Sec#:0, Addr:0x08000000, Size:0x0400, Caps:0x1 [R]\n" + "Zone:0, Sec#:0, Addr:0x08000400, Size:0x0400, Caps:0x1 [R]", + &error); + g_assert_no_error (error); + g_assert (ret); + g_free (tmp); + + /* multiple sectors */ + ret = fu_dfu_target_parse_sectors (target, "@Flash1 /0x08000000/2*001Ka,4*001Kg", &error); + g_assert_no_error (error); + g_assert (ret); + tmp = fu_dfu_target_sectors_to_string (target); + ret = fu_test_compare_lines (tmp, + "Zone:0, Sec#:0, Addr:0x08000000, Size:0x0400, Caps:0x1 [R]\n" + "Zone:0, Sec#:0, Addr:0x08000400, Size:0x0400, Caps:0x1 [R]\n" + "Zone:0, Sec#:1, Addr:0x08000800, Size:0x0400, Caps:0x7 [REW]\n" + "Zone:0, Sec#:1, Addr:0x08000c00, Size:0x0400, Caps:0x7 [REW]\n" + "Zone:0, Sec#:1, Addr:0x08001000, Size:0x0400, Caps:0x7 [REW]\n" + "Zone:0, Sec#:1, Addr:0x08001400, Size:0x0400, Caps:0x7 [REW]", + &error); + g_assert_no_error (error); + g_assert (ret); + g_free (tmp); + + /* non-contiguous */ + ret = fu_dfu_target_parse_sectors (target, "@Flash2 /0xF000/4*100Ba/0xE000/3*8Kg/0x80000/2*24Kg", &error); + g_assert_no_error (error); + g_assert (ret); + tmp = fu_dfu_target_sectors_to_string (target); + ret = fu_test_compare_lines (tmp, + "Zone:0, Sec#:0, Addr:0x0000f000, Size:0x0064, Caps:0x1 [R]\n" + "Zone:0, Sec#:0, Addr:0x0000f064, Size:0x0064, Caps:0x1 [R]\n" + "Zone:0, Sec#:0, Addr:0x0000f0c8, Size:0x0064, Caps:0x1 [R]\n" + "Zone:0, Sec#:0, Addr:0x0000f12c, Size:0x0064, Caps:0x1 [R]\n" + "Zone:1, Sec#:0, Addr:0x0000e000, Size:0x2000, Caps:0x7 [REW]\n" + "Zone:1, Sec#:0, Addr:0x00010000, Size:0x2000, Caps:0x7 [REW]\n" + "Zone:1, Sec#:0, Addr:0x00012000, Size:0x2000, Caps:0x7 [REW]\n" + "Zone:2, Sec#:0, Addr:0x00080000, Size:0x6000, Caps:0x7 [REW]\n" + "Zone:2, Sec#:0, Addr:0x00086000, Size:0x6000, Caps:0x7 [REW]", + &error); + g_assert_no_error (error); + g_assert (ret); + g_free (tmp); + + /* invalid */ + ret = fu_dfu_target_parse_sectors (target, "Flash", NULL); + g_assert (ret); + ret = fu_dfu_target_parse_sectors (target, "@Internal Flash /0x08000000", NULL); + g_assert (!ret); + ret = fu_dfu_target_parse_sectors (target, "@Internal Flash /0x08000000/12*001a", NULL); + g_assert (!ret); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + /* only critical and error are fatal */ + g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); + + /* log everything */ + g_setenv ("G_MESSAGES_DEBUG", "all", FALSE); + + /* tests go here */ + g_test_add_func ("/dfu/enums", fu_dfu_enums_func); + g_test_add_func ("/dfu/target(DfuSe}", fu_dfu_target_dfuse_func); + return g_test_run (); +} + diff -Nru fwupd-1.4.5/plugins/dfu/fu-dfu-target-avr.c fwupd-1.5.8/plugins/dfu/fu-dfu-target-avr.c --- fwupd-1.4.5/plugins/dfu/fu-dfu-target-avr.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/fu-dfu-target-avr.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,764 @@ +/* + * Copyright (C) 2017 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include + +#include "fu-chunk.h" + +#include "fu-dfu-common.h" +#include "fu-dfu-sector.h" +#include "fu-dfu-target-avr.h" +#include "fu-dfu-target-private.h" +#include "fu-dfu-device.h" + +#include "fwupd-error.h" + +/** + * FU_QUIRKS_DFU_AVR_ALT_NAME: + * @key: the AVR chip ID, e.g. `0x58200204` + * @value: the UM0424 sector description, e.g. `@Flash/0x2000/1*248Kg` + * + * Assigns a sector description for the chip ID. This is required so fwupd can + * program the user firmware avoiding the bootloader and for checking the total + * chunk size. + * + * The chip ID can be found from a datasheet or using `dfu-tool list` when the + * hardware is connected and in bootloader mode. + * + * Since: 1.0.1 + */ +#define FU_QUIRKS_DFU_AVR_ALT_NAME "DfuAltName" + +typedef struct { + guint32 device_id; +} FuDfuTargetAvrPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (FuDfuTargetAvr, fu_dfu_target_avr, FU_TYPE_DFU_TARGET) +#define GET_PRIVATE(o) (fu_dfu_target_avr_get_instance_private (o)) + +/* ATMEL AVR version of DFU: + * http://www.atmel.com/Images/doc7618.pdf */ +#define DFU_AVR_CMD_PROG_START 0x01 +#define DFU_AVR_CMD_DISPLAY_DATA 0x03 +#define DFU_AVR_CMD_WRITE_COMMAND 0x04 +#define DFU_AVR_CMD_READ_COMMAND 0x05 +#define DFU_AVR_CMD_CHANGE_BASE_ADDR 0x06 + +/* Atmel AVR32 version of DFU: + * http://www.atmel.com/images/doc32131.pdf */ +#define DFU_AVR32_GROUP_SELECT 0x06 /** SELECT */ +#define DFU_AVR32_CMD_SELECT_MEMORY 0x03 +#define DFU_AVR32_MEMORY_UNIT 0x00 +#define DFU_AVR32_MEMORY_PAGE 0x01 +#define DFU_AVR32_MEMORY_UNIT_FLASH 0x00 +#define DFU_AVR32_MEMORY_UNIT_EEPROM 0x01 +#define DFU_AVR32_MEMORY_UNIT_SECURITY 0x02 +#define DFU_AVR32_MEMORY_UNIT_CONFIGURATION 0x03 +#define DFU_AVR32_MEMORY_UNIT_BOOTLOADER 0x04 +#define DFU_AVR32_MEMORY_UNIT_SIGNATURE 0x05 +#define DFU_AVR32_MEMORY_UNIT_USER 0x06 +#define DFU_AVR32_GROUP_DOWNLOAD 0x01 /** DOWNLOAD */ +#define DFU_AVR32_CMD_PROGRAM_START 0x00 +#define DFU_AVR32_GROUP_UPLOAD 0x03 /** UPLOAD */ +#define DFU_AVR32_CMD_READ_MEMORY 0x00 +#define DFU_AVR32_CMD_BLANK_CHECK 0x01 +#define DFU_AVR32_GROUP_EXEC 0x04 /** EXEC */ +#define DFU_AVR32_CMD_ERASE 0x00 +#define DFU_AVR32_ERASE_EVERYTHING 0xff +#define DFU_AVR32_CMD_START_APPLI 0x03 +#define DFU_AVR32_START_APPLI_RESET 0x00 +#define DFU_AVR32_START_APPLI_NO_RESET 0x01 + +#define ATMEL_64KB_PAGE 0x10000 +#define ATMEL_MAX_TRANSFER_SIZE 0x0400 +#define ATMEL_AVR_CONTROL_BLOCK_SIZE 32 +#define ATMEL_AVR32_CONTROL_BLOCK_SIZE 64 + +#define ATMEL_MANUFACTURER_CODE1 0x58 +#define ATMEL_MANUFACTURER_CODE2 0x1e + +static gboolean +fu_dfu_target_avr_mass_erase (FuDfuTarget *target, GError **error) +{ + g_autoptr(GBytes) data_in = NULL; + guint8 buf[3]; + + /* this takes a long time on some devices */ + fu_dfu_device_set_timeout (fu_dfu_target_get_device (target), 5000); + + /* format buffer */ + buf[0] = DFU_AVR32_GROUP_EXEC; + buf[1] = DFU_AVR32_CMD_ERASE; + buf[2] = 0xff; + data_in = g_bytes_new_static (buf, sizeof(buf)); + g_debug ("mass erasing"); + fu_dfu_target_set_action (target, FWUPD_STATUS_DEVICE_ERASE); + if (!fu_dfu_target_download_chunk (target, 0, data_in, error)) { + g_prefix_error (error, "cannot mass-erase: "); + return FALSE; + } + fu_dfu_target_set_action (target, FWUPD_STATUS_IDLE); + return TRUE; +} + +static gboolean +fu_dfu_target_avr_attach (FuDfuTarget *target, GError **error) +{ + guint8 buf[3]; + g_autoptr(GBytes) data_empty = NULL; + g_autoptr(GBytes) data_in = NULL; + g_autoptr(GError) error_local = NULL; + + /* format buffer */ + buf[0] = DFU_AVR32_GROUP_EXEC; + buf[1] = DFU_AVR32_CMD_START_APPLI; + buf[2] = DFU_AVR32_START_APPLI_RESET; + data_in = g_bytes_new_static (buf, sizeof(buf)); + if (!fu_dfu_target_download_chunk (target, 0, data_in, &error_local)) { + if (g_error_matches (error_local, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED)) { + g_debug ("ignoring as device rebooting: %s", error_local->message); + return TRUE; + } + g_prefix_error (error, "cannot start application reset attach: "); + return FALSE; + } + + /* do zero-sized download to initiate the reset */ + data_empty = g_bytes_new (NULL, 0); + if (!fu_dfu_target_download_chunk (target, 0, data_empty, &error_local)) { + if (g_error_matches (error_local, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED)) { + g_debug ("ignoring as device rebooting: %s", error_local->message); + return TRUE; + } + g_prefix_error (error, "cannot initiate reset for attach: "); + return FALSE; + } + + /* success */ + return TRUE; +} + +/** + * fu_dfu_target_avr_select_memory_unit: + * @target: a #FuDfuTarget + * @memory_unit: a unit, e.g. %DFU_AVR32_MEMORY_UNIT_FLASH + * @error: a #GError, or %NULL + * + * Selects the memory unit for the device. + * + * Return value: %TRUE for success + **/ +static gboolean +fu_dfu_target_avr_select_memory_unit (FuDfuTarget *target, + guint8 memory_unit, + GError **error) +{ + g_autoptr(GBytes) data_in = NULL; + guint8 buf[4]; + + /* check legacy protocol quirk */ + if (fu_device_has_custom_flag (FU_DEVICE (fu_dfu_target_get_device (target)), + "legacy-protocol")) { + g_debug ("ignoring select memory unit as legacy protocol"); + return TRUE; + } + + /* format buffer */ + buf[0] = DFU_AVR32_GROUP_SELECT; + buf[1] = DFU_AVR32_CMD_SELECT_MEMORY; + buf[2] = DFU_AVR32_MEMORY_UNIT; + buf[3] = memory_unit; + data_in = g_bytes_new_static (buf, sizeof(buf)); + g_debug ("selecting memory unit 0x%02x", (guint) memory_unit); + if (!fu_dfu_target_download_chunk (target, 0, data_in, error)) { + g_prefix_error (error, "cannot select memory unit: "); + return FALSE; + } + return TRUE; +} + +/** + * fu_dfu_target_avr_select_memory_page: + * @target: a #FuDfuTarget + * @memory_page: an address + * @error: a #GError, or %NULL + * + * Selects the memory page for the AVR device. + * + * Return value: %TRUE for success + **/ +static gboolean +fu_dfu_target_avr_select_memory_page (FuDfuTarget *target, + guint16 memory_page, + GError **error) +{ + g_autoptr(GBytes) data_in = NULL; + guint8 buf[4]; + + /* check page not too large for protocol */ + if (memory_page > 0xff) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "cannot select memory page:0x%02x " + "with FLIP protocol version 1", + memory_page); + return FALSE; + } + + /* format buffer */ + buf[0] = DFU_AVR_CMD_CHANGE_BASE_ADDR; + buf[1] = 0x03; + buf[2] = 0x00; + buf[3] = memory_page & 0xff; + data_in = g_bytes_new_static (buf, sizeof(buf)); + g_debug ("selecting memory page 0x%01x", (guint) memory_page); + if (!fu_dfu_target_download_chunk (target, 0, data_in, error)) { + g_prefix_error (error, "cannot select memory page: "); + return FALSE; + } + return TRUE; +} + +/** + * fu_dfu_target_avr32_select_memory_page: + * @target: a #FuDfuTarget + * @memory_page: an address + * @error: a #GError, or %NULL + * + * Selects the memory page for the AVR32 device. + * + * Return value: %TRUE for success + **/ +static gboolean +fu_dfu_target_avr32_select_memory_page (FuDfuTarget *target, + guint16 memory_page, + GError **error) +{ + g_autoptr(GBytes) data_in = NULL; + guint8 buf[5]; + + /* format buffer */ + buf[0] = DFU_AVR32_GROUP_SELECT; + buf[1] = DFU_AVR32_CMD_SELECT_MEMORY; + buf[2] = DFU_AVR32_MEMORY_PAGE; + fu_common_write_uint16 (&buf[3], memory_page, G_BIG_ENDIAN); + data_in = g_bytes_new_static (buf, sizeof(buf)); + g_debug ("selecting memory page 0x%02x", (guint) memory_page); + if (!fu_dfu_target_download_chunk (target, 0, data_in, error)) { + g_prefix_error (error, "cannot select memory page: "); + return FALSE; + } + return TRUE; +} + +/** + * fu_dfu_target_avr_read_memory + * @target: a #FuDfuTarget + * @addr_start: an address + * @addr_end: an address + * @error: a #GError, or %NULL + * + * Reads flash data from the device. + * + * Return value: %TRUE for success + **/ +static gboolean +fu_dfu_target_avr_read_memory (FuDfuTarget *target, + guint16 addr_start, + guint16 addr_end, + GError **error) +{ + g_autoptr(GBytes) data_in = NULL; + guint8 buf[6]; + + /* format buffer */ + buf[0] = DFU_AVR32_GROUP_UPLOAD; + buf[1] = DFU_AVR32_CMD_READ_MEMORY; + fu_common_write_uint16 (&buf[2], addr_start, G_BIG_ENDIAN); + fu_common_write_uint16 (&buf[4], addr_end, G_BIG_ENDIAN); + data_in = g_bytes_new_static (buf, sizeof(buf)); + g_debug ("reading memory from 0x%04x to 0x%04x", + (guint) addr_start, (guint) addr_end); + if (!fu_dfu_target_download_chunk (target, 0, data_in, error)) { + g_prefix_error (error, "cannot read memory 0x%04x to 0x%04x: ", + (guint) addr_start, (guint) addr_end); + return FALSE; + } + return TRUE; +} + +/** + * fu_dfu_target_avr_read_command: + * @target: a #FuDfuTarget + * @memory_unit: a unit, e.g. %DFU_AVR32_MEMORY_UNIT_FLASH + * @error: a #GError, or %NULL + * + * Performs a read operation on the device. + * + * Return value: %TRUE for success + **/ +static gboolean +fu_dfu_target_avr_read_command (FuDfuTarget *target, guint8 page, guint8 addr, GError **error) +{ + g_autoptr(GBytes) data_in = NULL; + guint8 buf[3]; + + /* format buffer */ + buf[0] = DFU_AVR_CMD_READ_COMMAND; + buf[1] = page; + buf[2] = addr; + data_in = g_bytes_new_static (buf, sizeof(buf)); + g_debug ("read command page:0x%02x addr:0x%02x", (guint) page, (guint) addr); + if (!fu_dfu_target_download_chunk (target, 0, data_in, error)) { + g_prefix_error (error, "cannot read command page: "); + return FALSE; + } + return TRUE; +} + +/** + * fu_dfu_target_avr32_get_chip_signature: + * @target: a #FuDfuTarget + * @error: a #GError, or %NULL + * + * Gets the chip signature for the AVR32 device. + * + * Return value: a 4-byte %GBytes object for success, else %NULL + **/ +static GBytes * +fu_dfu_target_avr32_get_chip_signature (FuDfuTarget *target, GError **error) +{ + /* select unit, and request 4 bytes */ + if (!fu_dfu_target_avr_select_memory_unit (target, + DFU_AVR32_MEMORY_UNIT_SIGNATURE, + error)) + return NULL; + if (!fu_dfu_target_avr32_select_memory_page (target, 0x00, error)) + return NULL; + if (!fu_dfu_target_avr_read_memory (target, 0x00, 0x03, error)) + return NULL; + + /* get data back */ + return fu_dfu_target_upload_chunk (target, 0x00, 0, error); +} + +/** + * fu_dfu_target_avr_get_chip_signature: + * @target: a #FuDfuTarget + * @error: a #GError, or %NULL + * + * Gets the chip signature for the AVR device. + * + * Return value: a 4-byte %GBytes object for success, else %NULL + **/ +static GBytes * +fu_dfu_target_avr_get_chip_signature (FuDfuTarget *target, GError **error) +{ + struct { + guint8 page; + guint addr; + } signature_locations[] = { + { 0x01, 0x30 }, + { 0x01, 0x31 }, + { 0x01, 0x60 }, + { 0x01, 0x61 }, + { 0xff, 0xff } + }; + g_autoptr(GPtrArray) chunks = NULL; + + /* we have to request this one byte at a time */ + chunks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref); + for (guint i = 0; signature_locations[i].page != 0xff; i++) { + g_autoptr(GBytes) chunk_byte = NULL; + + /* request a single byte */ + if (!fu_dfu_target_avr_read_command (target, + signature_locations[i].page, + signature_locations[i].addr, + error)) + return NULL; + + /* get data back */ + chunk_byte = fu_dfu_target_upload_chunk (target, 0x00, 0x01, error); + if (chunk_byte == NULL) + return NULL; + if (g_bytes_get_size (chunk_byte) != 1) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "cannot read signature memory page:0x%02x " + "addr:0x%02x, got 0x%02x bytes", + (guint) signature_locations[i].page, + (guint) signature_locations[i].addr, + (guint) g_bytes_get_size (chunk_byte)); + return NULL; + } + g_ptr_array_add (chunks, g_steal_pointer (&chunk_byte)); + } + return fu_dfu_utils_bytes_join_array (chunks); +} + +static gboolean +fu_dfu_target_avr_setup (FuDfuTarget *target, GError **error) +{ + FuDfuDevice *device; + FuDfuTargetAvr *self = FU_DFU_TARGET_AVR (target); + FuDfuTargetAvrPrivate *priv = GET_PRIVATE (self); + const gchar *chip_id; + const guint8 *buf; + gsize sz; + guint32 device_id_be; + g_autofree gchar *chip_id_guid = NULL; + g_autoptr(GBytes) chunk_sig = NULL; + + /* already done */ + if (priv->device_id > 0x0) + return TRUE; + + /* different methods for AVR vs. AVR32 */ + if (fu_device_has_custom_flag (FU_DEVICE (fu_dfu_target_get_device (target)), + "legacy-protocol")) { + chunk_sig = fu_dfu_target_avr_get_chip_signature (target, error); + if (chunk_sig == NULL) + return FALSE; + } else { + chunk_sig = fu_dfu_target_avr32_get_chip_signature (target, error); + if (chunk_sig == NULL) { + g_prefix_error (error, "failed to get chip signature: "); + return FALSE; + } + } + + /* get data back */ + buf = g_bytes_get_data (chunk_sig, &sz); + if (sz != 4) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "cannot read config memory, got 0x%02x bytes", + (guint) sz); + return FALSE; + } + memcpy (&device_id_be, buf, 4); + priv->device_id = GINT32_FROM_BE (device_id_be); + if (buf[0] == ATMEL_MANUFACTURER_CODE1) { + chip_id_guid = g_strdup_printf ("DFU_AVR\\CID_0x%08x", (guint) priv->device_id); + } else if (buf[0] == ATMEL_MANUFACTURER_CODE2) { + chip_id_guid = g_strdup_printf ("DFU_AVR\\CID_0x%06x", (guint) priv->device_id >> 8); + } else { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "cannot read config vendor, got 0x%08x, " + "expected 0x%02x or 0x%02x", + (guint) priv->device_id, + (guint) ATMEL_MANUFACTURER_CODE1, + (guint) ATMEL_MANUFACTURER_CODE2); + return FALSE; + } + + /* set the alt-name using the chip ID via a quirk */ + device = fu_dfu_target_get_device (target); + fu_device_add_instance_id (FU_DEVICE (device), chip_id_guid); + chip_id = fu_dfu_device_get_chip_id (device); + if (chip_id == NULL) { + fu_dfu_device_remove_attribute (fu_dfu_target_get_device (target), + FU_DFU_DEVICE_ATTR_CAN_DOWNLOAD); + fu_dfu_device_remove_attribute (fu_dfu_target_get_device (target), + FU_DFU_DEVICE_ATTR_CAN_UPLOAD); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "ChipID %s is not supported", + chip_id); + return FALSE; + } + fu_dfu_target_set_alt_name (target, chip_id); + + return TRUE; +} + +static gboolean +fu_dfu_target_avr_download_element (FuDfuTarget *target, + FuChunk *chk, + FuDfuTargetTransferFlags flags, + GError **error) +{ + FuDfuSector *sector; + const guint8 *data; + gsize header_sz = ATMEL_AVR32_CONTROL_BLOCK_SIZE; + guint16 page_last = G_MAXUINT16; + guint32 address; + guint32 address_offset = 0x0; + g_autoptr(GBytes) blob = NULL; + g_autoptr(GPtrArray) chunks = NULL; + const guint8 footer[] = { 0x00, 0x00, 0x00, 0x00, /* CRC */ + 16, /* len */ + 'D', 'F', 'U', /* signature */ + 0x01, 0x10, /* version */ + 0xff, 0xff, /* vendor ID */ + 0xff, 0xff, /* product ID */ + 0xff, 0xff }; /* release */ + + /* select a memory and erase everything */ + if (!fu_dfu_target_avr_select_memory_unit (target, + fu_dfu_target_get_alt_setting (target), + error)) + return FALSE; + if (!fu_dfu_target_avr_mass_erase (target, error)) + return FALSE; + + /* verify the element isn't larger than the target size */ + blob = fu_chunk_get_bytes (chk); + sector = fu_dfu_target_get_sector_default (target); + if (sector == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "no sector defined for target"); + return FALSE; + } + address = fu_chunk_get_address (chk) & ~0x80000000; + if (address < fu_dfu_sector_get_address (sector)) { + address_offset = fu_dfu_sector_get_address (sector) - address; + g_warning ("firmware element starts at 0x%x but sector " + "starts at 0x%x, so offsetting by 0x%x (bootloader?)", + (guint) address, + (guint) fu_dfu_sector_get_address (sector), + (guint) address_offset); + } + if (g_bytes_get_size (blob) + address_offset > fu_dfu_sector_get_size (sector)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "element was larger than sector size: 0x%x", + (guint) fu_dfu_sector_get_size (sector)); + return FALSE; + } + + /* the original AVR protocol uses a half-size control block */ + if (fu_device_has_custom_flag (FU_DEVICE (fu_dfu_target_get_device (target)), + "legacy-protocol")) { + header_sz = ATMEL_AVR_CONTROL_BLOCK_SIZE; + } + + /* chunk up the memory space into pages */ + data = g_bytes_get_data (blob, NULL); + chunks = fu_chunk_array_new (data + address_offset, + g_bytes_get_size (blob) - address_offset, + fu_dfu_sector_get_address (sector), + ATMEL_64KB_PAGE, + ATMEL_MAX_TRANSFER_SIZE); + + /* update UI */ + fu_dfu_target_set_action (target, FWUPD_STATUS_DEVICE_WRITE); + + /* process each chunk */ + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk2 = g_ptr_array_index (chunks, i); + g_autofree guint8 *buf = NULL; + g_autoptr(GBytes) chunk_tmp = NULL; + + /* select page if required */ + if (fu_chunk_get_page (chk2) != page_last) { + if (fu_device_has_custom_flag (FU_DEVICE (fu_dfu_target_get_device (target)), + "legacy-protocol")) { + if (!fu_dfu_target_avr_select_memory_page (target, + fu_chunk_get_page (chk2), + error)) + return FALSE; + } else { + if (!fu_dfu_target_avr32_select_memory_page (target, + fu_chunk_get_page (chk2), + error)) + return FALSE; + } + page_last = fu_chunk_get_page (chk2); + } + + /* create chunk with header and footer */ + buf = g_malloc0 (fu_chunk_get_data_sz (chk2) + header_sz + sizeof(footer)); + buf[0] = DFU_AVR32_GROUP_DOWNLOAD; + buf[1] = DFU_AVR32_CMD_PROGRAM_START; + fu_common_write_uint16 (&buf[2], fu_chunk_get_address (chk2), G_BIG_ENDIAN); + fu_common_write_uint16 (&buf[4], fu_chunk_get_address (chk2) + fu_chunk_get_data_sz (chk2) - 1, G_BIG_ENDIAN); + memcpy (&buf[header_sz], fu_chunk_get_data (chk2), fu_chunk_get_data_sz (chk2)); + memcpy (&buf[header_sz + fu_chunk_get_data_sz (chk2)], footer, sizeof(footer)); + + /* download data */ + chunk_tmp = g_bytes_new_static (buf, fu_chunk_get_data_sz (chk2) + header_sz + sizeof(footer)); + g_debug ("sending %" G_GSIZE_FORMAT " bytes to the hardware", + g_bytes_get_size (chunk_tmp)); + if (!fu_dfu_target_download_chunk (target, i, chunk_tmp, error)) + return FALSE; + + /* update UI */ + fu_dfu_target_set_percentage (target, i + 1, chunks->len); + } + + /* done */ + fu_dfu_target_set_percentage_raw (target, 100); + fu_dfu_target_set_action (target, FWUPD_STATUS_IDLE); + return TRUE; +} + +static FuChunk * +fu_dfu_target_avr_upload_element (FuDfuTarget *target, + guint32 address, + gsize expected_size, + gsize maximum_size, + GError **error) +{ + guint16 page_last = G_MAXUINT16; + guint chunk_valid = G_MAXUINT; + g_autoptr(FuChunk) chk2 = NULL; + g_autoptr(GBytes) contents = NULL; + g_autoptr(GBytes) contents_truncated = NULL; + g_autoptr(GPtrArray) blobs = NULL; + g_autoptr(GPtrArray) chunks = NULL; + FuDfuSector *sector; + + /* select unit */ + if (!fu_dfu_target_avr_select_memory_unit (target, + fu_dfu_target_get_alt_setting (target), + error)) + return NULL; + + /* verify the element isn't lower than the flash area */ + sector = fu_dfu_target_get_sector_default (target); + if (sector == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "no sector defined for target"); + return NULL; + } + if (address < fu_dfu_sector_get_address (sector)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "cannot read from below sector start"); + return NULL; + } + + /* the flash starts at 0x80000000, but is indexed from zero */ + address &= ~0x80000000; + + /* chunk up the memory space into pages */ + chunks = fu_chunk_array_new (NULL, maximum_size, address, + ATMEL_64KB_PAGE, ATMEL_MAX_TRANSFER_SIZE); + + /* update UI */ + fu_dfu_target_set_action (target, FWUPD_STATUS_DEVICE_READ); + + /* process each chunk */ + blobs = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref); + for (guint i = 0; i < chunks->len; i++) { + GBytes *blob_tmp = NULL; + FuChunk *chk = g_ptr_array_index (chunks, i); + + /* select page if required */ + if (fu_chunk_get_page (chk) != page_last) { + if (fu_device_has_custom_flag (FU_DEVICE (fu_dfu_target_get_device (target)), + "legacy-protocol")) { + if (!fu_dfu_target_avr_select_memory_page (target, + fu_chunk_get_page (chk), + error)) + return NULL; + } else { + if (!fu_dfu_target_avr32_select_memory_page (target, + fu_chunk_get_page (chk), + error)) + return NULL; + } + page_last = fu_chunk_get_page (chk); + } + + /* prepare to read */ + if (!fu_dfu_target_avr_read_memory (target, + fu_chunk_get_address (chk), + fu_chunk_get_address (chk) + + fu_chunk_get_data_sz (chk) - 1, + error)) + return NULL; + + /* upload data */ + g_debug ("requesting %i bytes from the hardware for chunk 0x%x", + ATMEL_MAX_TRANSFER_SIZE, i); + blob_tmp = fu_dfu_target_upload_chunk (target, i, + ATMEL_MAX_TRANSFER_SIZE, + error); + if (blob_tmp == NULL) + return NULL; + g_ptr_array_add (blobs, blob_tmp); + + /* this page has valid data */ + if (!fu_common_bytes_is_empty (blob_tmp)) { + g_debug ("chunk %u has data (page %" G_GUINT32_FORMAT ")", + i, fu_chunk_get_page (chk)); + chunk_valid = i; + } else { + g_debug ("chunk %u is empty", i); + } + + /* update UI */ + fu_dfu_target_set_percentage (target, i + 1, chunks->len); + } + + /* done */ + fu_dfu_target_set_percentage_raw (target, 100); + fu_dfu_target_set_action (target, FWUPD_STATUS_IDLE); + + /* truncate the image if any sectors are empty, i.e. all 0xff */ + if (chunk_valid == G_MAXUINT) { + g_debug ("all %u chunks are empty", blobs->len); + g_ptr_array_set_size (chunks, 0); + } else if (blobs->len != chunk_valid + 1) { + g_debug ("truncating chunks from %u to %u", + blobs->len, chunk_valid + 1); + g_ptr_array_set_size (blobs, chunk_valid + 1); + } + + /* create element of required size */ + contents = fu_dfu_utils_bytes_join_array (blobs); + if (expected_size > 0 && g_bytes_get_size (contents) > expected_size) { + contents_truncated = g_bytes_new_from_bytes (contents, 0x0, expected_size); + } else { + contents_truncated = g_bytes_ref (contents); + } + + chk2 = fu_chunk_bytes_new (contents_truncated); + fu_chunk_set_address (chk2, address | 0x80000000); /* flash */ + return g_steal_pointer (&chk2); +} + +static void +fu_dfu_target_avr_init (FuDfuTargetAvr *self) +{ +} + +static void +fu_dfu_target_avr_class_init (FuDfuTargetAvrClass *klass) +{ + FuDfuTargetClass *klass_target = FU_DFU_TARGET_CLASS (klass); + klass_target->setup = fu_dfu_target_avr_setup; + klass_target->attach = fu_dfu_target_avr_attach; + klass_target->mass_erase = fu_dfu_target_avr_mass_erase; + klass_target->upload_element = fu_dfu_target_avr_upload_element; + klass_target->download_element = fu_dfu_target_avr_download_element; +} + +FuDfuTarget * +fu_dfu_target_avr_new (void) +{ + FuDfuTarget *target; + target = g_object_new (FU_TYPE_DFU_TARGET_AVR, NULL); + return target; +} diff -Nru fwupd-1.4.5/plugins/dfu/fu-dfu-target-avr.h fwupd-1.5.8/plugins/dfu/fu-dfu-target-avr.h --- fwupd-1.4.5/plugins/dfu/fu-dfu-target-avr.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/fu-dfu-target-avr.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2017 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include +#include + +#include "fu-dfu-target.h" + +#define FU_TYPE_DFU_TARGET_AVR (fu_dfu_target_avr_get_type ()) +G_DECLARE_DERIVABLE_TYPE (FuDfuTargetAvr, fu_dfu_target_avr, FU, DFU_TARGET_AVR, FuDfuTarget) + +struct _FuDfuTargetAvrClass +{ + FuDfuTargetClass parent_class; +}; + +FuDfuTarget *fu_dfu_target_avr_new (void); diff -Nru fwupd-1.4.5/plugins/dfu/fu-dfu-target.c fwupd-1.5.8/plugins/dfu/fu-dfu-target.c --- fwupd-1.4.5/plugins/dfu/fu-dfu-target.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/fu-dfu-target.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,1461 @@ +/* + * Copyright (C) 2015 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +/** + * SECTION:fu-dfu-target + * @short_description: Object representing a DFU-capable target + * + * This object allows uploading and downloading an image onto a + * specific DFU-capable target. + * + * You only need to use this in preference to #FuDfuDevice if you only + * want to update one target on the device. Most users will want to + * update all the targets on the device at the same time. + * + * See also: #FuDfuDevice, #FuFirmwareImage + */ + +#include "config.h" + +#include +#include + +#include "fu-dfu-common.h" +#include "fu-dfu-device.h" +#include "fu-dfu-sector.h" +#include "fu-dfu-target-private.h" + +#include "fu-dfu-firmware-private.h" + +#include "fwupd-error.h" + +#define DFU_TARGET_MANIFEST_MAX_POLLING_TRIES 200 + +static void fu_dfu_target_finalize (GObject *object); + +typedef struct { + FuDfuDevice *device; /* not refcounted */ + gboolean done_setup; + guint8 alt_setting; + guint8 alt_idx; + gchar *alt_name; + gchar *alt_name_for_display; + GPtrArray *sectors; /* of FuDfuSector */ + guint old_percentage; + FwupdStatus old_action; +} FuDfuTargetPrivate; + +enum { + SIGNAL_PERCENTAGE_CHANGED, + SIGNAL_ACTION_CHANGED, + SIGNAL_LAST +}; + +static guint signals [SIGNAL_LAST] = { 0 }; + +G_DEFINE_TYPE_WITH_PRIVATE (FuDfuTarget, fu_dfu_target, G_TYPE_OBJECT) +#define GET_PRIVATE(o) (fu_dfu_target_get_instance_private (o)) + +static void +fu_dfu_target_class_init (FuDfuTargetClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + /** + * FuDfuTarget::percentage-changed: + * @device: the #FuDfuTarget instance that emitted the signal + * @percentage: the new percentage + * + * The ::percentage-changed signal is emitted when the percentage changes. + **/ + signals [SIGNAL_PERCENTAGE_CHANGED] = + g_signal_new ("percentage-changed", + G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (FuDfuTargetClass, percentage_changed), + NULL, NULL, g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, 1, G_TYPE_UINT); + + /** + * FuDfuTarget::action-changed: + * @device: the #FuDfuTarget instance that emitted the signal + * @action: the new FwupdStatus + * + * The ::action-changed signal is emitted when the high level action changes. + **/ + signals [SIGNAL_ACTION_CHANGED] = + g_signal_new ("action-changed", + G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (FuDfuTargetClass, action_changed), + NULL, NULL, g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, 1, G_TYPE_UINT); + + object_class->finalize = fu_dfu_target_finalize; +} + +static void +fu_dfu_target_init (FuDfuTarget *self) +{ + FuDfuTargetPrivate *priv = GET_PRIVATE (self); + priv->sectors = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + priv->old_percentage = G_MAXUINT; + priv->old_action = FWUPD_STATUS_IDLE; +} + +static void +fu_dfu_target_finalize (GObject *object) +{ + FuDfuTarget *self = FU_DFU_TARGET (object); + FuDfuTargetPrivate *priv = GET_PRIVATE (self); + + g_free (priv->alt_name); + g_free (priv->alt_name_for_display); + g_ptr_array_unref (priv->sectors); + + /* we no longer care */ + if (priv->device != NULL) { + g_object_remove_weak_pointer (G_OBJECT (priv->device), + (gpointer *) &priv->device); + } + + G_OBJECT_CLASS (fu_dfu_target_parent_class)->finalize (object); +} + +void +fu_dfu_target_to_string (FuDfuTarget *self, guint idt, GString *str) +{ + FuDfuTargetPrivate *priv = GET_PRIVATE (self); + fu_common_string_append_kx (str, idt, "AltSetting", priv->alt_setting); + fu_common_string_append_kx (str, idt, "AltIdx", priv->alt_idx); + fu_common_string_append_kv (str, idt, "AltName", priv->alt_name); + if (priv->alt_name_for_display != NULL) { + fu_common_string_append_kv (str, idt, "AltNameForDisplay", + priv->alt_name_for_display); + } + for (guint i = 0; i < priv->sectors->len; i++) { + FuDfuSector *sector = g_ptr_array_index (priv->sectors, i); + g_autofree gchar *tmp1 = g_strdup_printf ("Idx%02x", i); + g_autofree gchar *tmp2 = fu_dfu_sector_to_string (sector); + fu_common_string_append_kv (str, idt + 1, tmp1, tmp2); + } +} + +FuDfuSector * +fu_dfu_target_get_sector_for_addr (FuDfuTarget *self, guint32 addr) +{ + FuDfuTargetPrivate *priv = GET_PRIVATE (self); + + for (guint i = 0; i < priv->sectors->len; i++) { + FuDfuSector *sector = g_ptr_array_index (priv->sectors, i); + if (addr < fu_dfu_sector_get_address (sector)) + continue; + if (addr > fu_dfu_sector_get_address (sector) + + fu_dfu_sector_get_size (sector)) + continue; + return sector; + } + return NULL; +} + +static gboolean +fu_dfu_target_parse_sector (FuDfuTarget *self, + const gchar *dfuse_sector_id, + guint32 *addr, + guint16 zone, + guint16 number, + GError **error) +{ + FuDfuTargetPrivate *priv = GET_PRIVATE (self); + FuDfuSectorCap cap = DFU_SECTOR_CAP_NONE; + gchar *tmp; + guint32 addr_offset = 0; + guint64 nr_sectors; + guint64 sector_size; + + /* parse # of sectors */ + nr_sectors = g_ascii_strtoull (dfuse_sector_id, &tmp, 10); + if (nr_sectors > 999) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Invalid number of sectors: %s", + dfuse_sector_id); + return FALSE; + } + + /* check this is the delimiter */ + if (tmp[0] != '*') { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Invalid sector ID: %s", + dfuse_sector_id); + return FALSE; + } + + /* parse sector size */ + sector_size = g_ascii_strtoull (tmp + 1, &tmp, 10); + if (sector_size > 999) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Invalid sector size: %s", + dfuse_sector_id); + return FALSE; + } + + /* handle weirdness */ + if (fu_device_has_custom_flag (FU_DEVICE (fu_dfu_target_get_device (self)), + "absent-sector-size")) { + if (tmp[1] == '\0') { + tmp[1] = tmp[0]; + tmp[0] = 'B'; + } + } + + /* get multiplier */ + switch (tmp[0]) { + case 'B': /* byte */ + case ' ': /* byte, ST reference bootloader :/ */ + break; + case 'K': /* Kilo */ + sector_size *= 0x400; + break; + case 'M': /* Mega */ + sector_size *= 0x100000 ; + break; + default: + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Invalid sector multiplier: %s", + tmp); + return FALSE; + } + + /* get sector type */ + switch (tmp[1]) { + case 'a': + cap = DFU_SECTOR_CAP_READABLE; + break; + case 'b': + cap = DFU_SECTOR_CAP_ERASEABLE; + break; + case 'c': + cap = DFU_SECTOR_CAP_READABLE | + DFU_SECTOR_CAP_ERASEABLE; + break; + case 'd': + cap = DFU_SECTOR_CAP_WRITEABLE; + break; + case 'e': + cap = DFU_SECTOR_CAP_READABLE | + DFU_SECTOR_CAP_WRITEABLE; + break; + case 'f': + cap = DFU_SECTOR_CAP_ERASEABLE | + DFU_SECTOR_CAP_WRITEABLE; + break; + case 'g': + cap = DFU_SECTOR_CAP_READABLE | + DFU_SECTOR_CAP_ERASEABLE | + DFU_SECTOR_CAP_WRITEABLE; + break; + default: + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Invalid sector type: %s", + tmp); + return FALSE; + } + + /* add all the sectors */ + for (guint i = 0; i < nr_sectors; i++) { + FuDfuSector *sector; + sector = fu_dfu_sector_new (*addr + addr_offset, + (guint32) sector_size, + (guint32) ((nr_sectors * sector_size) - addr_offset), + zone, + number, + cap); + g_ptr_array_add (priv->sectors, sector); + addr_offset += fu_dfu_sector_get_size (sector); + } + + /* update for next sector */ + *addr += addr_offset; + return TRUE; +} + +gboolean +fu_dfu_target_parse_sectors (FuDfuTarget *self, const gchar *alt_name, GError **error) +{ + FuDfuTargetPrivate *priv = GET_PRIVATE (self); + g_auto(GStrv) zones = NULL; + + /* not set */ + if (alt_name == NULL) + return TRUE; + + /* From the Neo Freerunner */ + if (g_str_has_prefix (alt_name, "RAM 0x")) { + FuDfuSector *sector; + guint64 addr_tmp; + addr_tmp = g_ascii_strtoull (alt_name + 6, NULL, 16); + if (addr_tmp == 0 || addr_tmp > G_MAXUINT32) + return FALSE; + g_debug ("RAM description, so parsing"); + sector = fu_dfu_sector_new ((guint32) addr_tmp, + 0x0, /* size */ + 0x0, /* size_left */ + 0x0, /* zone */ + 0x0, /* number */ + DFU_SECTOR_CAP_ERASEABLE | + DFU_SECTOR_CAP_READABLE | + DFU_SECTOR_CAP_WRITEABLE); + g_ptr_array_add (priv->sectors, sector); + } + + /* not a DfuSe alternative name */ + if (alt_name[0] != '@') + return TRUE; + + /* clear any existing zones */ + g_ptr_array_set_size (priv->sectors, 0); + + /* parse zones */ + zones = g_strsplit (alt_name, "/", -1); + g_free (priv->alt_name_for_display); + priv->alt_name_for_display = g_strdup (g_strchomp (zones[0] + 1)); + for (guint i = 1; zones[i] != NULL; i += 2) { + guint32 addr; + guint64 addr_tmp; + g_auto(GStrv) sectors = NULL; + + /* parse address */ + if (!g_str_has_prefix (zones[i], "0x")) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "No sector address"); + return FALSE; + } + addr_tmp = g_ascii_strtoull (zones[i] + 2, NULL, 16); + if (addr_tmp > G_MAXUINT32) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Sector address too large"); + return FALSE; + } + addr = (guint32) addr_tmp; + + /* no sectors?! */ + if (zones[i+1] == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "No sector section"); + return FALSE; + } + + /* parse sectors */ + sectors = g_strsplit (zones[i+1], ",", -1); + for (guint16 j = 0; sectors[j] != NULL; j++) { + if (!fu_dfu_target_parse_sector (self, + sectors[j], + &addr, + (i - 1) / 2, j, + error)) { + g_prefix_error (error, + "Failed to parse: '%s': ", + sectors[j]); + return FALSE; + } + } + } + + /* success */ + return TRUE; +} + +/** + * fu_dfu_target_new: (skip) + * + * Creates a new DFU target, which represents an alt-setting on a + * DFU-capable device. + * + * Return value: a #FuDfuTarget + **/ +FuDfuTarget * +fu_dfu_target_new (void) +{ + FuDfuTarget *self; + self = g_object_new (FU_TYPE_DFU_TARGET, NULL); + return self; +} + +/** + * fu_dfu_target_get_sectors: + * @self: a #FuDfuTarget + * + * Gets the sectors exported by the target. + * + * Return value: (transfer none) (element-type FuDfuSector): sectors + **/ +GPtrArray * +fu_dfu_target_get_sectors (FuDfuTarget *self) +{ + FuDfuTargetPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DFU_TARGET (self), NULL); + return priv->sectors; +} + +/** + * fu_dfu_target_get_sector_default: + * @self: a #FuDfuTarget + * + * Gets the default (first) sector exported by the target. + * + * Return value: (transfer none): a #FuDfuSector, or %NULL + **/ +FuDfuSector * +fu_dfu_target_get_sector_default (FuDfuTarget *self) +{ + FuDfuTargetPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DFU_TARGET (self), NULL); + if (priv->sectors->len == 0) + return NULL; + return FU_DFU_SECTOR (g_ptr_array_index (priv->sectors, 0)); +} + +/** + * fu_dfu_target_status_to_error_msg: + * @status: a #FuDfuStatus, e.g. %FU_DFU_STATUS_ERR_ERASE + * + * Converts an enumerated value to an error description. + * + * Return value: a string + **/ +static const gchar * +fu_dfu_target_status_to_error_msg (FuDfuStatus status) +{ + if (status == FU_DFU_STATUS_OK) + return "No error condition is present"; + if (status == FU_DFU_STATUS_ERR_TARGET) + return "Firmware is not for designed this device"; + if (status == FU_DFU_STATUS_ERR_FILE) + return "Firmware is for this device but fails verification"; + if (status == FU_DFU_STATUS_ERR_WRITE) + return "Device is unable to write memory"; + if (status == FU_DFU_STATUS_ERR_ERASE) + return "Memory erase function failed"; + if (status == FU_DFU_STATUS_ERR_CHECK_ERASED) + return "Memory erase check failed"; + if (status == FU_DFU_STATUS_ERR_PROG) + return "Program memory function failed"; + if (status == FU_DFU_STATUS_ERR_VERIFY) + return "Programmed memory failed verification"; + if (status == FU_DFU_STATUS_ERR_ADDRESS) + return "Cannot program memory due to address out of range"; + if (status == FU_DFU_STATUS_ERR_NOTDONE) + return "Received zero-length download but data is incomplete"; + if (status == FU_DFU_STATUS_ERR_FIRMWARE) + return "Device firmware is corrupt"; + if (status == FU_DFU_STATUS_ERR_VENDOR) + return "Vendor-specific error"; + if (status == FU_DFU_STATUS_ERR_USBR) + return "Device detected unexpected USB reset signaling"; + if (status == FU_DFU_STATUS_ERR_POR) + return "Device detected unexpected power on reset"; + if (status == FU_DFU_STATUS_ERR_UNKNOWN) + return "Something unexpected went wrong"; + if (status == FU_DFU_STATUS_ERR_STALLDPKT) + return "Device stalled an unexpected request"; + return NULL; +} + +static gboolean +fu_dfu_target_manifest_wait (FuDfuTarget *self, GError **error) +{ + FuDfuTargetPrivate *priv = GET_PRIVATE (self); + guint polling_count = 0; + + /* get the status */ + if (!fu_dfu_device_refresh (priv->device, error)) + return FALSE; + + /* wait for FU_DFU_STATE_DFU_MANIFEST to not be set */ + while (fu_dfu_device_get_state (priv->device) == FU_DFU_STATE_DFU_MANIFEST_SYNC || + fu_dfu_device_get_state (priv->device) == FU_DFU_STATE_DFU_MANIFEST) { + g_debug ("waiting for FU_DFU_STATE_DFU_MANIFEST to clear"); + + if (polling_count++ > DFU_TARGET_MANIFEST_MAX_POLLING_TRIES) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "reach to max polling tries"); + return FALSE; + } + + g_usleep ((fu_dfu_device_get_download_timeout (priv->device) + 1000) * 1000); + if (!fu_dfu_device_refresh (priv->device, error)) + return FALSE; + } + + /* in an error state */ + if (fu_dfu_device_get_state (priv->device) == FU_DFU_STATE_DFU_ERROR) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + fu_dfu_target_status_to_error_msg (fu_dfu_device_get_status (priv->device))); + return FALSE; + } + + return TRUE; +} + +gboolean +fu_dfu_target_check_status (FuDfuTarget *self, GError **error) +{ + FuDfuTargetPrivate *priv = GET_PRIVATE (self); + FuDfuStatus status; + g_autoptr(GTimer) timer = g_timer_new (); + + /* get the status */ + if (!fu_dfu_device_refresh (priv->device, error)) + return FALSE; + + /* wait for dfuDNBUSY to not be set */ + while (fu_dfu_device_get_state (priv->device) == FU_DFU_STATE_DFU_DNBUSY) { + g_debug ("waiting for FU_DFU_STATE_DFU_DNBUSY to clear"); + g_usleep (fu_dfu_device_get_download_timeout (priv->device) * 1000); + if (!fu_dfu_device_refresh (priv->device, error)) + return FALSE; + /* this is a really long time to save fwupd in case + * the device has got wedged */ + if (g_timer_elapsed (timer, NULL) > 120.f) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Stuck in DFU_DNBUSY"); + return FALSE; + } + } + + /* not in an error state */ + if (fu_dfu_device_get_state (priv->device) != FU_DFU_STATE_DFU_ERROR) + return TRUE; + + /* STM32-specific long errors */ + status = fu_dfu_device_get_status (priv->device); + if (fu_dfu_device_get_version (priv->device) == DFU_VERSION_DFUSE) { + if (status == FU_DFU_STATUS_ERR_VENDOR) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Read protection is active"); + return FALSE; + } + if (status == FU_DFU_STATUS_ERR_TARGET) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Address is wrong or unsupported"); + return FALSE; + } + } + + /* use a proper error description */ + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + fu_dfu_target_status_to_error_msg (status)); + return FALSE; +} + +/** + * fu_dfu_target_use_alt_setting: + * @self: a #FuDfuTarget + * @error: a #GError, or %NULL + * + * Opens a DFU-capable target. + * + * Return value: %TRUE for success + **/ +static gboolean +fu_dfu_target_use_alt_setting (FuDfuTarget *self, GError **error) +{ + FuDfuTargetPrivate *priv = GET_PRIVATE (self); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (priv->device)); + g_autoptr(GError) error_local = NULL; + + g_return_val_if_fail (FU_IS_DFU_TARGET (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* ensure interface is claimed */ + if (!fu_dfu_device_ensure_interface (priv->device, error)) + return FALSE; + + /* use the correct setting */ + if (fu_device_has_flag (FU_DEVICE (priv->device), FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { + if (!g_usb_device_set_interface_alt (usb_device, + (gint) fu_dfu_device_get_interface (priv->device), + (gint) priv->alt_setting, + &error_local)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "cannot set alternate setting 0x%02x on interface %i: %s", + priv->alt_setting, + fu_dfu_device_get_interface (priv->device), + error_local->message); + return FALSE; + } + } + + return TRUE; +} + +void +fu_dfu_target_set_alt_name (FuDfuTarget *self, const gchar *alt_name) +{ + FuDfuTargetPrivate *priv = GET_PRIVATE (self); + + /* not changed */ + if (g_strcmp0 (priv->alt_name, alt_name) == 0) + return; + + g_free (priv->alt_name); + priv->alt_name = g_strdup (alt_name); +} + +void +fu_dfu_target_set_device (FuDfuTarget *self, FuDfuDevice *device) +{ + FuDfuTargetPrivate *priv = GET_PRIVATE (self); + g_set_object (&priv->device, device); + + /* if we try to ref the target and destroy the device */ + g_object_add_weak_pointer (G_OBJECT (priv->device), + (gpointer *) &priv->device); +} + +/** + * fu_dfu_target_setup: + * @self: a #FuDfuTarget + * @error: a #GError, or %NULL + * + * Opens a DFU-capable target. + * + * Return value: %TRUE for success + **/ +gboolean +fu_dfu_target_setup (FuDfuTarget *self, GError **error) +{ + FuDfuTargetClass *klass = FU_DFU_TARGET_GET_CLASS (self); + FuDfuTargetPrivate *priv = GET_PRIVATE (self); + FuDevice *device = FU_DEVICE (fu_dfu_target_get_device (self)); + + g_return_val_if_fail (FU_IS_DFU_TARGET (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* already done */ + if (priv->done_setup) + return TRUE; + + /* superclassed */ + if (klass->setup != NULL) { + if (!klass->setup (self,error)) + return FALSE; + } + + /* GD32VF103 devices features and peripheral list */ + if (priv->alt_setting == 0x0 && + fu_device_has_custom_flag (device, "gd32")) { + /* RB R8 R6 R4 VB V8 + * Flash (KB) 128 64 32 16 128 64 + * TB T8 T6 T4 CB C8 C6 C4 + * Flash (KB) 128 64 32 16 128 64 32 16 + */ + const gchar *serial = fu_device_get_serial (device); + if (serial == NULL || strlen (serial) < 4 || serial[3] != 'J') { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "GD32 serial number %s invalid", + serial); + return FALSE; + } + if (serial[2] == '2') { + fu_dfu_target_set_alt_name (self, "@Internal Flash /0x8000000/8*1Kg"); + } else if (serial[2] == '4') { + fu_dfu_target_set_alt_name (self, "@Internal Flash /0x8000000/16*1Kg"); + } else if (serial[2] == '6') { + fu_dfu_target_set_alt_name (self, "@Internal Flash /0x8000000/32*1Kg"); + } else if (serial[2] == '8') { + fu_dfu_target_set_alt_name (self, "@Internal Flash /0x8000000/64*1Kg"); + } else if (serial[2] == 'B') { + fu_dfu_target_set_alt_name (self, "@Internal Flash /0x8000000/128*1Kg"); + } else if (serial[2] == 'D') { + fu_dfu_target_set_alt_name (self, "@Internal Flash /0x8000000/256*1Kg"); + } else { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Unknown GD32 sector size: %c", + serial[2]); + return FALSE; + } + } + + /* get string */ + if (priv->alt_idx != 0x00 && priv->alt_name == NULL) { + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (priv->device)); + priv->alt_name = + g_usb_device_get_string_descriptor (usb_device, + priv->alt_idx, + NULL); + } + + /* parse the DfuSe format according to UM0424 */ + if (priv->sectors->len == 0) { + if (!fu_dfu_target_parse_sectors (self, priv->alt_name, error)) + return FALSE; + } + + /* add a dummy entry */ + if (priv->sectors->len == 0) { + FuDfuSector *sector; + sector = fu_dfu_sector_new (0x0, /* addr */ + 0x0, /* size */ + 0x0, /* size_left */ + 0x0, /* zone */ + 0x0, /* number */ + DFU_SECTOR_CAP_READABLE | + DFU_SECTOR_CAP_WRITEABLE); + g_debug ("no UM0424 sector description in %s", priv->alt_name); + g_ptr_array_add (priv->sectors, sector); + } + + priv->done_setup = TRUE; + return TRUE; +} + +/** + * fu_dfu_target_mass_erase: + * @self: a #FuDfuTarget + * @error: a #GError, or %NULL + * + * Mass erases the device clearing all SRAM and EEPROM memory. + * + * IMPORTANT: This only works on STM32 devices from ST and AVR32 devices from Atmel. + * + * Return value: %TRUE for success + **/ +gboolean +fu_dfu_target_mass_erase (FuDfuTarget *self, GError **error) +{ + FuDfuTargetClass *klass = FU_DFU_TARGET_GET_CLASS (self); + if (!fu_dfu_target_setup (self,error)) + return FALSE; + if (klass->mass_erase == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "mass erase not supported"); + return FALSE; + } + return klass->mass_erase (self,error); +} + +gboolean +fu_dfu_target_download_chunk (FuDfuTarget *self, guint16 index, GBytes *bytes, GError **error) +{ + FuDfuTargetPrivate *priv = GET_PRIVATE (self); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (priv->device)); + g_autoptr(GError) error_local = NULL; + gsize actual_length; + + /* low level packet debugging */ + if (g_getenv ("FWUPD_DFU_VERBOSE") != NULL) + fu_common_dump_bytes (G_LOG_DOMAIN, "Message", bytes); + + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_CLASS, + G_USB_DEVICE_RECIPIENT_INTERFACE, + FU_DFU_REQUEST_DNLOAD, + index, + fu_dfu_device_get_interface (priv->device), + (guint8 *) g_bytes_get_data (bytes, NULL), + g_bytes_get_size (bytes), + &actual_length, + fu_dfu_device_get_timeout (priv->device), + NULL, + &error_local)) { + /* refresh the error code */ + fu_dfu_device_error_fixup (priv->device, &error_local); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "cannot download data: %s", + error_local->message); + return FALSE; + } + + /* for STM32 devices, the action only occurs when we do GetStatus */ + if (fu_dfu_device_get_version (priv->device) == DFU_VERSION_DFUSE) { + if (!fu_dfu_device_refresh (priv->device, error)) + return FALSE; + } + + /* wait for the device to write contents to the EEPROM */ + if (g_bytes_get_size (bytes) == 0 && + fu_dfu_device_get_download_timeout (priv->device) > 0) { + fu_dfu_target_set_action (self,FWUPD_STATUS_IDLE); + fu_dfu_target_set_action (self,FWUPD_STATUS_DEVICE_BUSY); + } + if (fu_dfu_device_get_download_timeout (priv->device) > 0) { + g_debug ("sleeping for %ums…", + fu_dfu_device_get_download_timeout (priv->device)); + g_usleep (fu_dfu_device_get_download_timeout (priv->device) * 1000); + } + + /* find out if the write was successful, waiting for BUSY to clear */ + if (!fu_dfu_target_check_status (self,error)) + return FALSE; + + g_assert (actual_length == g_bytes_get_size (bytes)); + return TRUE; +} + +GBytes * +fu_dfu_target_upload_chunk (FuDfuTarget *self, guint16 index, gsize buf_sz, GError **error) +{ + FuDfuTargetPrivate *priv = GET_PRIVATE (self); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (priv->device)); + g_autoptr(GError) error_local = NULL; + guint8 *buf; + gsize actual_length; + + /* unset */ + if (buf_sz == 0) + buf_sz = (gsize) fu_dfu_device_get_transfer_size (priv->device); + + buf = g_new0 (guint8, buf_sz); + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, + G_USB_DEVICE_REQUEST_TYPE_CLASS, + G_USB_DEVICE_RECIPIENT_INTERFACE, + FU_DFU_REQUEST_UPLOAD, + index, + fu_dfu_device_get_interface (priv->device), + buf, buf_sz, + &actual_length, + fu_dfu_device_get_timeout (priv->device), + NULL, + &error_local)) { + /* refresh the error code */ + fu_dfu_device_error_fixup (priv->device, &error_local); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "cannot upload data: %s", + error_local->message); + return NULL; + } + + /* low level packet debugging */ + if (g_getenv ("FWUPD_DFU_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "Message", buf, actual_length); + + return g_bytes_new_take (buf, actual_length); +} + +void +fu_dfu_target_set_alt_idx (FuDfuTarget *self, guint8 alt_idx) +{ + FuDfuTargetPrivate *priv = GET_PRIVATE (self); + priv->alt_idx = alt_idx; +} + +void +fu_dfu_target_set_alt_setting (FuDfuTarget *self, guint8 alt_setting) +{ + FuDfuTargetPrivate *priv = GET_PRIVATE (self); + priv->alt_setting = alt_setting; +} + +void +fu_dfu_target_set_action (FuDfuTarget *self, FwupdStatus action) +{ + FuDfuTargetPrivate *priv = GET_PRIVATE (self); + + /* unchanged */ + if (priv->old_action == action) + return; + if (priv->old_action != FWUPD_STATUS_IDLE && + action != FWUPD_STATUS_IDLE) { + g_debug ("ignoring action %s as %s already set and not idle", + fwupd_status_to_string (action), + fwupd_status_to_string (priv->old_action)); + return; + } + g_debug ("setting action %s", fwupd_status_to_string (action)); + g_signal_emit (self,signals[SIGNAL_ACTION_CHANGED], 0, action); + priv->old_action = action; +} + +FuDfuDevice * +fu_dfu_target_get_device (FuDfuTarget *self) +{ + FuDfuTargetPrivate *priv = GET_PRIVATE (self); + return priv->device; +} + +void +fu_dfu_target_set_percentage_raw (FuDfuTarget *self, guint percentage) +{ + FuDfuTargetPrivate *priv = GET_PRIVATE (self); + if (percentage == priv->old_percentage) + return; + g_debug ("setting percentage %u%% of %s", + percentage, fwupd_status_to_string (priv->old_action)); + g_signal_emit (self, + signals[SIGNAL_PERCENTAGE_CHANGED], + 0, percentage); + priv->old_percentage = percentage; +} + +void +fu_dfu_target_set_percentage (FuDfuTarget *self, guint value, guint total) +{ + guint percentage; + + g_return_if_fail (total > 0); + + percentage = (value * 100) / total; + if (percentage >= 100) + return; + fu_dfu_target_set_percentage_raw (self, percentage); +} + +gboolean +fu_dfu_target_attach (FuDfuTarget *self, GError **error) +{ + FuDfuTargetPrivate *priv = GET_PRIVATE (self); + FuDfuTargetClass *klass = FU_DFU_TARGET_GET_CLASS (self); + + /* ensure populated */ + if (!fu_dfu_target_setup (self, error)) + return FALSE; + + /* implemented as part of a superclass */ + if (klass->attach != NULL) + return klass->attach (self, error); + + /* normal DFU mode just needs a bus reset */ + return fu_dfu_device_reset (priv->device, error); +} + +static FuChunk * +fu_dfu_target_upload_element_dfu (FuDfuTarget *self, + guint32 address, + gsize expected_size, + gsize maximum_size, + GError **error) +{ + FuDfuTargetPrivate *priv = GET_PRIVATE (self); + GBytes *chunk_tmp; + guint32 offset = 0; + guint percentage_size = expected_size > 0 ? expected_size : maximum_size; + gsize total_size = 0; + guint16 transfer_size = fu_dfu_device_get_transfer_size (priv->device); + g_autoptr(GBytes) contents = NULL; + g_autoptr(GPtrArray) chunks = NULL; + + /* update UI */ + fu_dfu_target_set_action (self, FWUPD_STATUS_DEVICE_READ); + + /* get all the chunks from the hardware */ + chunks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref); + for (guint16 idx = 0; idx < G_MAXUINT16; idx++) { + guint32 chunk_size; + + /* read chunk of data */ + chunk_tmp = fu_dfu_target_upload_chunk (self, + idx, + 0, /* device transfer size */ + error); + if (chunk_tmp == NULL) + return NULL; + + /* keep a sum of all the chunks */ + chunk_size = (guint32) g_bytes_get_size (chunk_tmp); + total_size += chunk_size; + offset += chunk_size; + + /* add to array */ + g_debug ("got #%04x chunk of size %" G_GUINT32_FORMAT, + idx, chunk_size); + g_ptr_array_add (chunks, chunk_tmp); + + /* update UI */ + if (chunk_size > 0) + fu_dfu_target_set_percentage (self, total_size, percentage_size); + + /* detect short write as EOF */ + if (chunk_size < transfer_size) + break; + } + + /* check final size */ + if (expected_size > 0) { + if (total_size != expected_size) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "invalid size, got %" G_GSIZE_FORMAT ", " + "expected %" G_GSIZE_FORMAT , + total_size, expected_size); + return NULL; + } + } + + /* done */ + fu_dfu_target_set_percentage_raw (self, 100); + fu_dfu_target_set_action (self, FWUPD_STATUS_IDLE); + + /* create new image */ + contents = fu_dfu_utils_bytes_join_array (chunks); + return fu_chunk_bytes_new (contents); +} + +static FuChunk * +fu_dfu_target_upload_element (FuDfuTarget *self, + guint32 address, + gsize expected_size, + gsize maximum_size, + GError **error) +{ + FuDfuTargetClass *klass = FU_DFU_TARGET_GET_CLASS (self); + + /* implemented as part of a superclass */ + if (klass->upload_element != NULL) { + return klass->upload_element (self, address, expected_size, + maximum_size, error); + } + return fu_dfu_target_upload_element_dfu (self, + address, + expected_size, + maximum_size, + error); +} + +static guint32 +fu_dfu_target_get_size_of_zone (FuDfuTarget *self, guint16 zone) +{ + FuDfuTargetPrivate *priv = GET_PRIVATE (self); + guint32 len = 0; + for (guint i = 0; i < priv->sectors->len; i++) { + FuDfuSector *sector = g_ptr_array_index (priv->sectors, i); + if (fu_dfu_sector_get_zone (sector) != zone) + continue; + len += fu_dfu_sector_get_size (sector); + } + return len; +} + +/* private */ +gboolean +fu_dfu_target_upload (FuDfuTarget *self, + FuFirmware *firmware, + FuDfuTargetTransferFlags flags, + GError **error) +{ + FuDfuTargetPrivate *priv = GET_PRIVATE (self); + FuDfuSector *sector; + guint16 zone_cur; + guint32 zone_size = 0; + guint32 zone_last = G_MAXUINT; + g_autoptr(FuFirmwareImage) image = NULL; + + g_return_val_if_fail (FU_IS_DFU_TARGET (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* ensure populated */ + if (!fu_dfu_target_setup (self, error)) + return FALSE; + + /* can the target do this? */ + if (!fu_dfu_device_can_upload (priv->device)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "target cannot do uploading"); + return FALSE; + } + + /* use correct alt */ + if (!fu_dfu_target_use_alt_setting (self, error)) + return FALSE; + + /* no open?! */ + if (priv->sectors->len == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "no sectors defined for target"); + return FALSE; + } + + /* create a new image */ + image = fu_firmware_image_new (NULL); + fu_firmware_image_set_id (image, priv->alt_name); + fu_firmware_image_set_idx (image, priv->alt_setting); + + /* get all the sectors for the device */ + for (guint i = 0; i < priv->sectors->len; i++) { + g_autoptr(FuChunk) chk = NULL; + + /* only upload to the start of any zone:sector */ + sector = g_ptr_array_index (priv->sectors, i); + zone_cur = fu_dfu_sector_get_zone (sector); + if (zone_cur == zone_last) + continue; + + /* get the size of the entire continuous zone */ + zone_size = fu_dfu_target_get_size_of_zone (self, zone_cur); + zone_last = zone_cur; + + /* get the first element from the hardware */ + g_debug ("starting upload from 0x%08x (0x%04x)", + fu_dfu_sector_get_address (sector), + zone_size); + chk = fu_dfu_target_upload_element (self, + fu_dfu_sector_get_address (sector), + 0, /* expected */ + zone_size, /* maximum */ + error); + if (chk == NULL) + return FALSE; + + /* this chunk was uploaded okay */ + fu_firmware_image_add_chunk (image, chk); + } + + /* success */ + fu_firmware_add_image (firmware, image); + return TRUE; +} + +static gchar * +_g_bytes_compare_verbose (GBytes *bytes1, GBytes *bytes2) +{ + const guint8 *data1; + const guint8 *data2; + gsize length1; + gsize length2; + + data1 = g_bytes_get_data (bytes1, &length1); + data2 = g_bytes_get_data (bytes2, &length2); + + /* not the same length */ + if (length1 != length2) { + return g_strdup_printf ("got %" G_GSIZE_FORMAT " bytes, " + "expected %" G_GSIZE_FORMAT, + length1, length2); + } + + /* return 00 01 02 03 */ + for (guint i = 0; i < length1; i++) { + if (data1[i] != data2[i]) { + return g_strdup_printf ("got 0x%02x, expected 0x%02x @ 0x%04x", + data1[i], data2[i], i); + } + } + return NULL; +} + +static gboolean +fu_dfu_target_download_element_dfu (FuDfuTarget *self, + FuChunk *chk, + FuDfuTargetTransferFlags flags, + GError **error) +{ + FuDfuTargetPrivate *priv = GET_PRIVATE (self); + guint32 nr_chunks; + guint16 transfer_size = fu_dfu_device_get_transfer_size (priv->device); + g_autoptr(GBytes) bytes = NULL; + + /* round up as we have to transfer incomplete blocks */ + bytes = fu_chunk_get_bytes (chk); + nr_chunks = (guint) ceil ((gdouble) g_bytes_get_size (bytes) / + (gdouble) transfer_size); + if (nr_chunks == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "zero-length firmware"); + return FALSE; + } + fu_dfu_target_set_action (self, FWUPD_STATUS_DEVICE_WRITE); + for (guint32 i = 0; i < nr_chunks + 1; i++) { + gsize length; + guint32 offset; + g_autoptr(GBytes) bytes_tmp = NULL; + + /* caclulate the offset into the chunk data */ + offset = i * transfer_size; + + /* we have to write one final zero-sized chunk for EOF */ + if (i < nr_chunks) { + length = g_bytes_get_size (bytes) - offset; + if (length > transfer_size) + length = transfer_size; + bytes_tmp = fu_common_bytes_new_offset (bytes, + offset, + length, + error); + if (bytes_tmp == NULL) + return FALSE; + } else { + bytes_tmp = g_bytes_new (NULL, 0); + } + g_debug ("writing #%04x chunk of size %" G_GSIZE_FORMAT, + i, g_bytes_get_size (bytes_tmp)); + if (!fu_dfu_target_download_chunk (self, i, bytes_tmp, error)) + return FALSE; + + /* update UI */ + fu_dfu_target_set_percentage (self, offset, g_bytes_get_size (bytes)); + } + + /* done */ + fu_dfu_target_set_percentage_raw (self, 100); + fu_dfu_target_set_action (self, FWUPD_STATUS_IDLE); + + /* success */ + return TRUE; +} + +static gboolean +fu_dfu_target_download_element (FuDfuTarget *self, + FuChunk *chk, + FuDfuTargetTransferFlags flags, + GError **error) +{ + FuDfuTargetPrivate *priv = GET_PRIVATE (self); + FuDfuTargetClass *klass = FU_DFU_TARGET_GET_CLASS (self); + + /* implemented as part of a superclass */ + if (klass->download_element != NULL) { + if (!klass->download_element (self, chk, flags, error)) + return FALSE; + } else { + if (!fu_dfu_target_download_element_dfu (self, + chk, + flags, + error)) + return FALSE; + } + + /* verify */ + if (flags & DFU_TARGET_TRANSFER_FLAG_VERIFY && + fu_dfu_device_has_attribute (priv->device, FU_DFU_DEVICE_ATTR_CAN_UPLOAD)) { + g_autoptr(GBytes) bytes = NULL; + g_autoptr(GBytes) bytes_tmp = NULL; + g_autoptr(FuChunk) chunk_tmp = NULL; + fu_dfu_target_set_action (self, FWUPD_STATUS_DEVICE_VERIFY); + bytes = fu_chunk_get_bytes (chk); + chunk_tmp = fu_dfu_target_upload_element (self, + fu_chunk_get_address (chk), + g_bytes_get_size (bytes), + g_bytes_get_size (bytes), + error); + if (chunk_tmp == NULL) + return FALSE; + bytes_tmp = fu_chunk_get_bytes (chunk_tmp); + if (g_bytes_compare (bytes_tmp, bytes) != 0) { + g_autofree gchar *bytes_cmp_str = NULL; + bytes_cmp_str = _g_bytes_compare_verbose (bytes_tmp, bytes); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "verify failed: %s", + bytes_cmp_str); + return FALSE; + } + fu_dfu_target_set_action (self, FWUPD_STATUS_IDLE); + } + + return TRUE; +} + +/** + * fu_dfu_target_download: + * @self: a #FuDfuTarget + * @image: a #FuFirmwareImage + * @flags: flags to use, e.g. %DFU_TARGET_TRANSFER_FLAG_VERIFY + * @error: a #GError, or %NULL + * + * Downloads firmware from the host to the target, optionally verifying + * the transfer. + * + * Return value: %TRUE for success + **/ +gboolean +fu_dfu_target_download (FuDfuTarget *self, + FuFirmwareImage *image, + FuDfuTargetTransferFlags flags, + GError **error) +{ + FuDfuTargetPrivate *priv = GET_PRIVATE (self); + g_autoptr(GPtrArray) chunks = NULL; + + g_return_val_if_fail (FU_IS_DFU_TARGET (self), FALSE); + g_return_val_if_fail (FU_IS_FIRMWARE_IMAGE (image), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* ensure populated */ + if (!fu_dfu_target_setup (self, error)) + return FALSE; + + /* can the target do this? */ + if (!fu_dfu_device_can_download (priv->device)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "target cannot do downloading"); + return FALSE; + } + + /* use correct alt */ + if (!fu_dfu_target_use_alt_setting (self, error)) + return FALSE; + + /* download all chunks in the image to the device */ + chunks = fu_firmware_image_get_chunks (image, error); + if (chunks == NULL) + return FALSE; + if (chunks->len == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "no image chunks"); + return FALSE; + } + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + g_debug ("downloading chunk at 0x%04x", + fu_chunk_get_address (chk)); + + /* auto-detect missing firmware address -- this assumes + * that the first target is the main program memory and that + * there is only one element in the firmware file */ + if (flags & DFU_TARGET_TRANSFER_FLAG_ADDR_HEURISTIC && + fu_chunk_get_address (chk) == 0x0 && + chunks->len == 1 && + priv->sectors->len > 0) { + FuDfuSector *sector = g_ptr_array_index (priv->sectors, 0); + g_debug ("fixing up firmware address from 0x0 to 0x%x", + fu_dfu_sector_get_address (sector)); + fu_chunk_set_address (chk, fu_dfu_sector_get_address (sector)); + } + + /* download to device */ + if (!fu_dfu_target_download_element (self, chk, flags, error)) + return FALSE; + } + + if (fu_device_has_custom_flag (FU_DEVICE (fu_dfu_target_get_device (self)), "manifest-poll") && + fu_dfu_device_has_attribute (priv->device, FU_DFU_DEVICE_ATTR_MANIFEST_TOL)) + if (!fu_dfu_target_manifest_wait (self, error)) + return FALSE; + + /* success */ + return TRUE; +} + +/** + * fu_dfu_target_get_alt_setting: + * @self: a #FuDfuTarget + * + * Gets the alternate setting to use for this interface. + * + * Return value: the alternative setting, typically zero + **/ +guint8 +fu_dfu_target_get_alt_setting (FuDfuTarget *self) +{ + FuDfuTargetPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DFU_TARGET (self), 0xff); + return priv->alt_setting; +} + +/** + * fu_dfu_target_get_alt_name: + * @self: a #FuDfuTarget + * @error: a #GError, or %NULL + * + * Gets the alternate setting name to use for this interface. + * + * Return value: the alternative setting name, typically %NULL + **/ +const gchar * +fu_dfu_target_get_alt_name (FuDfuTarget *self, GError **error) +{ + FuDfuTargetPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DFU_TARGET (self), NULL); + + /* ensure populated */ + if (!fu_dfu_target_setup (self, error)) + return NULL; + + /* nothing */ + if (priv->alt_name == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "no alt-name"); + return NULL; + } + + return priv->alt_name; +} + +/** + * fu_dfu_target_get_alt_name_for_display: + * @self: a #FuDfuTarget + * @error: a #GError, or %NULL + * + * Gets the alternate setting name to use for this interface that can be + * shown on the display. + * + * Return value: the alternative setting name + **/ +const gchar * +fu_dfu_target_get_alt_name_for_display (FuDfuTarget *self, GError **error) +{ + FuDfuTargetPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DFU_TARGET (self), NULL); + + /* ensure populated */ + if (!fu_dfu_target_setup (self, error)) + return NULL; + + /* nothing */ + if (priv->alt_name_for_display == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "no alt-name for display"); + return NULL; + } + + return priv->alt_name_for_display; +} diff -Nru fwupd-1.4.5/plugins/dfu/fu-dfu-target.h fwupd-1.5.8/plugins/dfu/fu-dfu-target.h --- fwupd-1.4.5/plugins/dfu/fu-dfu-target.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/fu-dfu-target.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2015 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include +#include +#include + +#include "fu-dfu-common.h" +#include "fu-dfu-sector.h" + +#include "fu-chunk.h" +#include "fu-firmware.h" + +#include "fwupd-enums.h" + +#define FU_TYPE_DFU_TARGET (fu_dfu_target_get_type ()) +G_DECLARE_DERIVABLE_TYPE (FuDfuTarget, fu_dfu_target, FU, DFU_TARGET, GUsbDevice) + +/** + * FuDfuTargetTransferFlags: + * @DFU_TARGET_TRANSFER_FLAG_NONE: No flags set + * @DFU_TARGET_TRANSFER_FLAG_VERIFY: Verify the download once complete + * @DFU_TARGET_TRANSFER_FLAG_WILDCARD_VID: Allow downloading images with wildcard VIDs + * @DFU_TARGET_TRANSFER_FLAG_WILDCARD_PID: Allow downloading images with wildcard PIDs + * @DFU_TARGET_TRANSFER_FLAG_ADDR_HEURISTIC: Automatically detect the address to use + * + * The optional flags used for transferring firmware. + **/ +typedef enum { + DFU_TARGET_TRANSFER_FLAG_NONE = 0, + DFU_TARGET_TRANSFER_FLAG_VERIFY = (1 << 0), + DFU_TARGET_TRANSFER_FLAG_WILDCARD_VID = (1 << 4), + DFU_TARGET_TRANSFER_FLAG_WILDCARD_PID = (1 << 5), + DFU_TARGET_TRANSFER_FLAG_ADDR_HEURISTIC = (1 << 7), + /*< private >*/ + DFU_TARGET_TRANSFER_FLAG_LAST +} FuDfuTargetTransferFlags; + +struct _FuDfuTargetClass +{ + GUsbDeviceClass parent_class; + void (*percentage_changed) (FuDfuTarget *self, + guint percentage); + void (*action_changed) (FuDfuTarget *self, + FwupdStatus action); + gboolean (*setup) (FuDfuTarget *self, + GError **error); + gboolean (*attach) (FuDfuTarget *self, + GError **error); + gboolean (*detach) (FuDfuTarget *self, + GError **error); + gboolean (*mass_erase) (FuDfuTarget *self, + GError **error); + FuChunk *(*upload_element) (FuDfuTarget *self, + guint32 address, + gsize expected_size, + gsize maximum_size, + GError **error); + gboolean (*download_element) (FuDfuTarget *self, + FuChunk *chk, + FuDfuTargetTransferFlags flags, + GError **error); +}; + +GPtrArray *fu_dfu_target_get_sectors (FuDfuTarget *self); +FuDfuSector *fu_dfu_target_get_sector_default (FuDfuTarget *self); +guint8 fu_dfu_target_get_alt_setting (FuDfuTarget *self); +const gchar *fu_dfu_target_get_alt_name (FuDfuTarget *self, + GError **error); +const gchar *fu_dfu_target_get_alt_name_for_display (FuDfuTarget *self, + GError **error); +gboolean fu_dfu_target_upload (FuDfuTarget *self, + FuFirmware *firmware, + FuDfuTargetTransferFlags flags, + GError **error); +gboolean fu_dfu_target_setup (FuDfuTarget *self, + GError **error); +gboolean fu_dfu_target_download (FuDfuTarget *self, + FuFirmwareImage *image, + FuDfuTargetTransferFlags flags, + GError **error); +gboolean fu_dfu_target_mass_erase (FuDfuTarget *self, + GError **error); +void fu_dfu_target_to_string (FuDfuTarget *self, + guint idt, + GString *str); diff -Nru fwupd-1.4.5/plugins/dfu/fu-dfu-target-private.h fwupd-1.5.8/plugins/dfu/fu-dfu-target-private.h --- fwupd-1.4.5/plugins/dfu/fu-dfu-target-private.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/fu-dfu-target-private.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2015 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#include "fu-dfu-device.h" +#include "fu-dfu-target.h" +#include "fu-dfu-sector.h" + +FuDfuTarget *fu_dfu_target_new (void); + +GBytes *fu_dfu_target_upload_chunk (FuDfuTarget *self, + guint16 index, + gsize buf_sz, + GError **error); +gboolean fu_dfu_target_download_chunk (FuDfuTarget *self, + guint16 index, + GBytes *bytes, + GError **error); +gboolean fu_dfu_target_attach (FuDfuTarget *self, + GError **error); +void fu_dfu_target_set_alt_idx (FuDfuTarget *self, + guint8 alt_idx); +void fu_dfu_target_set_alt_setting (FuDfuTarget *self, + guint8 alt_setting); + +/* for the other implementations */ +void fu_dfu_target_set_action (FuDfuTarget *self, + FwupdStatus action); +void fu_dfu_target_set_percentage_raw (FuDfuTarget *self, + guint percentage); +void fu_dfu_target_set_percentage (FuDfuTarget *self, + guint value, + guint total); +void fu_dfu_target_set_alt_name (FuDfuTarget *self, + const gchar *alt_name); +void fu_dfu_target_set_device (FuDfuTarget *self, + FuDfuDevice *device); +FuDfuDevice *fu_dfu_target_get_device (FuDfuTarget *self); +gboolean fu_dfu_target_check_status (FuDfuTarget *self, + GError **error); +FuDfuSector *fu_dfu_target_get_sector_for_addr (FuDfuTarget *self, + guint32 addr); + +/* export this just for the self tests */ +gboolean fu_dfu_target_parse_sectors (FuDfuTarget *self, + const gchar *alt_name, + GError **error); diff -Nru fwupd-1.4.5/plugins/dfu/fu-dfu-target-stm.c fwupd-1.5.8/plugins/dfu/fu-dfu-target-stm.c --- fwupd-1.4.5/plugins/dfu/fu-dfu-target-stm.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/fu-dfu-target-stm.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,413 @@ +/* + * Copyright (C) 2017 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include +#include + +#include "fu-dfu-common.h" +#include "fu-dfu-sector.h" +#include "fu-dfu-target-stm.h" +#include "fu-dfu-target-private.h" + +#include "fu-chunk.h" + +#include "fwupd-error.h" + +G_DEFINE_TYPE (FuDfuTargetStm, fu_dfu_target_stm, FU_TYPE_DFU_TARGET) + +/* STMicroelectronics STM32 version of DFU: + * www.st.com/resource/en/application_note/cd00264379.pdf */ +#define DFU_STM_CMD_GET_COMMAND 0x00 +#define DFU_STM_CMD_SET_ADDRESS_POINTER 0x21 +#define DFU_STM_CMD_ERASE 0x41 +#define DFU_STM_CMD_READ_UNPROTECT 0x92 + +static gboolean +fu_dfu_target_stm_attach (FuDfuTarget *target, GError **error) +{ + /* downloading empty payload will cause a dfu to leave, + * the returned status will be dfuMANIFEST and expect the device to disconnect */ + g_autoptr(GBytes) bytes_tmp = g_bytes_new (NULL, 0); + return fu_dfu_target_download_chunk (target, 2, bytes_tmp, error); +} + +static gboolean +fu_dfu_target_stm_mass_erase (FuDfuTarget *target, GError **error) +{ + GBytes *data_in; + guint8 buf[1]; + + /* format buffer */ + buf[0] = DFU_STM_CMD_ERASE; + data_in = g_bytes_new_static (buf, sizeof(buf)); + if (!fu_dfu_target_download_chunk (target, 0, data_in, error)) { + g_prefix_error (error, "cannot mass-erase: "); + return FALSE; + } + + /* 2nd check required to get error code */ + return fu_dfu_target_check_status (target, error); +} + +/** + * fu_dfu_target_stm_set_address: + * @target: a #FuDfuTarget + * @address: memory address + * @error: a #GError, or %NULL + * + * Sets the address used for the next download or upload request. + * + * Return value: %TRUE for success + **/ +static gboolean +fu_dfu_target_stm_set_address (FuDfuTarget *target, guint32 address, GError **error) +{ + GBytes *data_in; + guint8 buf[5]; + + /* format buffer */ + buf[0] = DFU_STM_CMD_SET_ADDRESS_POINTER; + memcpy (buf + 1, &address, 4); + data_in = g_bytes_new_static (buf, sizeof(buf)); + if (!fu_dfu_target_download_chunk (target, 0, data_in, error)) { + g_prefix_error (error, "cannot set address 0x%x: ", address); + return FALSE; + } + + /* 2nd check required to get error code */ + g_debug ("doing actual check status"); + return fu_dfu_target_check_status (target, error); +} + +static FuChunk * +fu_dfu_target_stm_upload_element (FuDfuTarget *target, + guint32 address, + gsize expected_size, + gsize maximum_size, + GError **error) +{ + FuDfuDevice *device = fu_dfu_target_get_device (target); + FuDfuSector *sector; + FuChunk *chk = NULL; + GBytes *chunk_tmp; + guint32 offset = address; + guint percentage_size = expected_size > 0 ? expected_size : maximum_size; + gsize total_size = 0; + guint16 transfer_size = fu_dfu_device_get_transfer_size (device); + g_autoptr(GBytes) contents = NULL; + g_autoptr(GBytes) contents_truncated = NULL; + g_autoptr(GPtrArray) chunks = NULL; + + /* for DfuSe devices we need to handle the address manually */ + sector = fu_dfu_target_get_sector_for_addr (target, offset); + if (sector == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "no memory sector at 0x%04x", + (guint) offset); + return NULL; + } + g_debug ("using sector %u for read of %x", + fu_dfu_sector_get_id (sector), + offset); + if (!fu_dfu_sector_has_cap (sector, DFU_SECTOR_CAP_READABLE)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "memory sector at 0x%04x is not readable", + (guint) offset); + return NULL; + } + + /* update UI */ + fu_dfu_target_set_action (target, FWUPD_STATUS_DEVICE_READ); + + /* manually set the sector address */ + g_debug ("setting DfuSe address to 0x%04x", (guint) offset); + if (!fu_dfu_target_stm_set_address (target, offset, error)) + return NULL; + + /* abort back to IDLE */ + if (!fu_dfu_device_abort (device, error)) + return NULL; + + /* get all the chunks from the hardware */ + chunks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref); + for (guint16 idx = 0; idx < G_MAXUINT16; idx++) { + guint32 chunk_size; + + /* read chunk of data -- ST uses wBlockNum=0 for DfuSe commands + * and wBlockNum=1 is reserved */ + chunk_tmp = fu_dfu_target_upload_chunk (target, + idx + 2, + 0, /* device transfer size */ + error); + if (chunk_tmp == NULL) + return NULL; + + /* add to array */ + chunk_size = (guint32) g_bytes_get_size (chunk_tmp); + g_debug ("got #%04x chunk @0x%x of size %" G_GUINT32_FORMAT, + idx, offset, chunk_size); + g_ptr_array_add (chunks, chunk_tmp); + total_size += chunk_size; + offset += chunk_size; + + /* update UI */ + if (chunk_size > 0) + fu_dfu_target_set_percentage (target, total_size, percentage_size); + + /* detect short write as EOF */ + if (chunk_size < transfer_size) + break; + + /* more data than we needed */ + if (maximum_size > 0 && total_size > maximum_size) + break; + } + + /* abort back to IDLE */ + if (!fu_dfu_device_abort (device, error)) + return NULL; + + /* check final size */ + if (expected_size > 0) { + if (total_size < expected_size) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "invalid size, got %" G_GSIZE_FORMAT ", " + "expected %" G_GSIZE_FORMAT , + total_size, expected_size); + return NULL; + } + } + + /* done */ + fu_dfu_target_set_percentage_raw (target, 100); + fu_dfu_target_set_action (target, FWUPD_STATUS_IDLE); + + /* create new image */ + contents = fu_dfu_utils_bytes_join_array (chunks); + if (expected_size > 0) { + contents_truncated = fu_common_bytes_new_offset (contents, + 0, + expected_size, + error); + if (contents_truncated == NULL) + return NULL; + } else { + contents_truncated = g_bytes_ref (contents); + } + chk = fu_chunk_bytes_new (contents_truncated); + fu_chunk_set_address (chk, address); + return chk; +} + +/** + * fu_dfu_target_stm_erase_address: + * @target: a #FuDfuTarget + * @address: memory address + * @error: a #GError, or %NULL + * + * Erases a memory sector at a given address. + * + * Return value: %TRUE for success + **/ +static gboolean +fu_dfu_target_stm_erase_address (FuDfuTarget *target, guint32 address, GError **error) +{ + GBytes *data_in; + guint8 buf[5]; + + /* format buffer */ + buf[0] = DFU_STM_CMD_ERASE; + memcpy (buf + 1, &address, 4); + data_in = g_bytes_new_static (buf, sizeof(buf)); + if (!fu_dfu_target_download_chunk (target, 0, data_in, error)) { + g_prefix_error (error, "cannot erase address 0x%x: ", address); + return FALSE; + } + + /* 2nd check required to get error code */ + g_debug ("doing actual check status"); + return fu_dfu_target_check_status (target, error); +} + +static gboolean +fu_dfu_target_stm_download_element (FuDfuTarget *target, + FuChunk *chk, + FuDfuTargetTransferFlags flags, + GError **error) +{ + FuDfuDevice *device = fu_dfu_target_get_device (target); + FuDfuSector *sector; + guint nr_chunks; + guint zone_last = G_MAXUINT; + guint16 transfer_size = fu_dfu_device_get_transfer_size (device); + g_autoptr(GBytes) bytes = NULL; + g_autoptr(GPtrArray) sectors_array = NULL; + g_autoptr(GHashTable) sectors_hash = NULL; + + /* round up as we have to transfer incomplete blocks */ + bytes = fu_chunk_get_bytes (chk); + nr_chunks = (guint) ceil ((gdouble) g_bytes_get_size (bytes) / + (gdouble) transfer_size); + if (nr_chunks == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "zero-length firmware"); + return FALSE; + } + + /* 1st pass: work out which sectors need erasing */ + sectors_array = g_ptr_array_new (); + sectors_hash = g_hash_table_new (g_direct_hash, g_direct_equal); + for (guint i = 0; i < nr_chunks; i++) { + guint32 offset_dev; + + /* for DfuSe devices we need to handle the erase and setting + * the sectory address manually */ + offset_dev = i * transfer_size; + while (offset_dev < (i + 1) * transfer_size) { + sector = fu_dfu_target_get_sector_for_addr (target, fu_chunk_get_address (chk) + offset_dev); + if (sector == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "no memory sector at 0x%04x", + (guint) fu_chunk_get_address (chk) + offset_dev); + return FALSE; + } + if (!fu_dfu_sector_has_cap (sector, DFU_SECTOR_CAP_WRITEABLE)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "memory sector at 0x%04x is not writable", + (guint) fu_chunk_get_address (chk) + offset_dev); + return FALSE; + } + + /* if it's erasable and not yet blanked */ + if (fu_dfu_sector_has_cap (sector, DFU_SECTOR_CAP_ERASEABLE) && + g_hash_table_lookup (sectors_hash, sector) == NULL) { + g_hash_table_insert (sectors_hash, + sector, + GINT_TO_POINTER (1)); + g_ptr_array_add (sectors_array, sector); + g_debug ("marking sector 0x%04x-%04x to be erased", + fu_dfu_sector_get_address (sector), + fu_dfu_sector_get_address (sector) + fu_dfu_sector_get_size (sector)); + } + offset_dev += fu_dfu_sector_get_size (sector); + } + } + + /* 2nd pass: actually erase sectors */ + fu_dfu_target_set_action (target, FWUPD_STATUS_DEVICE_ERASE); + for (guint i = 0; i < sectors_array->len; i++) { + sector = g_ptr_array_index (sectors_array, i); + g_debug ("erasing sector at 0x%04x", + fu_dfu_sector_get_address (sector)); + if (!fu_dfu_target_stm_erase_address (target, + fu_dfu_sector_get_address (sector), + error)) + return FALSE; + fu_dfu_target_set_percentage (target, i + 1, sectors_array->len); + } + fu_dfu_target_set_percentage_raw (target, 100); + fu_dfu_target_set_action (target, FWUPD_STATUS_IDLE); + + /* 3rd pass: write data */ + fu_dfu_target_set_action (target, FWUPD_STATUS_DEVICE_WRITE); + for (guint i = 0; i < nr_chunks; i++) { + gsize length; + guint32 offset; + guint32 offset_dev; + g_autoptr(GBytes) bytes_tmp = NULL; + + /* caclulate the offset into the element data */ + offset = i * transfer_size; + offset_dev = fu_chunk_get_address (chk) + offset; + + /* for DfuSe devices we need to set the address manually */ + sector = fu_dfu_target_get_sector_for_addr (target, offset_dev); + g_assert (sector != NULL); + + /* manually set the sector address */ + if (fu_dfu_sector_get_zone (sector) != zone_last) { + g_debug ("setting address to 0x%04x", + (guint) offset_dev); + if (!fu_dfu_target_stm_set_address (target, + (guint32) offset_dev, + error)) + return FALSE; + zone_last = fu_dfu_sector_get_zone (sector); + } + + /* we have to write one final zero-sized chunk for EOF */ + length = g_bytes_get_size (bytes) - offset; + if (length > transfer_size) + length = transfer_size; + bytes_tmp = fu_common_bytes_new_offset (bytes, + offset, + length, + error); + if (bytes_tmp == NULL) + return FALSE; + g_debug ("writing sector at 0x%04x (0x%" G_GSIZE_FORMAT ")", + offset_dev, + g_bytes_get_size (bytes_tmp)); + /* ST uses wBlockNum=0 for DfuSe commands and wBlockNum=1 is reserved */ + if (!fu_dfu_target_download_chunk (target, + (i + 2), + bytes_tmp, + error)) + return FALSE; + + /* getting the status moves the state machine to DNLOAD-IDLE */ + if (!fu_dfu_target_check_status (target, error)) + return FALSE; + + /* update UI */ + fu_dfu_target_set_percentage (target, offset, g_bytes_get_size (bytes)); + } + + /* done */ + fu_dfu_target_set_percentage_raw (target, 100); + fu_dfu_target_set_action (target, FWUPD_STATUS_IDLE); + + /* success */ + return TRUE; +} + +static void +fu_dfu_target_stm_init (FuDfuTargetStm *self) +{ +} + +static void +fu_dfu_target_stm_class_init (FuDfuTargetStmClass *klass) +{ + FuDfuTargetClass *klass_target = FU_DFU_TARGET_CLASS (klass); + klass_target->attach = fu_dfu_target_stm_attach; + klass_target->mass_erase = fu_dfu_target_stm_mass_erase; + klass_target->upload_element = fu_dfu_target_stm_upload_element; + klass_target->download_element = fu_dfu_target_stm_download_element; +} + +FuDfuTarget * +fu_dfu_target_stm_new (void) +{ + FuDfuTarget *target; + target = g_object_new (FU_TYPE_DFU_TARGET_STM, NULL); + return target; +} diff -Nru fwupd-1.4.5/plugins/dfu/fu-dfu-target-stm.h fwupd-1.5.8/plugins/dfu/fu-dfu-target-stm.h --- fwupd-1.4.5/plugins/dfu/fu-dfu-target-stm.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/fu-dfu-target-stm.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2017 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include +#include + +#include "fu-dfu-target.h" + +#define FU_TYPE_DFU_TARGET_STM (fu_dfu_target_stm_get_type ()) +G_DECLARE_DERIVABLE_TYPE (FuDfuTargetStm, fu_dfu_target_stm, FU, DFU_TARGET_STM, FuDfuTarget) + +struct _FuDfuTargetStmClass +{ + FuDfuTargetClass parent_class; +}; + +FuDfuTarget *fu_dfu_target_stm_new (void); diff -Nru fwupd-1.4.5/plugins/dfu/fu-dfu-tool.c fwupd-1.5.8/plugins/dfu/fu-dfu-tool.c --- fwupd-1.4.5/plugins/dfu/fu-dfu-tool.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/fu-dfu-tool.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,974 @@ +/* + * Copyright (C) 2015 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include +#include +#include +#ifdef HAVE_GIO_UNIX +#include +#endif + +#include "fu-dfu-device.h" +#include "fu-dfu-sector.h" + +#include "fu-chunk.h" +#include "fu-dfuse-firmware.h" +#include "fu-device-locker.h" + +#include "fwupd-error.h" + +typedef struct { + GCancellable *cancellable; + GPtrArray *cmd_array; + gboolean force; + gchar *device_vid_pid; + guint16 transfer_size; + FuQuirks *quirks; +} FuDfuTool; + +static void +fu_dfu_tool_free (FuDfuTool *self) +{ + if (self == NULL) + return; + g_free (self->device_vid_pid); + if (self->cancellable != NULL) + g_object_unref (self->cancellable); + g_object_unref (self->quirks); + if (self->cmd_array != NULL) + g_ptr_array_unref (self->cmd_array); + g_free (self); +} +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuDfuTool, fu_dfu_tool_free) +#pragma clang diagnostic pop + +typedef gboolean (*FuUtilPrivateCb) (FuDfuTool *util, + gchar **values, + GError **error); + +typedef struct { + gchar *name; + gchar *arguments; + gchar *description; + FuUtilPrivateCb callback; +} FuUtilItem; + +static void +fu_dfu_tool_item_free (FuUtilItem *item) +{ + g_free (item->name); + g_free (item->arguments); + g_free (item->description); + g_free (item); +} + +static gint +fu_dfu_tool_sort_command_name_cb (FuUtilItem **item1, FuUtilItem **item2) +{ + return g_strcmp0 ((*item1)->name, (*item2)->name); +} + +static void +fu_dfu_tool_add (GPtrArray *array, + const gchar *name, + const gchar *arguments, + const gchar *description, + FuUtilPrivateCb callback) +{ + g_auto(GStrv) names = NULL; + + g_return_if_fail (name != NULL); + g_return_if_fail (description != NULL); + g_return_if_fail (callback != NULL); + + /* add each one */ + names = g_strsplit (name, ",", -1); + for (guint i = 0; names[i] != NULL; i++) { + FuUtilItem *item = g_new0 (FuUtilItem, 1); + item->name = g_strdup (names[i]); + if (i == 0) { + item->description = g_strdup (description); + } else { + /* TRANSLATORS: this is a command alias, e.g. 'get-devices' */ + item->description = g_strdup_printf (_("Alias to %s"), + names[0]); + } + item->arguments = g_strdup (arguments); + item->callback = callback; + g_ptr_array_add (array, item); + } +} + +static gchar * +fu_dfu_tool_get_descriptions (GPtrArray *array) +{ + gsize len; + const gsize max_len = 31; + FuUtilItem *item; + GString *string; + + /* print each command */ + string = g_string_new (""); + for (guint i = 0; i < array->len; i++) { + item = g_ptr_array_index (array, i); + g_string_append (string, " "); + g_string_append (string, item->name); + len = strlen (item->name) + 2; + if (item->arguments != NULL) { + g_string_append (string, " "); + g_string_append (string, item->arguments); + len += strlen (item->arguments) + 1; + } + if (len < max_len) { + for (guint j = len; j < max_len + 1; j++) + g_string_append_c (string, ' '); + g_string_append (string, item->description); + g_string_append_c (string, '\n'); + } else { + g_string_append_c (string, '\n'); + for (guint j = 0; j < max_len + 1; j++) + g_string_append_c (string, ' '); + g_string_append (string, item->description); + g_string_append_c (string, '\n'); + } + } + + /* remove trailing newline */ + if (string->len > 0) + g_string_set_size (string, string->len - 1); + + return g_string_free (string, FALSE); +} + +static gboolean +fu_dfu_tool_run (FuDfuTool *self, + const gchar *command, + gchar **values, + GError **error) +{ + /* find command */ + for (guint i = 0; i < self->cmd_array->len; i++) { + FuUtilItem *item = g_ptr_array_index (self->cmd_array, i); + if (g_strcmp0 (item->name, command) == 0) + return item->callback (self, values, error); + } + + /* not found */ + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + /* TRANSLATORS: error message */ + _("Command not found")); + return FALSE; +} + +static FuDfuDevice * +fu_dfu_tool_get_default_device (FuDfuTool *self, GError **error) +{ + g_autoptr(GUsbContext) usb_context = NULL; + g_autoptr(GPtrArray) devices = NULL; + + /* get all the DFU devices */ + usb_context = g_usb_context_new (error); + if (usb_context == NULL) + return NULL; + g_usb_context_enumerate (usb_context); + + /* we specified it manually */ + if (self->device_vid_pid != NULL) { + gchar *tmp; + guint64 pid; + guint64 vid; + g_autoptr(FuDfuDevice) device = NULL; + g_autoptr(GUsbDevice) usb_device = NULL; + + /* parse */ + vid = g_ascii_strtoull (self->device_vid_pid, &tmp, 16); + if (vid == 0 || vid > G_MAXUINT16) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Invalid format of VID:PID"); + return NULL; + } + if (tmp[0] != ':') { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Invalid format of VID:PID"); + return NULL; + } + pid = g_ascii_strtoull (tmp + 1, NULL, 16); + if (pid == 0 || pid > G_MAXUINT16) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Invalid format of VID:PID"); + return NULL; + } + + /* find device */ + usb_device = g_usb_context_find_by_vid_pid (usb_context, + (guint16) vid, + (guint16) pid, + error); + if (usb_device == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "no device matches for %04x:%04x", + (guint) vid, (guint) pid); + return NULL; + } + device = fu_dfu_device_new (usb_device); + fu_device_set_quirks (FU_DEVICE (device), self->quirks); + return device; + } + + /* auto-detect first device */ + devices = g_usb_context_get_devices (usb_context); + for (guint i = 0; i < devices->len; i++) { + GUsbDevice *usb_device = g_ptr_array_index (devices, i); + g_autoptr(FuDfuDevice) device = fu_dfu_device_new (usb_device); + fu_device_set_quirks (FU_DEVICE (device), self->quirks); + if (fu_device_probe (FU_DEVICE (device), NULL)) + return g_steal_pointer (&device); + } + + /* failed */ + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "no DFU devices found"); + return NULL; +} + +static gboolean +fu_dfu_device_wait_for_replug (FuDfuTool *self, FuDfuDevice *device, guint timeout, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + g_autoptr(GUsbDevice) usb_device2 = NULL; + g_autoptr(GUsbContext) usb_context = NULL; + g_autoptr(GError) error_local = NULL; + + /* get all the DFU devices */ + usb_context = g_usb_context_new (error); + if (usb_context == NULL) + return FALSE; + + /* close */ + if (!fu_device_close (FU_DEVICE (device), &error_local)) + g_debug ("failed to close: %s", error_local->message); + + /* watch the device disappear and re-appear */ + usb_device2 = g_usb_context_wait_for_replug (usb_context, + usb_device, + timeout, + error); + if (usb_device2 == NULL) + return FALSE; + + /* re-open with new device set */ + fu_device_set_status (FU_DEVICE (device), FWUPD_STATUS_IDLE); + fu_usb_device_set_dev (FU_USB_DEVICE (device), usb_device2); + if (!fu_device_open (FU_DEVICE (device), error)) + return FALSE; + if (!fu_dfu_device_refresh_and_clear (device, error)) + return FALSE; + + /* success */ + return TRUE; +} + +static GBytes * +fu_dfu_tool_parse_hex_string (const gchar *val, GError **error) +{ + gsize result_size; + g_autofree guint8 *result = NULL; + + /* sanity check */ + if (val == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "nothing to parse"); + return NULL; + } + + /* parse each hex byte */ + result_size = strlen (val) / 2; + result = g_malloc (result_size); + for (guint i = 0; i < result_size; i++) { + gchar buf[3] = { "xx" }; + gchar *endptr = NULL; + guint64 tmp; + + /* copy two bytes and parse as hex */ + memcpy (buf, val + (i * 2), 2); + tmp = g_ascii_strtoull (buf, &endptr, 16); + if (tmp > 0xff || endptr[0] != '\0') { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to parse '%s'", val); + return NULL; + } + result[i] = tmp; + } + return g_bytes_new (result, result_size); +} + +static guint +fu_dfu_tool_bytes_replace (GBytes *data, GBytes *search, GBytes *replace) +{ + gsize data_sz; + gsize replace_sz; + gsize search_sz; + guint8 *data_buf; + guint8 *replace_buf; + guint8 *search_buf; + guint cnt = 0; + + data_buf = (gpointer) g_bytes_get_data (data, &data_sz); + search_buf = (gpointer) g_bytes_get_data (search, &search_sz); + replace_buf = (gpointer) g_bytes_get_data (replace, &replace_sz); + + g_return_val_if_fail (search_sz == replace_sz, 0); + + /* find and replace each one */ + for (gsize i = 0; i < data_sz - search_sz + 1; i++) { + if (memcmp (data_buf + i, search_buf, search_sz) == 0) { + g_print ("Replacing %" G_GSIZE_FORMAT " bytes @0x%04x\n", + replace_sz, (guint) i); + memcpy (data_buf + i, replace_buf, replace_sz); + i += replace_sz; + cnt++; + } + } + return cnt; +} + +static gboolean +fu_dfu_tool_parse_firmware_from_file (FuFirmware *firmware, GFile *file, + FwupdInstallFlags flags, + GError **error) +{ + gchar *contents = NULL; + gsize length = 0; + g_autoptr(GBytes) bytes = NULL; + if (!g_file_load_contents (file, NULL, &contents, &length, NULL, error)) + return FALSE; + bytes = g_bytes_new_take (contents, length); + return fu_firmware_parse (firmware, bytes, flags, error); +} + +static gboolean +fu_dfu_tool_write_firmware_to_file (FuFirmware *firmware, GFile *file, GError **error) +{ + const guint8 *data; + gsize length = 0; + g_autoptr(GBytes) bytes = fu_firmware_write (firmware, error); + if (bytes == NULL) + return FALSE; + data = g_bytes_get_data (bytes, &length); + return g_file_replace_contents (file, + (const gchar *) data, + length, + NULL, + FALSE, + G_FILE_CREATE_NONE, + NULL, + NULL, /* cancellable */ + error); +} + +static gboolean +fu_dfu_tool_replace_data (FuDfuTool *self, gchar **values, GError **error) +{ + guint cnt = 0; + g_autoptr(FuFirmware) firmware = NULL; + g_autoptr(GFile) file = NULL; + g_autoptr(GBytes) data_search = NULL; + g_autoptr(GBytes) data_replace = NULL; + g_autoptr(GPtrArray) images = NULL; + + /* check args */ + if (g_strv_length (values) < 3) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Invalid arguments, expected FILE SEARCH REPLACE" + " -- e.g. `firmware.dfu deadbeef beefdead"); + return FALSE; + } + + /* open */ + file = g_file_new_for_path (values[0]); + firmware = fu_dfu_firmware_new (); + if (!fu_dfu_tool_parse_firmware_from_file (firmware, file, + FWUPD_INSTALL_FLAG_NONE, + error)) { + return FALSE; + } + + /* parse hex values */ + data_search = fu_dfu_tool_parse_hex_string (values[1], error); + if (data_search == NULL) + return FALSE; + data_replace = fu_dfu_tool_parse_hex_string (values[2], error); + if (data_replace == NULL) + return FALSE; + if (g_bytes_get_size (data_search) != g_bytes_get_size (data_replace)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "search and replace were different sizes"); + return FALSE; + } + + /* get each data segment */ + images = fu_firmware_get_images (firmware); + for (guint i = 0; i < images->len; i++) { + FuFirmwareImage *image = g_ptr_array_index (images, i); + g_autoptr(GPtrArray) chunks = fu_firmware_image_get_chunks (image, error); + if (chunks == NULL) + return FALSE; + for (guint j = 0; j < chunks->len; j++) { + FuChunk *chk = g_ptr_array_index (chunks, j); + g_autoptr(GBytes) contents = fu_chunk_get_bytes (chk); + if (contents == NULL) + continue; + cnt += fu_dfu_tool_bytes_replace (contents, data_search, data_replace); + } + } + + /* nothing done */ + if (cnt == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "search string was not found"); + return FALSE; + } + + /* write out new file */ + return fu_dfu_tool_write_firmware_to_file (firmware, file, error); +} + +static void +fu_tool_action_changed_cb (FuDevice *device, GParamSpec *pspec, FuDfuTool *self) +{ + g_print ("%s:\t%u%%\n", + fwupd_status_to_string (fu_device_get_status (device)), + fu_device_get_progress (device)); +} + +static gboolean +fu_dfu_tool_read_alt (FuDfuTool *self, gchar **values, GError **error) +{ + FuDfuTargetTransferFlags flags = DFU_TARGET_TRANSFER_FLAG_NONE; + g_autofree gchar *str_debug = NULL; + g_autoptr(FuDfuDevice) device = NULL; + g_autoptr(FuFirmware) firmware = NULL; + g_autoptr(FuDfuTarget) target = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; + g_autoptr(GFile) file = NULL; + + /* check args */ + if (g_strv_length (values) < 2) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Invalid arguments, expected " + "FILENAME DEVICE-ALT-NAME|DEVICE-ALT-ID"); + return FALSE; + } + + /* open correct device */ + device = fu_dfu_tool_get_default_device (self, error); + if (device == NULL) + return FALSE; + if (self->transfer_size > 0) + fu_dfu_device_set_transfer_size (device, self->transfer_size); + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + if (!fu_dfu_device_refresh (device, error)) + return FALSE; + + /* set up progress */ + g_signal_connect (device, "notify::status", + G_CALLBACK (fu_tool_action_changed_cb), self); + g_signal_connect (device, "notify::progress", + G_CALLBACK (fu_tool_action_changed_cb), self); + + /* APP -> DFU */ + if (!fu_device_has_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { + g_debug ("detaching"); + if (!fu_device_detach (FU_DEVICE (device), error)) + return FALSE; + if (!fu_dfu_device_wait_for_replug (self, device, + FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE, + error)) + return FALSE; + } + + /* transfer */ + target = fu_dfu_device_get_target_by_alt_name (device, + values[1], + NULL); + if (target == NULL) { + gchar *endptr; + guint64 tmp = g_ascii_strtoull (values[1], &endptr, 10); + if (tmp > 0xff || endptr[0] != '\0') { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Failed to parse alt-setting '%s'", + values[1]); + return FALSE; + } + target = fu_dfu_device_get_target_by_alt_setting (device, + (guint8) tmp, + error); + if (target == NULL) + return FALSE; + } + + /* do transfer */ + firmware = fu_dfuse_firmware_new (); + fu_dfu_firmware_set_vid (FU_DFU_FIRMWARE (firmware), fu_dfu_device_get_runtime_vid (device)); + fu_dfu_firmware_set_pid (FU_DFU_FIRMWARE (firmware), fu_dfu_device_get_runtime_pid (device)); + if (!fu_dfu_target_upload (target, firmware, flags, error)) + return FALSE; + + /* do host reset */ + if (!fu_device_attach (FU_DEVICE (device), error)) + return FALSE; + if (!fu_dfu_device_wait_for_replug (self, device, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE, error)) + return FALSE; + + /* save file */ + file = g_file_new_for_path (values[0]); + if (!fu_dfu_tool_write_firmware_to_file (firmware, file, error)) + return FALSE; + + /* print the new object */ + str_debug = fu_firmware_to_string (firmware); + g_debug ("DFU: %s", str_debug); + + /* success */ + g_print ("Successfully uploaded from device\n"); + return TRUE; +} + +static gboolean +fu_dfu_tool_read (FuDfuTool *self, gchar **values, GError **error) +{ + FuDfuTargetTransferFlags flags = DFU_TARGET_TRANSFER_FLAG_NONE; + g_autofree gchar *str_debug = NULL; + g_autoptr(FuDfuDevice) device = NULL; + g_autoptr(FuFirmware) firmware = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; + g_autoptr(GFile) file = NULL; + + /* check args */ + if (g_strv_length (values) != 1) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Invalid arguments, expected FILENAME"); + return FALSE; + } + + /* open correct device */ + device = fu_dfu_tool_get_default_device (self, error); + if (device == NULL) + return FALSE; + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + if (!fu_dfu_device_refresh (device, error)) + return FALSE; + + /* APP -> DFU */ + if (!fu_device_has_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { + if (!fu_device_detach (FU_DEVICE (device), error)) + return FALSE; + if (!fu_dfu_device_wait_for_replug (self, device, + FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE, + error)) { + return FALSE; + } + } + + /* transfer */ + g_signal_connect (device, "notify::status", + G_CALLBACK (fu_tool_action_changed_cb), self); + g_signal_connect (device, "notify::progress", + G_CALLBACK (fu_tool_action_changed_cb), self); + firmware = fu_dfu_device_upload (device, flags, error); + if (firmware == NULL) + return FALSE; + + /* do host reset */ + if (!fu_device_attach (FU_DEVICE (device), error)) + return FALSE; + if (!fu_dfu_device_wait_for_replug (self, device, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE, error)) + return FALSE; + + /* save file */ + file = g_file_new_for_path (values[0]); + if (!fu_dfu_tool_write_firmware_to_file (firmware, file, error)) + return FALSE; + + /* print the new object */ + str_debug = fu_firmware_to_string (firmware); + g_debug ("DFU: %s", str_debug); + + /* success */ + g_print ("successfully uploaded from device\n"); + return TRUE; +} + +static gboolean +fu_dfu_tool_write_alt (FuDfuTool *self, gchar **values, GError **error) +{ + FuDfuTargetTransferFlags flags = DFU_TARGET_TRANSFER_FLAG_VERIFY; + g_autofree gchar *str_debug = NULL; + g_autoptr(FuDfuDevice) device = NULL; + g_autoptr(FuFirmware) firmware = NULL; + g_autoptr(FuFirmwareImage) image = NULL; + g_autoptr(FuDfuTarget) target = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; + g_autoptr(GFile) file = NULL; + + /* check args */ + if (g_strv_length (values) < 2) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Invalid arguments, expected " + "FILENAME DEVICE-ALT-NAME|DEVICE-ALT-ID " + "[IMAGE-ALT-NAME|IMAGE-ALT-ID]"); + return FALSE; + } + + /* open file */ + firmware = fu_dfuse_firmware_new (); + file = g_file_new_for_path (values[0]); + if (!fu_dfu_tool_parse_firmware_from_file (firmware, file, + FWUPD_INSTALL_FLAG_NONE, + error)) + return FALSE; + + /* open correct device */ + device = fu_dfu_tool_get_default_device (self, error); + if (device == NULL) + return FALSE; + if (self->transfer_size > 0) + fu_dfu_device_set_transfer_size (device, self->transfer_size); + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + if (!fu_dfu_device_refresh (device, error)) + return FALSE; + + /* set up progress */ + g_signal_connect (device, "notify::status", + G_CALLBACK (fu_tool_action_changed_cb), self); + g_signal_connect (device, "notify::progress", + G_CALLBACK (fu_tool_action_changed_cb), self); + + /* APP -> DFU */ + if (!fu_device_has_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { + g_debug ("detaching"); + if (!fu_device_detach (FU_DEVICE (device), error)) + return FALSE; + if (!fu_dfu_device_wait_for_replug (self, device, 5000, error)) + return FALSE; + } + + /* print the new object */ + str_debug = fu_firmware_to_string (firmware); + g_debug ("DFU: %s", str_debug); + + /* get correct target on device */ + target = fu_dfu_device_get_target_by_alt_name (device, values[1], NULL); + if (target == NULL) { + gchar *endptr; + guint64 tmp = g_ascii_strtoull (values[1], &endptr, 10); + if (tmp > 0xff || endptr[0] != '\0') { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Failed to parse alt-setting '%s'", + values[1]); + return FALSE; + } + target = fu_dfu_device_get_target_by_alt_setting (device, + (guint8) tmp, + error); + if (target == NULL) + return FALSE; + } + + /* allow overriding the firmware alt-setting */ + if (g_strv_length (values) > 2) { + image = fu_firmware_get_image_by_id (firmware, values[2], NULL); + if (image == NULL) { + gchar *endptr; + guint64 tmp = g_ascii_strtoull (values[2], &endptr, 10); + if (tmp > 0xff || endptr[0] != '\0') { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Failed to parse image alt-setting '%s'", + values[2]); + return FALSE; + } + image = fu_firmware_get_image_by_idx (firmware, tmp, error); + if (image == NULL) + return FALSE; + } + } else { + g_print ("WARNING: Using default firmware image\n"); + image = fu_firmware_get_image_default (firmware, error); + if (image == NULL) + return FALSE; + } + + /* transfer */ + if (!fu_dfu_target_download (target, image, flags, error)) + return FALSE; + + /* do host reset */ + if (!fu_device_attach (FU_DEVICE (device), error)) + return FALSE; + if (!fu_dfu_device_wait_for_replug (self, device, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE, error)) + return FALSE; + + /* success */ + g_print ("Successfully downloaded to device\n"); + return TRUE; +} + +static gboolean +fu_dfu_tool_write (FuDfuTool *self, gchar **values, GError **error) +{ + FwupdInstallFlags flags = FWUPD_INSTALL_FLAG_NONE; + g_autoptr(FuDfuDevice) device = NULL; + g_autoptr(GBytes) fw = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; + + /* check args */ + if (g_strv_length (values) < 1) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Invalid arguments, expected FILENAME"); + return FALSE; + } + + /* open file */ + fw = fu_common_get_contents_bytes (values[0], error); + if (fw == NULL) + return FALSE; + + /* open correct device */ + device = fu_dfu_tool_get_default_device (self, error); + if (device == NULL) + return FALSE; + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + if (!fu_dfu_device_refresh (device, error)) + return FALSE; + + /* APP -> DFU */ + if (!fu_device_has_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { + if (!fu_device_detach (FU_DEVICE (device), error)) + return FALSE; + if (!fu_dfu_device_wait_for_replug (self, device, + fu_device_get_remove_delay (FU_DEVICE (device)), + error)) + return FALSE; + } + + /* allow wildcards */ + if (self->force) { + flags |= FWUPD_INSTALL_FLAG_IGNORE_VID_PID; + flags |= FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM; + } + + /* transfer */ + g_signal_connect (device, "notify::status", + G_CALLBACK (fu_tool_action_changed_cb), self); + g_signal_connect (device, "notify::progress", + G_CALLBACK (fu_tool_action_changed_cb), self); + if (!fu_device_write_firmware (FU_DEVICE (device), fw, flags, error)) + return FALSE; + + /* do host reset */ + if (!fu_device_attach (FU_DEVICE (device), error)) + return FALSE; + + if (fu_dfu_device_has_attribute (device, FU_DFU_DEVICE_ATTR_MANIFEST_TOL)) { + if (!fu_dfu_device_wait_for_replug (self, device, fu_device_get_remove_delay (FU_DEVICE (device)), error)) + return FALSE; + } + + /* success */ + g_print ("%u bytes successfully downloaded to device\n", + (guint) g_bytes_get_size (fw)); + return TRUE; +} + +#ifdef HAVE_GIO_UNIX +static gboolean +fu_dfu_tool_sigint_cb (gpointer user_data) +{ + FuDfuTool *self = (FuDfuTool *) user_data; + g_debug ("Handling SIGINT"); + g_cancellable_cancel (self->cancellable); + return FALSE; +} +#endif + +int +main (int argc, char *argv[]) +{ + gboolean ret; + gboolean verbose = FALSE; + gboolean version = FALSE; + g_autofree gchar *cmd_descriptions = NULL; + g_autoptr(FuDfuTool) self = g_new0 (FuDfuTool, 1); + g_autoptr(GError) error = NULL; + g_autoptr(GOptionContext) context = NULL; + const GOptionEntry options[] = { + { "version", '\0', 0, G_OPTION_ARG_NONE, &version, + _("Print the version number"), NULL }, + { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, + _("Print verbose debug statements"), NULL }, + { "device", 'd', 0, G_OPTION_ARG_STRING, &self->device_vid_pid, + _("Specify Vendor/Product ID(s) of DFU device"), _("VID:PID") }, + { "transfer-size", 't', 0, G_OPTION_ARG_STRING, &self->transfer_size, + _("Specify the number of bytes per USB transfer"), _("BYTES") }, + { "force", '\0', 0, G_OPTION_ARG_NONE, &self->force, + _("Force the action ignoring all warnings"), NULL }, + { NULL} + }; + + setlocale (LC_ALL, ""); + + bindtextdomain (GETTEXT_PACKAGE, FWUPD_LOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + /* add commands */ + self->cmd_array = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_dfu_tool_item_free); + fu_dfu_tool_add (self->cmd_array, + "read", + /* TRANSLATORS: command argument: uppercase, spaces->dashes */ + _("FILENAME"), + /* TRANSLATORS: command description */ + _("Read firmware from device into a file"), + fu_dfu_tool_read); + fu_dfu_tool_add (self->cmd_array, + "read-alt", + /* TRANSLATORS: command argument: uppercase, spaces->dashes */ + _("FILENAME DEVICE-ALT-NAME|DEVICE-ALT-ID"), + /* TRANSLATORS: command description */ + _("Read firmware from one partition into a file"), + fu_dfu_tool_read_alt); + fu_dfu_tool_add (self->cmd_array, + "write", + NULL, + /* TRANSLATORS: command description */ + _("Write firmware from file into device"), + fu_dfu_tool_write); + fu_dfu_tool_add (self->cmd_array, + "write-alt", + /* TRANSLATORS: command argument: uppercase, spaces->dashes */ + _("FILENAME DEVICE-ALT-NAME|DEVICE-ALT-ID [IMAGE-ALT-NAME|IMAGE-ALT-ID]"), + /* TRANSLATORS: command description */ + _("Write firmware from file into one partition"), + fu_dfu_tool_write_alt); + fu_dfu_tool_add (self->cmd_array, + "replace-data", + NULL, + /* TRANSLATORS: command description */ + _("Replace data in an existing firmware file"), + fu_dfu_tool_replace_data); + + /* use quirks */ + self->quirks = fu_quirks_new (); + if (!fu_quirks_load (self->quirks, FU_QUIRKS_LOAD_FLAG_NONE, &error)) { + /* TRANSLATORS: quirks are device-specific workarounds */ + g_print ("%s: %s\n", _("Failed to load quirks"), error->message); + return EXIT_FAILURE; + } + + /* do stuff on ctrl+c */ + self->cancellable = g_cancellable_new (); +#ifdef HAVE_GIO_UNIX + g_unix_signal_add_full (G_PRIORITY_DEFAULT, + SIGINT, + fu_dfu_tool_sigint_cb, + self, + NULL); +#endif + + /* sort by command name */ + g_ptr_array_sort (self->cmd_array, + (GCompareFunc) fu_dfu_tool_sort_command_name_cb); + + /* get a list of the commands */ + context = g_option_context_new (NULL); + cmd_descriptions = fu_dfu_tool_get_descriptions (self->cmd_array); + g_option_context_set_summary (context, cmd_descriptions); + + /* TRANSLATORS: DFU stands for device firmware update */ + g_set_application_name (_("DFU Utility")); + g_option_context_add_main_entries (context, options, NULL); + ret = g_option_context_parse (context, &argc, &argv, &error); + if (!ret) { + /* TRANSLATORS: the user didn't read the man page */ + g_print ("%s: %s\n", _("Failed to parse arguments"), error->message); + return EXIT_FAILURE; + } + + /* set verbose? */ + if (verbose) + g_setenv ("G_MESSAGES_DEBUG", "all", FALSE); + + /* version */ + if (version) { + g_print ("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION); + return EXIT_SUCCESS; + } + + /* run the specified command */ + ret = fu_dfu_tool_run (self, argv[1], (gchar**) &argv[2], &error); + if (!ret) { + if (g_error_matches (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL)) { + g_autofree gchar *tmp = NULL; + tmp = g_option_context_get_help (context, TRUE, NULL); + g_print ("%s\n\n%s", error->message, tmp); + } else { + g_print ("%s\n", error->message); + } + return EXIT_FAILURE; + } + + /* success/ */ + return EXIT_SUCCESS; +} diff -Nru fwupd-1.4.5/plugins/dfu/fu-dfu-tool.h2m fwupd-1.5.8/plugins/dfu/fu-dfu-tool.h2m --- fwupd-1.4.5/plugins/dfu/fu-dfu-tool.h2m 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/fu-dfu-tool.h2m 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,41 @@ +[DESCRIPTION] +.PP +This manual page documents briefly the \fBdfu-tool\fR command. +.PP +\fBdfu-tool\fR allows a user to write various kinds of +firmware onto devices supporting the USB Device Firmware Upgrade protocol. +This tool can be used to switch the device from the normal runtime mode +to `DFU mode' which allows the user to read and write firmware. +Either the whole device can be written in one operation, or individual +`targets' can be specified with the alternative name or number. +.PP +All synchronous actions can be safely cancelled and on failure will return +errors with both a type and a full textual description. +libdfu supports DFU 1.0, DFU 1.1 and the ST DfuSe vendor extension, and +handles many device `quirks' necessary for the real-world implementations +of DFU\&. +.PP +Additionally \fBdfu-tool\fR can be used to convert firmware +from various different formats, or to modify details about the elements, +images and metadata contained inside the firmware file. +For example, you can easily convert DFU 1.1 firmware into the +vendor-specific DfuSe format, convert a Intel HEX file into a raw file +padded to a specific size, or add new copyright and licensing information +to an existing file. +Fields such as the vendor and product IDs can be changed, and the firmware +elements can be encrypted and decrypted using various different methods. +Merging two DfuSe files together is also possible, although specifying +different alt-setting numbers before merging is a good idea to avoid +confusion. +.PP +Although \fBdfu-tool\fR tries to provide a large number of +easy-to-use commands, it may only be possible to do certain operations +using the libdfu library directly. +This is easier than it sounds, as the library is built with GObject +Introspection support making it usable in many languages such as C, +Javascript and Python. +Furthermore, using the library is a good idea if you want to perform +multiple operations on large firmware files, for instance, +converting from an Intel HEX file, padding to a certain size, setting +vendor and adding licensing information and then saving to a remote +location. diff -Nru fwupd-1.4.5/plugins/dfu/fu-plugin-dfu.c fwupd-1.5.8/plugins/dfu/fu-plugin-dfu.c --- fwupd-1.4.5/plugins/dfu/fu-plugin-dfu.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/fu-plugin-dfu.c 2021-03-31 20:08:32.000000000 +0000 @@ -7,13 +7,15 @@ #include "config.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" -#include "dfu-device.h" +#include "fu-dfu-device.h" void fu_plugin_init (FuPlugin *plugin) { fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); - fu_plugin_set_device_gtype (plugin, DFU_TYPE_DEVICE); + fu_plugin_set_device_gtype (plugin, FU_TYPE_DFU_DEVICE); + fu_plugin_add_possible_quirk_key (plugin, "DfuAltName"); + fu_plugin_add_possible_quirk_key (plugin, "DfuForceTimeout"); + fu_plugin_add_possible_quirk_key (plugin, "DfuForceVersion"); } Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/dfu/fuzzing/example.dfu and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/dfu/fuzzing/example.dfu differ Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/dfu/fuzzing/example.dfuse and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/dfu/fuzzing/example.dfuse differ Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/dfu/fuzzing/metadata.dfu and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/dfu/fuzzing/metadata.dfu differ Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/dfu/fuzzing/metadata-multiple.dfu and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/dfu/fuzzing/metadata-multiple.dfu differ diff -Nru fwupd-1.4.5/plugins/dfu/fuzzing.md fwupd-1.5.8/plugins/dfu/fuzzing.md --- fwupd-1.4.5/plugins/dfu/fuzzing.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/fuzzing.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -Fuzzing -======= - - CC=afl-gcc meson --default-library=static ../ - AFL_HARDEN=1 ninja - afl-fuzz -m 300 -i fuzzing -o findings ./plugins/dfu/dfu-tool --force dump @@ diff -Nru fwupd-1.4.5/plugins/dfu/meson.build fwupd-1.5.8/plugins/dfu/meson.build --- fwupd-1.4.5/plugins/dfu/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,4 @@ +if get_option('gusb') cargs = ['-DG_LOG_DOMAIN="FuPluginDfu"'] install_data(['dfu.quirk'], @@ -8,22 +9,17 @@ 'dfu', fu_hash, sources : [ - 'dfu-common.c', - 'dfu-device.c', - 'dfu-element.c', - 'dfu-firmware.c', - 'dfu-format-dfu.c', - 'dfu-format-dfuse.c', - 'dfu-format-raw.c', - 'dfu-image.c', - 'dfu-sector.c', - 'dfu-target.c', - 'dfu-target-stm.c', - 'dfu-target-avr.c', + 'fu-dfu-common.c', + 'fu-dfu-device.c', + 'fu-dfu-sector.c', + 'fu-dfu-target.c', + 'fu-dfu-target-stm.c', + 'fu-dfu-target-avr.c', ], dependencies : [ giounix, libm, + libxmlb, gusb, gudev, ], @@ -62,11 +58,11 @@ ], ) -dfu_tool = executable( +fu_dfu_tool = executable( 'dfu-tool', fu_hash, sources : [ - 'dfu-tool.c', + 'fu-dfu-tool.c', ], include_directories : [ root_incdir, @@ -92,9 +88,9 @@ if get_option('man') help2man = find_program('help2man') - extra = join_paths(meson.current_source_dir(), 'dfu-tool.h2m') + extra = join_paths(meson.current_source_dir(), 'fu-dfu-tool.h2m') custom_target('dfu-tool-man', - input : dfu_tool, + input : fu_dfu_tool, output : 'dfu-tool.1', command : [ help2man, '@INPUT@', @@ -111,13 +107,14 @@ endif if get_option('tests') - testdatadir = join_paths(meson.current_source_dir(), 'tests') - cargs += '-DTESTDATADIR="' + testdatadir + '"' + testdatadirs = environment() + testdatadirs.set('G_TEST_SRCDIR', meson.current_source_dir()) + testdatadirs.set('G_TEST_BUILDDIR', meson.current_build_dir()) e = executable( - 'dfu-self-test', + 'fu-dfu-self-test', fu_hash, sources : [ - 'dfu-self-test.c' + 'fu-dfu-self-test.c' ], include_directories : [ root_incdir, @@ -136,9 +133,11 @@ fwupd, fwupdplugin, ], - c_args : cargs + install : true, + install_dir : installed_test_bindir, ) - test('dfu-self-test', e) + test('fu-dfu-self-test', e, env : testdatadirs) # added to installed-tests endif plugindfu_incdir = include_directories('.') +endif diff -Nru fwupd-1.4.5/plugins/dfu/README.md fwupd-1.5.8/plugins/dfu/README.md --- fwupd-1.4.5/plugins/dfu/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -27,6 +27,16 @@ * `USB\VID_273F&PID_1003` * `USB\VID_273F` +Update Behavior +--------------- + +A DFU device usually presents in runtime mode (with optional DFU runtime), but +on detach re-enumerates with an additional required DFU descriptor. On attach +the device again re-enumerates back to the runtime mode. + +For this reason the `REPLUG_MATCH_GUID` internal device flag is used so that +the bootloader and runtime modes are treated as the same device. + Vendor ID Security ------------------ @@ -41,3 +51,8 @@ |`DfuFlags` | Optional quirks for a DFU device which doesn't follow the DFU 1.0 or 1.1 specification | 1.0.1| |`DfuForceVersion` | Forces a specific DFU version for the hardware device. This is required if the device does not set, or sets incorrectly, items in the DFU functional descriptor. |1.0.1| |`DfuForceTimeout` | Forces a specific device timeout, in ms | 1.4.0 | +|`DfuForceTransferSize` | Forces a target transfer size, in bytes | 1.5.6 | + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/dfu/tests/dev_VRBRAIN.dfu and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/dfu/tests/dev_VRBRAIN.dfu differ diff -Nru fwupd-1.4.5/plugins/dfu/tests/example.bin fwupd-1.5.8/plugins/dfu/tests/example.bin --- fwupd-1.4.5/plugins/dfu/tests/example.bin 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu/tests/example.bin 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -hello world Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/dfu/tests/example.dfu and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/dfu/tests/example.dfu differ Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/dfu/tests/example.xdfu and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/dfu/tests/example.xdfu differ Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/dfu/tests/kiibohd.dfu.bin and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/dfu/tests/kiibohd.dfu.bin differ Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/dfu/tests/metadata.dfu and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/dfu/tests/metadata.dfu differ diff -Nru fwupd-1.4.5/plugins/dfu-csr/data/lsusb.txt fwupd-1.5.8/plugins/dfu-csr/data/lsusb.txt --- fwupd-1.4.5/plugins/dfu-csr/data/lsusb.txt 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu-csr/data/lsusb.txt 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,58 @@ +Bus 001 Device 040: ID 0a12:1337 Cambridge Silicon Radio, Ltd +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x0a12 Cambridge Silicon Radio, Ltd + idProduct 0x1337 + bcdDevice 25.20 + iManufacturer 0 + iProduct 2 AIAIAI H05 in + iSerial 3 ABCDEF0123456789 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 34 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 500mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 3 Human Interface Device + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 0 + HID Device Descriptor: + bLength 9 + bDescriptorType 33 + bcdHID 1.00 + bCountryCode 0 Not supported + bNumDescriptors 1 + bDescriptorType 34 Report + wDescriptorLength 40 + Report Descriptors: + ** UNAVAILABLE ** + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 +Device Status: 0x0000 + (Bus Powered) Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/dfu-csr/data/upgrade.tdc.gz and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/dfu-csr/data/upgrade.tdc.gz differ diff -Nru fwupd-1.4.5/plugins/dfu-csr/dfu-csr.quirk fwupd-1.5.8/plugins/dfu-csr/dfu-csr.quirk --- fwupd-1.4.5/plugins/dfu-csr/dfu-csr.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu-csr/dfu-csr.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,15 @@ +[USB\VID_0A12&PID_1337] +Plugin = dfu_csr +Name = H05 +Summary = Bluetooth Headphones +Icon = audio-headphones +Vendor = AIAIAI +[USB\VID_0A12&PID_1337&REV_2520] +Version = 1.2 + +[USB\VID_0A12&PID_4004] +Plugin = dfu_csr +Name = H60 +Summary = Bluetooth Headphones +Icon = audio-headphones +Vendor = AIAIAI diff -Nru fwupd-1.4.5/plugins/dfu-csr/fu-dfu-csr-device.c fwupd-1.5.8/plugins/dfu-csr/fu-dfu-csr-device.c --- fwupd-1.4.5/plugins/dfu-csr/fu-dfu-csr-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu-csr/fu-dfu-csr-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,451 @@ +/* + * Copyright (C) 2017 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-chunk.h" +#include "fu-dfu-csr-device.h" +#include "fu-dfu-firmware.h" +#include "fu-dfu-common.h" + +/** + * FU_DFU_CSR_DEVICE_QUIRK_FLAG_REQUIRE_DELAY: + * + * Respect the write timeout value when performing actions. This is sometimes + * set to a huge amount of time, and so is not used by default. + * + * Since: 1.0.3 + */ +#define FU_DFU_CSR_DEVICE_FLAG_REQUIRE_DELAY "require-delay" + +typedef enum { + FU_DFU_CSR_DEVICE_QUIRK_NONE = 0, + FU_DFU_CSR_DEVICE_QUIRK_REQUIRE_DELAY = (1 << 0), + FU_DFU_CSR_DEVICE_QUIRK_LAST +} FuDfuCsrDeviceQuirks; + +struct _FuDfuCsrDevice +{ + FuHidDevice parent_instance; + FuDfuCsrDeviceQuirks quirks; + FuDfuState dfu_state; + guint32 dnload_timeout; +}; + +G_DEFINE_TYPE (FuDfuCsrDevice, fu_dfu_csr_device, FU_TYPE_HID_DEVICE) + +#define FU_DFU_CSR_REPORT_ID_COMMAND 0x01 +#define FU_DFU_CSR_REPORT_ID_STATUS 0x02 +#define FU_DFU_CSR_REPORT_ID_CONTROL 0x03 + +#define FU_DFU_CSR_COMMAND_HEADER_SIZE 6 /* bytes */ +#define FU_DFU_CSR_COMMAND_UPGRADE 0x01 + +#define FU_DFU_CSR_STATUS_HEADER_SIZE 7 + +#define FU_DFU_CSR_CONTROL_HEADER_SIZE 2 /* bytes */ +#define FU_DFU_CSR_CONTROL_CLEAR_STATUS 0x04 +#define FU_DFU_CSR_CONTROL_RESET 0xff + +/* maximum firmware packet, including the command header */ +#define FU_DFU_CSR_PACKET_DATA_SIZE 1023 /* bytes */ + +#define FU_DFU_CSR_DEVICE_TIMEOUT 5000 /* ms */ + +static void +fu_dfu_csr_device_to_string (FuDevice *device, guint idt, GString *str) +{ + FuDfuCsrDevice *self = FU_DFU_CSR_DEVICE (device); + fu_common_string_append_kv (str, idt, "State", fu_dfu_state_to_string (self->dfu_state)); + fu_common_string_append_ku (str, idt, "DownloadTimeout", self->dnload_timeout); +} + +static gboolean +fu_dfu_csr_device_attach (FuDevice *device, GError **error) +{ + guint8 buf[] = { FU_DFU_CSR_REPORT_ID_CONTROL, FU_DFU_CSR_CONTROL_RESET }; + if (!fu_hid_device_set_report (FU_HID_DEVICE (device), + FU_DFU_CSR_REPORT_ID_CONTROL, + buf, sizeof(buf), + FU_DFU_CSR_DEVICE_TIMEOUT, + FU_HID_DEVICE_FLAG_IS_FEATURE, + error)) { + g_prefix_error (error, "failed to attach: "); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_dfu_csr_device_get_status (FuDfuCsrDevice *self, GError **error) +{ + guint8 buf[64] = {0}; + + /* hit hardware */ + if (!fu_hid_device_get_report (FU_HID_DEVICE (self), + FU_DFU_CSR_REPORT_ID_STATUS, + buf, sizeof(buf), + FU_DFU_CSR_DEVICE_TIMEOUT, + FU_HID_DEVICE_FLAG_ALLOW_TRUNC | + FU_HID_DEVICE_FLAG_IS_FEATURE, + error)) { + g_prefix_error (error, "failed to GetStatus: "); + return FALSE; + } + + /* check packet */ + if (buf[0] != FU_DFU_CSR_REPORT_ID_STATUS) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "GetStatus packet-id was %i expected %i", + buf[0], FU_DFU_CSR_REPORT_ID_STATUS); + return FALSE; + } + + self->dfu_state = buf[5]; + self->dnload_timeout = buf[2] + (((guint32) buf[3]) << 8) + (((guint32) buf[4]) << 16); + g_debug ("timeout=%" G_GUINT32_FORMAT, self->dnload_timeout); + g_debug ("state=%s", fu_dfu_state_to_string (self->dfu_state)); + g_debug ("status=%s", fu_dfu_status_to_string (buf[6])); + return TRUE; +} + + +static gboolean +fu_dfu_csr_device_clear_status (FuDfuCsrDevice *self, GError **error) +{ + guint8 buf[] = { FU_DFU_CSR_REPORT_ID_CONTROL, + FU_DFU_CSR_CONTROL_CLEAR_STATUS }; + + /* only clear the status if the state is error */ + if (!fu_dfu_csr_device_get_status (self, error)) + return FALSE; + if (self->dfu_state != FU_DFU_STATE_DFU_ERROR) + return TRUE; + + /* hit hardware */ + if (!fu_hid_device_set_report (FU_HID_DEVICE (self), + FU_DFU_CSR_REPORT_ID_CONTROL, + buf, sizeof(buf), + FU_DFU_CSR_DEVICE_TIMEOUT, + FU_HID_DEVICE_FLAG_IS_FEATURE, + error)) { + g_prefix_error (error, "failed to ClearStatus: "); + return FALSE; + } + + /* check the hardware again */ + return fu_dfu_csr_device_get_status (self, error); +} + +static GBytes * +fu_dfu_csr_device_upload_chunk (FuDfuCsrDevice *self, GError **error) +{ + guint16 data_sz; + guint8 buf[64] = {0}; + + /* hit hardware */ + if (!fu_hid_device_get_report (FU_HID_DEVICE (self), + FU_DFU_CSR_REPORT_ID_COMMAND, + buf, sizeof(buf), + FU_DFU_CSR_DEVICE_TIMEOUT, + FU_HID_DEVICE_FLAG_ALLOW_TRUNC | + FU_HID_DEVICE_FLAG_IS_FEATURE, + error)) { + g_prefix_error (error, "failed to ReadFirmware: "); + return NULL; + } + + /* check command byte */ + if (buf[0] != FU_DFU_CSR_REPORT_ID_COMMAND) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "wrong report ID %u", buf[0]); + return NULL; + } + + /* check the length */ + data_sz = fu_common_read_uint16 (&buf[1], G_LITTLE_ENDIAN); + if (data_sz + FU_DFU_CSR_COMMAND_HEADER_SIZE != (guint16) sizeof(buf)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "wrong data length %" G_GUINT16_FORMAT, + data_sz); + return NULL; + } + + /* return as bytes */ + return g_bytes_new (buf + FU_DFU_CSR_COMMAND_HEADER_SIZE, + sizeof(buf) - FU_DFU_CSR_COMMAND_HEADER_SIZE); +} + +static GBytes * +fu_dfu_csr_device_upload (FuDevice *device, GError **error) +{ + FuDfuCsrDevice *self = FU_DFU_CSR_DEVICE (device); + g_autoptr(GPtrArray) chunks = NULL; + guint32 total_sz = 0; + gsize done_sz = 0; + + /* notify UI */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_READ); + + chunks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref); + for (guint32 i = 0; i < 0x3ffffff; i++) { + g_autoptr(GBytes) chunk = NULL; + gsize chunk_sz; + + /* hit hardware */ + chunk = fu_dfu_csr_device_upload_chunk (self, error); + if (chunk == NULL) + return NULL; + chunk_sz = g_bytes_get_size (chunk); + + /* get the total size using the DFU_CSR header */ + if (i == 0 && chunk_sz >= 10) { + const guint8 *buf = g_bytes_get_data (chunk, NULL); + if (memcmp (buf, "DFU_CSR-dfu", 7) == 0) { + guint16 hdr_ver; + guint16 hdr_len; + if (!fu_common_read_uint16_safe (buf, chunk_sz, 8, + &hdr_ver, G_LITTLE_ENDIAN, + error)) + return NULL; + if (hdr_ver != 0x03) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "DFU_CSR header version is " + "invalid %" G_GUINT16_FORMAT, + hdr_ver); + return NULL; + } + if (!fu_common_read_uint32_safe (buf, chunk_sz, 10, + &total_sz, G_LITTLE_ENDIAN, + error)) + return NULL; + if (total_sz == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "DFU_CSR header data length " + "invalid %" G_GUINT32_FORMAT, + total_sz); + return NULL; + } + if (!fu_common_read_uint16_safe (buf, chunk_sz, 14, + &hdr_len, G_LITTLE_ENDIAN, + error)) + return NULL; + g_debug ("DFU_CSR header length: %" G_GUINT16_FORMAT, hdr_len); + } + } + + /* add to chunk array */ + done_sz += chunk_sz; + g_ptr_array_add (chunks, g_steal_pointer (&chunk)); + fu_device_set_progress_full (device, done_sz, (gsize) total_sz); + + /* we're done */ + if (chunk_sz < 64 - FU_DFU_CSR_COMMAND_HEADER_SIZE) + break; + } + + /* notify UI */ + return fu_dfu_utils_bytes_join_array (chunks); +} + +static gboolean +fu_dfu_csr_device_download_chunk (FuDfuCsrDevice *self, guint16 idx, GBytes *chunk, GError **error) +{ + const guint8 *chunk_data; + gsize chunk_sz = 0; + guint8 buf[FU_DFU_CSR_PACKET_DATA_SIZE] = {0}; + + /* too large? */ + chunk_data = g_bytes_get_data (chunk, &chunk_sz); + if (chunk_sz + FU_DFU_CSR_COMMAND_HEADER_SIZE > FU_DFU_CSR_PACKET_DATA_SIZE) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "packet was too large: %" G_GSIZE_FORMAT, chunk_sz); + return FALSE; + } + g_debug ("writing %" G_GSIZE_FORMAT " bytes of data", chunk_sz); + + /* create packet */ + buf[0] = FU_DFU_CSR_REPORT_ID_COMMAND; + buf[1] = FU_DFU_CSR_COMMAND_UPGRADE; + fu_common_write_uint16 (&buf[2], idx, G_LITTLE_ENDIAN); + fu_common_write_uint16 (&buf[4], chunk_sz, G_LITTLE_ENDIAN); + if (!fu_memcpy_safe (buf, sizeof(buf), FU_DFU_CSR_COMMAND_HEADER_SIZE, /* dst */ + chunk_data, chunk_sz, 0x0, /* src */ + chunk_sz, error)) + return FALSE; + + /* hit hardware */ + if (!fu_hid_device_set_report (FU_HID_DEVICE (self), + FU_DFU_CSR_REPORT_ID_COMMAND, + buf, sizeof(buf), + FU_DFU_CSR_DEVICE_TIMEOUT, + FU_HID_DEVICE_FLAG_IS_FEATURE, + error)) { + g_prefix_error (error, "failed to Upgrade: "); + return FALSE; + } + + /* wait for hardware */ + if (self->quirks & FU_DFU_CSR_DEVICE_QUIRK_REQUIRE_DELAY) { + g_debug ("sleeping for %ums", self->dnload_timeout); + g_usleep (self->dnload_timeout * 1000); + } + + /* get status */ + if (!fu_dfu_csr_device_get_status (self, error)) + return FALSE; + + /* is still busy */ + if (self->dfu_state == FU_DFU_STATE_DFU_DNBUSY) { + g_debug ("busy, so sleeping a bit longer"); + g_usleep (G_USEC_PER_SEC); + if (!fu_dfu_csr_device_get_status (self, error)) + return FALSE; + } + + /* not correct */ + if (self->dfu_state != FU_DFU_STATE_DFU_DNLOAD_IDLE && + self->dfu_state != FU_DFU_STATE_DFU_IDLE) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "device did not return to IDLE"); + return FALSE; + } + + /* success */ + return TRUE; +} + +static FuFirmware * +fu_dfu_csr_device_prepare_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuFirmware) firmware = fu_dfu_firmware_new (); + + /* parse the file */ + if (!fu_firmware_parse (firmware, fw, flags, error)) + return NULL; + if (g_getenv ("FWUPD_DFU_CSR_VERBOSE") != NULL) { + g_autofree gchar *fw_str = NULL; + fw_str = fu_firmware_to_string (firmware); + g_debug ("%s", fw_str); + } + + /* success */ + return g_steal_pointer (&firmware); +} + +static gboolean +fu_dfu_csr_device_download (FuDevice *device, + FuFirmware *firmware, + FwupdInstallFlags flags, + GError **error) +{ + FuDfuCsrDevice *self = FU_DFU_CSR_DEVICE (device); + guint16 idx; + g_autoptr(GBytes) blob_empty = NULL; + g_autoptr(GBytes) blob = NULL; + g_autoptr(GPtrArray) chunks = NULL; + + /* get default image */ + blob = fu_firmware_get_image_default_bytes (firmware, error); + if (blob == NULL) + return FALSE; + + /* notify UI */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + + /* create chunks */ + chunks = fu_chunk_array_new_from_bytes (blob, 0x0, 0x0, + FU_DFU_CSR_PACKET_DATA_SIZE - FU_DFU_CSR_COMMAND_HEADER_SIZE); + + /* send to hardware */ + for (idx = 0; idx < chunks->len; idx++) { + FuChunk *chk = g_ptr_array_index (chunks, idx); + g_autoptr(GBytes) blob_tmp = fu_chunk_get_bytes (chk); + + /* send packet */ + if (!fu_dfu_csr_device_download_chunk (self, idx, blob_tmp, error)) + return FALSE; + + /* update progress */ + fu_device_set_progress_full (device, + (gsize) idx, (gsize) chunks->len); + } + + /* all done */ + blob_empty = g_bytes_new (NULL, 0); + return fu_dfu_csr_device_download_chunk (self, idx, blob_empty, error); +} + +static gboolean +fu_dfu_csr_device_probe (FuDevice *device, GError **error) +{ + FuDfuCsrDevice *self = FU_DFU_CSR_DEVICE (device); + + /* FuUsbDevice->probe */ + if (!FU_DEVICE_CLASS (fu_dfu_csr_device_parent_class)->probe (device, error)) + return FALSE; + + /* proxy the quirk delay */ + if (fu_device_has_custom_flag (device, FU_DFU_CSR_DEVICE_FLAG_REQUIRE_DELAY)) + self->quirks = FU_DFU_CSR_DEVICE_QUIRK_REQUIRE_DELAY; + + /* hardcoded */ + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + + /* success */ + return TRUE; +} + +static gboolean +fu_dfu_csr_device_setup (FuDevice *device, GError **error) +{ + FuDfuCsrDevice *self = FU_DFU_CSR_DEVICE (device); + + if (!fu_dfu_csr_device_clear_status (self, error)) + return FALSE; + + /* success */ + return TRUE; +} + +static void +fu_dfu_csr_device_init (FuDfuCsrDevice *self) +{ + fu_device_add_protocol (FU_DEVICE (self), "com.qualcomm.dfu"); + fu_device_add_internal_flag (FU_DEVICE (self), FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID); +} + +static void +fu_dfu_csr_device_class_init (FuDfuCsrDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + klass_device->to_string = fu_dfu_csr_device_to_string; + klass_device->write_firmware = fu_dfu_csr_device_download; + klass_device->dump_firmware = fu_dfu_csr_device_upload; + klass_device->prepare_firmware = fu_dfu_csr_device_prepare_firmware; + klass_device->attach = fu_dfu_csr_device_attach; + klass_device->setup = fu_dfu_csr_device_setup; + klass_device->probe = fu_dfu_csr_device_probe; +} diff -Nru fwupd-1.4.5/plugins/dfu-csr/fu-dfu-csr-device.h fwupd-1.5.8/plugins/dfu-csr/fu-dfu-csr-device.h --- fwupd-1.4.5/plugins/dfu-csr/fu-dfu-csr-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu-csr/fu-dfu-csr-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2017 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-hid-device.h" +#include "fu-plugin.h" + +#define FU_TYPE_DFU_CSR_DEVICE (fu_dfu_csr_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuDfuCsrDevice, fu_dfu_csr_device, FU, DFU_CSR_DEVICE, FuHidDevice) diff -Nru fwupd-1.4.5/plugins/dfu-csr/fu-plugin-dfu-csr.c fwupd-1.5.8/plugins/dfu-csr/fu-plugin-dfu-csr.c --- fwupd-1.4.5/plugins/dfu-csr/fu-plugin-dfu-csr.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu-csr/fu-plugin-dfu-csr.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2017 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" + +#include "fu-dfu-csr-device.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_set_device_gtype (plugin, FU_TYPE_DFU_CSR_DEVICE); +} diff -Nru fwupd-1.4.5/plugins/dfu-csr/meson.build fwupd-1.5.8/plugins/dfu-csr/meson.build --- fwupd-1.4.5/plugins/dfu-csr/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu-csr/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,31 @@ +if get_option('gusb') +cargs = ['-DG_LOG_DOMAIN="FuPluginDfuCsr"'] + +install_data(['dfu-csr.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_dfu_csr', + fu_hash, + sources : [ + 'fu-dfu-csr-device.c', + 'fu-plugin-dfu-csr.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + plugindfu_incdir, + ], + install : true, + install_dir: plugin_dir, + c_args : cargs, + dependencies : [ + plugin_deps, + ], + link_with : [ + fwupdplugin, + dfu, + ], +) +endif diff -Nru fwupd-1.4.5/plugins/dfu-csr/README.md fwupd-1.5.8/plugins/dfu-csr/README.md --- fwupd-1.4.5/plugins/dfu-csr/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/dfu-csr/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,56 @@ +DFU CSR Support +=============== + +Introduction +------------ + +CSR is often called “driverless DFU” and is used only by BlueCore chips from +Cambridge Silicon Radio (now owned by Qualcomm). The driverless just means that +it's DFU like, and is routed over HID. + +CSR is a ODM that makes most of the Bluetooth audio chips in vendor hardware. +The hardware vendor can enable or disable features on the CSR microcontroller +depending on licensing options (for instance echo cancellation), and there’s +even a little virtual machine to do simple vendor-specific things. + +All the CSR chips are updatable in-field, and most vendors issue updates to fix +sound quality issues or to add support for new protocols or devices. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +DFU file format. + +This plugin supports the following protocol ID: + + * com.qualcomm.dfu + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_0A12&PID_1337&REV_2520` + * `USB\VID_0A12&PID_1337` + * `USB\VID_0A12` + +Update Behavior +--------------- + +A DFU device usually presents in runtime mode (or with no interfaces defined), +but if the user puts the device into bootloader mode using a physical button +it then enumerates with a HID descriptor. On attach the device returns to +runtime mode which *may* mean the device "goes away". + +For this reason the `REPLUG_MATCH_GUID` internal device flag is used so that +the bootloader and runtime modes are treated as the same device. + +Vendor ID Security +------------------ + +The vendor ID is set from the USB vendor, in this instance set to `USB:0x0A12` + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff -Nru fwupd-1.4.5/plugins/ebitdo/ebitdo.quirk fwupd-1.5.8/plugins/ebitdo/ebitdo.quirk --- fwupd-1.4.5/plugins/ebitdo/ebitdo.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/ebitdo/ebitdo.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,98 +1,98 @@ # bootloader -[DeviceInstanceId=USB\VID_0483&PID_5750] +[USB\VID_0483&PID_5750] Plugin = ebitdo Flags = is-bootloader -[DeviceInstanceId=USB\VID_2DC8&PID_5750] +[USB\VID_2DC8&PID_5750] Plugin = ebitdo Flags = is-bootloader InstallDuration = 120 -[DeviceInstanceId=USB\VID_0483&PID_5760] +[USB\VID_0483&PID_5760] Plugin = ebitdo Flags = is-bootloader,will-disappear InstallDuration = 120 # FC30 -[DeviceInstanceId=USB\VID_1235&PID_AB11] +[USB\VID_1235&PID_AB11] Plugin = ebitdo Flags = ~is-bootloader -[DeviceInstanceId=USB\VID_2DC8&PID_AB11] +[USB\VID_2DC8&PID_AB11] Plugin = ebitdo Flags = ~is-bootloader InstallDuration = 120 # NES30 -[DeviceInstanceId=USB\VID_1235&PID_AB12] +[USB\VID_1235&PID_AB12] Plugin = ebitdo Flags = ~is-bootloader -[DeviceInstanceId=USB\VID_2DC8&PID_AB12] +[USB\VID_2DC8&PID_AB12] Plugin = ebitdo Flags = ~is-bootloader InstallDuration = 120 # SFC30 -[DeviceInstanceId=USB\VID_1235&PID_AB21] +[USB\VID_1235&PID_AB21] Plugin = ebitdo Flags = ~is-bootloader -[DeviceInstanceId=USB\VID_2DC8&PID_AB21] +[USB\VID_2DC8&PID_AB21] Plugin = ebitdo Flags = ~is-bootloader InstallDuration = 120 # SNES30 -[DeviceInstanceId=USB\VID_1235&PID_AB20] +[USB\VID_1235&PID_AB20] Plugin = ebitdo Flags = ~is-bootloader -[DeviceInstanceId=USB\VID_2DC8&PID_AB20] +[USB\VID_2DC8&PID_AB20] Plugin = ebitdo Flags = ~is-bootloader InstallDuration = 120 # FC30PRO -[DeviceInstanceId=USB\VID_1002&PID_9000] +[USB\VID_1002&PID_9000] Plugin = ebitdo Flags = ~is-bootloader -[DeviceInstanceId=USB\VID_2DC8&PID_9000] +[USB\VID_2DC8&PID_9000] Plugin = ebitdo Flags = ~is-bootloader InstallDuration = 120 # NES30PRO -[DeviceInstanceId=USB\VID_2002&PID_9000] +[USB\VID_2002&PID_9000] Plugin = ebitdo Flags = will-disappear -[DeviceInstanceId=USB\VID_2DC8&PID_9001] +[USB\VID_2DC8&PID_9001] Plugin = ebitdo Flags = will-disappear InstallDuration = 120 # FC30_ARCADE -[DeviceInstanceId=USB\VID_8000&PID_1002] +[USB\VID_8000&PID_1002] Plugin = ebitdo Flags = ~is-bootloader -[DeviceInstanceId=USB\VID_2DC8&PID_1002] +[USB\VID_2DC8&PID_1002] Plugin = ebitdo Flags = ~is-bootloader InstallDuration = 120 # SF30 PRO/SN30 PRO ## Dinput mode (Start + B) -[DeviceInstanceId=USB\VID_2DC8&PID_6000] +[USB\VID_2DC8&PID_6000] Plugin = ebitdo Flags = will-disappear -[DeviceInstanceId=USB\VID_2DC8&PID_6001] +[USB\VID_2DC8&PID_6001] Plugin = ebitdo Flags = will-disappear InstallDuration = 120 # SN30 PRO+ ## Dinput mode (Start + B) -[DeviceInstanceId=USB\VID_2DC8&PID_6002] +[USB\VID_2DC8&PID_6002] Plugin = ebitdo Flags = will-disappear InstallDuration = 120 # M30 -[DeviceInstanceId=USB\VID_2DC8&PID_5006] +[USB\VID_2DC8&PID_5006] Plugin = ebitdo Flags = ~is-bootloader InstallDuration = 120 diff -Nru fwupd-1.4.5/plugins/ebitdo/fu-ebitdo-device.c fwupd-1.5.8/plugins/ebitdo/fu-ebitdo-device.c --- fwupd-1.4.5/plugins/ebitdo/fu-ebitdo-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/ebitdo/fu-ebitdo-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2017 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -236,7 +236,7 @@ fu_ebitdo_device_validate (FuEbitdoDevice *self, GError **error) { const gchar *ven; - const gchar *whitelist[] = { + const gchar *allowlist[] = { "8Bitdo", "SFC30", NULL }; @@ -245,7 +245,7 @@ if (fu_usb_device_get_vid (FU_USB_DEVICE (self)) == 0x2dc8) return TRUE; - /* verify the vendor prefix against a whitelist */ + /* verify the vendor prefix against a allowlist */ ven = fu_device_get_vendor (FU_DEVICE (self)); if (ven == NULL) { g_set_error (error, @@ -254,24 +254,28 @@ "could not check vendor descriptor: "); return FALSE; } - for (guint i = 0; whitelist[i] != NULL; i++) { - if (g_str_has_prefix (ven, whitelist[i])) + for (guint i = 0; allowlist[i] != NULL; i++) { + if (g_str_has_prefix (ven, allowlist[i])) return TRUE; } g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, - "vendor '%s' did not match whitelist, " + "vendor '%s' did not match allowlist, " "probably not a 8Bitdo device…", ven); return FALSE; } static gboolean -fu_ebitdo_device_open (FuUsbDevice *device, GError **error) +fu_ebitdo_device_open (FuDevice *device, GError **error) { - GUsbDevice *usb_device = fu_usb_device_get_dev (device); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); FuEbitdoDevice *self = FU_EBITDO_DEVICE (device); + /* FuUsbDevice->open */ + if (!FU_DEVICE_CLASS (fu_ebitdo_device_parent_class)->open (device, error)) + return FALSE; + /* open, then ensure this is actually 8Bitdo hardware */ if (!fu_ebitdo_device_validate (self, error)) return FALSE; @@ -437,7 +441,7 @@ FU_EBITDO_PKT_CMD_UPDATE_FIRMWARE_DATA, FU_EBITDO_PKT_CMD_FW_UPDATE_HEADER, buf, bufsz, error)) { - g_prefix_error (error, "failed to set up firmware header:"); + g_prefix_error (error, "failed to set up firmware header: "); return FALSE; } if (!fu_ebitdo_device_receive (self, NULL, 0, error)) { @@ -448,29 +452,32 @@ /* flash the firmware in 32 byte blocks */ chunks = fu_chunk_array_new_from_bytes (fw_payload, 0x0, 0x0, 32); for (guint i = 0; i < chunks->len; i++) { - FuChunk *chunk = g_ptr_array_index (chunks, i); + FuChunk *chk = g_ptr_array_index (chunks, i); if (g_getenv ("FWUPD_EBITDO_VERBOSE") != NULL) { g_debug ("writing %u bytes to 0x%04x of 0x%04x", - chunk->data_sz, chunk->address, chunk->data_sz); + fu_chunk_get_data_sz (chk), + fu_chunk_get_address (chk), + fu_chunk_get_data_sz (chk)); } if (!fu_ebitdo_device_send (self, FU_EBITDO_PKT_TYPE_USER_CMD, FU_EBITDO_PKT_CMD_UPDATE_FIRMWARE_DATA, FU_EBITDO_PKT_CMD_FW_UPDATE_DATA, - chunk->data, chunk->data_sz, + fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk), error)) { g_prefix_error (error, "failed to write firmware @0x%04x: ", - chunk->address); + fu_chunk_get_address (chk)); return FALSE; } if (!fu_ebitdo_device_receive (self, NULL, 0, error)) { g_prefix_error (error, "failed to get ACK for write firmware @0x%04x: ", - chunk->address); + fu_chunk_get_address (chk)); return FALSE; } - fu_device_set_progress_full (device, chunk->idx, chunks->len); + fu_device_set_progress_full (device, fu_chunk_get_idx (chk), chunks->len); } /* set the "encode id" which is likely a checksum, bluetooth pairing @@ -546,28 +553,28 @@ } static gboolean -fu_ebitdo_device_probe (FuUsbDevice *device, GError **error) +fu_ebitdo_device_probe (FuDevice *device, GError **error) { - FuEbitdoDevice *self = FU_EBITDO_DEVICE (device); + /* FuUsbDevice->probe */ + if (!FU_DEVICE_CLASS (fu_ebitdo_device_parent_class)->probe (device, error)) + return FALSE; /* allowed, but requires manual bootloader step */ - fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_UPDATABLE); - fu_device_set_remove_delay (FU_DEVICE (device), FU_DEVICE_REMOVE_DELAY_USER_REPLUG); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_set_remove_delay (device, FU_DEVICE_REMOVE_DELAY_USER_REPLUG); /* set name and vendor */ - fu_device_set_summary (FU_DEVICE (device), - "A redesigned classic game controller"); - fu_device_set_vendor (FU_DEVICE (device), "8Bitdo"); + fu_device_set_summary (device, "A redesigned classic game controller"); + fu_device_set_vendor (device, "8Bitdo"); /* add a hardcoded icon name */ - fu_device_add_icon (FU_DEVICE (device), "input-gaming"); + fu_device_add_icon (device, "input-gaming"); /* only the bootloader can do the update */ - if (!fu_device_has_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { - fu_device_add_counterpart_guid (FU_DEVICE (device), "USB\\VID_0483&PID_5750"); - fu_device_add_counterpart_guid (FU_DEVICE (device), "USB\\VID_2DC8&PID_5750"); - fu_device_add_flag (FU_DEVICE (device), - FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER); + if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { + fu_device_add_counterpart_guid (device, "USB\\VID_0483&PID_5750"); + fu_device_add_counterpart_guid (device, "USB\\VID_2DC8&PID_5750"); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER); } /* success */ @@ -581,7 +588,6 @@ GError **error) { g_autoptr(FuFirmware) firmware = fu_ebitdo_firmware_new (); - fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); if (!fu_firmware_parse (firmware, fw, flags, error)) return NULL; return g_steal_pointer (&firmware); @@ -590,19 +596,19 @@ static void fu_ebitdo_device_init (FuEbitdoDevice *self) { - fu_device_set_protocol (FU_DEVICE (self), "com.8bitdo"); + fu_device_add_protocol (FU_DEVICE (self), "com.8bitdo"); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_ADD_COUNTERPART_GUIDS); + fu_device_add_internal_flag (FU_DEVICE (self), FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID); } static void fu_ebitdo_device_class_init (FuEbitdoDeviceClass *klass) { FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); klass_device->write_firmware = fu_ebitdo_device_write_firmware; klass_device->setup = fu_ebitdo_device_setup; klass_device->attach = fu_ebitdo_device_attach; - klass_usb_device->open = fu_ebitdo_device_open; - klass_usb_device->probe = fu_ebitdo_device_probe; + klass_device->open = fu_ebitdo_device_open; + klass_device->probe = fu_ebitdo_device_probe; klass_device->prepare_firmware = fu_ebitdo_device_prepare_firmware; } diff -Nru fwupd-1.4.5/plugins/ebitdo/fu-ebitdo-firmware.c fwupd-1.5.8/plugins/ebitdo/fu-ebitdo-firmware.c --- fwupd-1.4.5/plugins/ebitdo/fu-ebitdo-firmware.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/ebitdo/fu-ebitdo-firmware.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,11 +1,12 @@ /* - * Copyright (C) 2016-2019 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" +#include "fu-common.h" #include "fu-ebitdo-firmware.h" struct _FuEbitdoFirmware { @@ -75,15 +76,25 @@ /* parse version */ version = g_strdup_printf ("%.2f", GUINT32_FROM_LE(hdr->version) / 100.f); fu_firmware_set_version (firmware, version); + fu_firmware_set_version_raw (firmware, GUINT32_FROM_LE(hdr->version)); /* add header */ - fw_hdr = g_bytes_new_from_bytes (fw, 0x0, sizeof(FuEbitdoFirmwareHeader)); + fw_hdr = fu_common_bytes_new_offset (fw, 0x0, + sizeof(FuEbitdoFirmwareHeader), + error); + if (fw_hdr == NULL) + return FALSE; fu_firmware_image_set_id (img_hdr, FU_FIRMWARE_IMAGE_ID_HEADER); fu_firmware_image_set_bytes (img_hdr, fw_hdr); fu_firmware_add_image (firmware, img_hdr); /* add payload */ - fw_payload = g_bytes_new_from_bytes (fw, sizeof(FuEbitdoFirmwareHeader), payload_len); + fw_payload = fu_common_bytes_new_offset (fw, + sizeof(FuEbitdoFirmwareHeader), + payload_len, + error); + if (fw_payload == NULL) + return FALSE; fu_firmware_image_set_id (img_payload, FU_FIRMWARE_IMAGE_ID_PAYLOAD); fu_firmware_image_set_addr (img_payload, GUINT32_FROM_LE(hdr->destination_addr)); fu_firmware_image_set_bytes (img_payload, fw_payload); diff -Nru fwupd-1.4.5/plugins/ebitdo/fu-ebitdo-firmware.h fwupd-1.5.8/plugins/ebitdo/fu-ebitdo-firmware.h --- fwupd-1.4.5/plugins/ebitdo/fu-ebitdo-firmware.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/ebitdo/fu-ebitdo-firmware.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2019 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/ebitdo/fu-plugin-ebitdo.c fwupd-1.5.8/plugins/ebitdo/fu-plugin-ebitdo.c --- fwupd-1.4.5/plugins/ebitdo/fu-plugin-ebitdo.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/ebitdo/fu-plugin-ebitdo.c 2021-03-31 20:08:32.000000000 +0000 @@ -9,7 +9,6 @@ #include "fu-ebitdo-device.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #include "fu-ebitdo-firmware.h" void @@ -17,5 +16,5 @@ { fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_set_device_gtype (plugin, FU_TYPE_EBITDO_DEVICE); - fu_plugin_add_firmware_gtype (plugin, "8bitdo", FU_TYPE_EBITDO_FIRMWARE); + fu_plugin_add_firmware_gtype (plugin, NULL, FU_TYPE_EBITDO_FIRMWARE); } diff -Nru fwupd-1.4.5/plugins/ebitdo/meson.build fwupd-1.5.8/plugins/ebitdo/meson.build --- fwupd-1.4.5/plugins/ebitdo/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/ebitdo/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,4 @@ +if get_option('gusb') cargs = ['-DG_LOG_DOMAIN="FuPluginEbitdo"'] install_data(['ebitdo.quirk'], @@ -10,7 +11,7 @@ 'fu-plugin-ebitdo.c', 'fu-ebitdo-common.c', 'fu-ebitdo-device.c', - 'fu-ebitdo-firmware.c', + 'fu-ebitdo-firmware.c', # fuzzing ], include_directories : [ root_incdir, @@ -28,3 +29,4 @@ plugin_deps, ], ) +endif diff -Nru fwupd-1.4.5/plugins/ebitdo/README.md fwupd-1.5.8/plugins/ebitdo/README.md --- fwupd-1.4.5/plugins/ebitdo/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/ebitdo/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -32,6 +32,16 @@ * `USB\VID_2DC8&PID_AB11` * `USB\VID_2DC8` +Update Behavior +--------------- + +The device usually presents in runtime mode, but on detach re-enumerates with a +different USB VID and PID in a bootloader mode. On attach the device again +re-enumerates back to the runtime mode. + +For this reason the `REPLUG_MATCH_GUID` internal device flag is used so that +the bootloader and runtime modes are treated as the same device. + Vendor ID Security ------------------ @@ -44,3 +54,7 @@ * `USB:0x1235` * `USB:0x2002` * `USB:0x8000` + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff -Nru fwupd-1.4.5/plugins/elantp/elantp.quirk fwupd-1.5.8/plugins/elantp/elantp.quirk --- fwupd-1.4.5/plugins/elantp/elantp.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/elantp/elantp.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,97 @@ +[HIDRAW\VEN_04F3] +Plugin = elantp +GType = FuElantpHidDevice + +# ThinkPad X1 Carbon Gen 9 +[6c87726f-b545-549e-840a-189422ea21d0] +Flags = elantp-recovery + +# Lenovo X1 Nano Gen1 +[4c20262a-aee0-5d6e-ba72-6d29b23fe350] +Flags = elantp-recovery + +# Lenovo ThinkPad X13 Yoga Gen 2 +[34874ca5-54f0-5a4f-9161-e03910d14b75] +Flags = elantp-recovery + +# Lenovo ThinkPad X13 Gen 2 - 20XHFVT007 +[e5319542-ca16-5d93-bd0f-2d25f547a846] +Flags = elantp-recovery + +# Lenovo ThinkPad X13 Gen 2 - 20XHFVT003 +[ea5ea62f-ec8d-5f5d-8231-0816c89d75d6] +Flags = elantp-recovery + +# Acer Aspire V3-372T +[513cde3d-d939-59bd-a634-5c1645ebb93b] +Flags = elantp-recovery + +# recovery device +[I2C\NAME_Synopsys-DesignWare-I2C-adapter] +Plugin = elantp +GType = FuElantpI2cDevice +ElantpI2cTargetAddress = 0x15 + +[ELANTP\ICTYPE_00] +ElantpIcPageCount = 0x200 +ElantpIapPassword = 0x1EA5 + +[ELANTP\ICTYPE_03] +ElantpIcPageCount = 0x300 +ElantpIapPassword = 0x1EA5 + +[ELANTP\ICTYPE_06] +ElantpIcPageCount = 0x200 +ElantpIapPassword = 0x1EA5 + +[ELANTP\ICTYPE_07] +ElantpIcPageCount = 0x300 +ElantpIapPassword = 0x1EA5 + +[ELANTP\ICTYPE_08] +ElantpIcPageCount = 0x200 +ElantpIapPassword = 0x1EA5 + +[ELANTP\ICTYPE_0A] +ElantpIcPageCount = 0x300 +ElantpIapPassword = 0xE15A + +[ELANTP\ICTYPE_0B] +ElantpIcPageCount = 0x300 +ElantpIapPassword = 0x1EA5 + +[ELANTP\ICTYPE_0C] +ElantpIcPageCount = 0x300 +ElantpIapPassword = 0x1EA5 + +[ELANTP\ICTYPE_0E] +ElantpIcPageCount = 0x280 +ElantpIapPassword = 0x1EA5 + +[ELANTP\ICTYPE_09] +ElantpIcPageCount = 0x300 +ElantpIapPassword = 0x1EA5 + +[ELANTP\ICTYPE_0D] +ElantpIcPageCount = 0x380 +ElantpIapPassword = 0x1EA5 + +[ELANTP\ICTYPE_10] +ElantpIcPageCount = 0x400 +ElantpIapPassword = 0x1EA5 + +[ELANTP\ICTYPE_11] +ElantpIcPageCount = 0x500 +ElantpIapPassword = 0x1EA5 + +[ELANTP\ICTYPE_13] +ElantpIcPageCount = 0x800 +ElantpIapPassword = 0x1EA5 + +[ELANTP\ICTYPE_14] +ElantpIcPageCount = 0x400 +ElantpIapPassword = 0x1EA5 + +[ELANTP\ICTYPE_15] +ElantpIcPageCount = 0x400 +ElantpIapPassword = 0x1EA5 diff -Nru fwupd-1.4.5/plugins/elantp/fu-elantp-common.c fwupd-1.5.8/plugins/elantp/fu-elantp-common.c --- fwupd-1.4.5/plugins/elantp/fu-elantp-common.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/elantp/fu-elantp-common.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-elantp-common.h" + +guint16 +fu_elantp_calc_checksum (const guint8 *data, gsize length) +{ + guint16 checksum = 0; + for (gsize i = 0; i < length; i += 2) + checksum += ((guint16) (data[i+1]) << 8) | (data[i]); + return checksum; +} diff -Nru fwupd-1.4.5/plugins/elantp/fu-elantp-common.h fwupd-1.5.8/plugins/elantp/fu-elantp-common.h --- fwupd-1.4.5/plugins/elantp/fu-elantp-common.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/elantp/fu-elantp-common.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#define ETP_CMD_GET_HID_DESCRIPTOR 0x0001 +#define ETP_CMD_GET_HARDWARE_ID 0x0100 +#define ETP_CMD_GET_MODULE_ID 0x0101 +#define ETP_CMD_I2C_FW_CHECKSUM 0x030F +#define ETP_CMD_I2C_FW_VERSION 0x0102 +#define ETP_CMD_I2C_IAP 0x0311 +#define ETP_CMD_I2C_IAP_CHECKSUM 0x0315 +#define ETP_CMD_I2C_IAP_CTRL 0x0310 +#define ETP_CMD_I2C_IAP_ICBODY 0x0110 +#define ETP_CMD_I2C_IAP_RESET 0x0314 +#define ETP_CMD_I2C_IAP_VERSION 0x0111 +#define ETP_CMD_I2C_IAP_VERSION_2 0x0110 +#define ETP_CMD_I2C_OSM_VERSION 0x0103 +#define ETP_CMD_I2C_GET_HID_ID 0x0100 +#define ETP_CMD_I2C_IAP_TYPE 0x0304 + +#define ETP_I2C_IAP_TYPE_REG 0x0040 + +#define ETP_I2C_ENABLE_REPORT 0x0800 + +#define ETP_I2C_IAP_RESET 0xF0F0 +#define ETP_I2C_MAIN_MODE_ON (1 << 9) + +#define ETP_I2C_IAP_REG_L 0x01 +#define ETP_I2C_IAP_REG_H 0x06 + +#define ETP_FW_IAP_INTF_ERR (1 << 4) +#define ETP_FW_IAP_PAGE_ERR (1 << 5) +#define ETP_FW_IAP_CHECK_PW (1 << 7) +#define ETP_FW_IAP_LAST_FIT (1 << 9) + + +#define ELANTP_DELAY_COMPLETE 1200 /* ms */ +#define ELANTP_DELAY_RESET 30 /* ms */ +#define ELANTP_DELAY_UNLOCK 100 /* ms */ +#define ELANTP_DELAY_WRITE_BLOCK 35 /* ms */ +#define ELANTP_DELAY_WRITE_BLOCK_512 50 /* ms */ + +guint16 fu_elantp_calc_checksum (const guint8 *data, + gsize length); diff -Nru fwupd-1.4.5/plugins/elantp/fu-elantp-firmware.c fwupd-1.5.8/plugins/elantp/fu-elantp-firmware.c --- fwupd-1.4.5/plugins/elantp/fu-elantp-firmware.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/elantp/fu-elantp-firmware.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-common.h" + +#include "fu-elantp-common.h" +#include "fu-elantp-firmware.h" + +struct _FuElantpFirmware { + FuFirmwareClass parent_instance; + guint16 module_id; + guint16 iap_addr; +}; + +G_DEFINE_TYPE (FuElantpFirmware, fu_elantp_firmware, FU_TYPE_FIRMWARE) + +/* firmware block update */ +#define ETP_IAP_START_ADDR_WRDS 0x0083 + +const guint8 elantp_signature[] = { 0xAA, 0x55, 0xCC, 0x33, 0xFF, 0xFF }; + +guint16 +fu_elantp_firmware_get_module_id (FuElantpFirmware *self) +{ + g_return_val_if_fail (FU_IS_ELANTP_FIRMWARE (self), 0); + return self->module_id; +} + +guint16 +fu_elantp_firmware_get_iap_addr (FuElantpFirmware *self) +{ + g_return_val_if_fail (FU_IS_ELANTP_FIRMWARE (self), 0); + return self->iap_addr; +} + +static void +fu_elantp_firmware_to_string (FuFirmware *firmware, guint idt, GString *str) +{ + FuElantpFirmware *self = FU_ELANTP_FIRMWARE (firmware); + fu_common_string_append_kx (str, idt, "IapAddr", self->iap_addr); + fu_common_string_append_kx (str, idt, "ModuleId", self->module_id); +} + +static gboolean +fu_elantp_firmware_parse (FuFirmware *firmware, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error) +{ + FuElantpFirmware *self = FU_ELANTP_FIRMWARE (firmware); + gsize bufsz = 0; + guint16 iap_addr_wrds; + guint16 module_id_wrds; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + g_autoptr(FuFirmwareImage) img = fu_firmware_image_new (fw); + + /* presumably in words */ + if (!fu_common_read_uint16_safe (buf, bufsz, ETP_IAP_START_ADDR_WRDS * 2, + &iap_addr_wrds, G_LITTLE_ENDIAN, error)) + return FALSE; + if (iap_addr_wrds < ETP_IAP_START_ADDR_WRDS || iap_addr_wrds > 0x7FFF) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "IAP address invalid: 0x%x", + iap_addr_wrds); + return FALSE; + } + self->iap_addr = iap_addr_wrds * 2; + + /* read module ID */ + if (!fu_common_read_uint16_safe (buf, bufsz, self->iap_addr, + &module_id_wrds, G_LITTLE_ENDIAN, error)) + return FALSE; + if (module_id_wrds > 0x7FFF) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "module ID address invalid: 0x%x", + module_id_wrds); + return FALSE; + } + if (!fu_common_read_uint16_safe (buf, bufsz, module_id_wrds * 2, + &self->module_id, G_LITTLE_ENDIAN, error)) + return FALSE; + + /* check signature */ + if ((flags & FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM) == 0) { + gsize offset = bufsz - sizeof(elantp_signature); + for (gsize i = 0; i < sizeof(elantp_signature); i++) { + guint8 tmp = 0x0; + if (!fu_common_read_uint8_safe (buf, bufsz, offset + i, &tmp, error)) + return FALSE; + if (tmp != elantp_signature[i]) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "signature[%u] invalid: got 0x%2x, expected 0x%02x", + (guint) i, tmp, elantp_signature[i]); + return FALSE; + } + } + } + + /* whole image */ + fu_firmware_add_image (firmware, img); + return TRUE; +} + +static gboolean +fu_elantp_firmware_build (FuFirmware *firmware, XbNode *n, GError **error) +{ + FuElantpFirmware *self = FU_ELANTP_FIRMWARE (firmware); + guint64 tmp; + + /* two simple properties */ + tmp = xb_node_query_text_as_uint (n, "module_id", NULL); + if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT16) + self->module_id = tmp; + tmp = xb_node_query_text_as_uint (n, "iap_addr", NULL); + if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT16) + self->iap_addr = tmp; + + /* success */ + return TRUE; +} + +static GBytes * +fu_elantp_firmware_write (FuFirmware *firmware, GError **error) +{ + FuElantpFirmware *self = FU_ELANTP_FIRMWARE (firmware); + g_autoptr(GByteArray) buf = g_byte_array_new (); + g_autoptr(GBytes) blob = NULL; + + /* only one image supported */ + blob = fu_firmware_get_image_default_bytes (firmware, error); + if (blob == NULL) + return NULL; + + /* lets build a simple firmware like this: + * ------ 0x0 + * HEADER (containing IAP offset and module ID) + * ------ ~0x10a + * DATA + * ------ + * SIGNATURE + * ------ + */ + fu_byte_array_set_size (buf, self->iap_addr + 0x2 + 0x2); + if (!fu_common_write_uint16_safe (buf->data, buf->len, + ETP_IAP_START_ADDR_WRDS * 2, + self->iap_addr / 2, + G_LITTLE_ENDIAN, error)) + return NULL; + if (!fu_common_write_uint16_safe (buf->data, buf->len, + self->iap_addr, + (self->iap_addr + 2) / 2, + G_LITTLE_ENDIAN, error)) + return NULL; + if (!fu_common_write_uint16_safe (buf->data, buf->len, + self->iap_addr + 0x2, + self->module_id, + G_LITTLE_ENDIAN, error)) + return NULL; + g_byte_array_append (buf, g_bytes_get_data (blob, NULL), g_bytes_get_size (blob)); + g_byte_array_append (buf, elantp_signature, sizeof(elantp_signature)); + return g_byte_array_free_to_bytes (g_steal_pointer (&buf)); +} + +static void +fu_elantp_firmware_init (FuElantpFirmware *self) +{ +} + +static void +fu_elantp_firmware_class_init (FuElantpFirmwareClass *klass) +{ + FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); + klass_firmware->parse = fu_elantp_firmware_parse; + klass_firmware->build = fu_elantp_firmware_build; + klass_firmware->write = fu_elantp_firmware_write; + klass_firmware->to_string = fu_elantp_firmware_to_string; +} + +FuFirmware * +fu_elantp_firmware_new (void) +{ + return FU_FIRMWARE (g_object_new (FU_TYPE_ELANTP_FIRMWARE, NULL)); +} diff -Nru fwupd-1.4.5/plugins/elantp/fu-elantp-firmware.h fwupd-1.5.8/plugins/elantp/fu-elantp-firmware.h --- fwupd-1.4.5/plugins/elantp/fu-elantp-firmware.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/elantp/fu-elantp-firmware.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-firmware.h" + +#define FU_TYPE_ELANTP_FIRMWARE (fu_elantp_firmware_get_type ()) +G_DECLARE_FINAL_TYPE (FuElantpFirmware, fu_elantp_firmware, FU, ELANTP_FIRMWARE, FuFirmware) + +FuFirmware *fu_elantp_firmware_new (void); +guint16 fu_elantp_firmware_get_module_id (FuElantpFirmware *self); +guint16 fu_elantp_firmware_get_iap_addr (FuElantpFirmware *self); diff -Nru fwupd-1.4.5/plugins/elantp/fu-elantp-hid-device.c fwupd-1.5.8/plugins/elantp/fu-elantp-hid-device.c --- fwupd-1.4.5/plugins/elantp/fu-elantp-hid-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/elantp/fu-elantp-hid-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,590 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include + +#include "fu-elantp-common.h" +#include "fu-elantp-firmware.h" +#include "fu-elantp-hid-device.h" + +#include "fu-chunk.h" + +struct _FuElantpHidDevice { + FuUdevDevice parent_instance; + guint16 ic_page_count; + guint16 iap_type; + guint16 iap_ctrl; + guint16 iap_password; + guint16 module_id; + guint16 fw_page_size; + guint8 pattern; +}; + +G_DEFINE_TYPE (FuElantpHidDevice, fu_elantp_hid_device, FU_TYPE_UDEV_DEVICE) + +static gboolean fu_elantp_hid_device_detach (FuDevice *device, GError **error); + +static void +fu_elantp_hid_device_to_string (FuDevice *device, guint idt, GString *str) +{ + FuElantpHidDevice *self = FU_ELANTP_HID_DEVICE (device); + fu_common_string_append_kx (str, idt, "ModuleId", self->module_id); + fu_common_string_append_kx (str, idt, "Pattern", self->pattern); + fu_common_string_append_kx (str, idt, "FwPageSize", self->fw_page_size); + fu_common_string_append_kx (str, idt, "IcPageCount", self->ic_page_count); + fu_common_string_append_kx (str, idt, "IapType", self->iap_type); + fu_common_string_append_kx (str, idt, "IapCtrl", self->iap_ctrl); +} + +static gboolean +fu_elantp_hid_device_probe (FuDevice *device, GError **error) +{ + /* FuUdevDevice->probe */ + if (!FU_DEVICE_CLASS (fu_elantp_hid_device_parent_class)->probe (device, error)) + return FALSE; + + /* check is valid */ + if (g_strcmp0 (fu_udev_device_get_subsystem (FU_UDEV_DEVICE (device)), "hidraw") != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "is not correct subsystem=%s, expected hidraw", + fu_udev_device_get_subsystem (FU_UDEV_DEVICE (device))); + return FALSE; + } + + /* i2c-hid */ + if (fu_udev_device_get_model (FU_UDEV_DEVICE (device)) < 0x3000 || + fu_udev_device_get_model (FU_UDEV_DEVICE (device)) >= 0x4000) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "not i2c-hid touchpad"); + return FALSE; + } + + /* set the physical ID */ + return fu_udev_device_set_physical_id (FU_UDEV_DEVICE (device), "hid", error); +} + +static gboolean +fu_elantp_hid_device_send_cmd (FuElantpHidDevice *self, + guint8 *tx, gsize txsz, + guint8 *rx, gsize rxsz, + GError **error) +{ + g_autofree guint8 *buf = NULL; + gsize bufsz = rxsz + 3; + + if (g_getenv ("FWUPD_ELANTP_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "SetReport", tx, txsz); + if (!fu_udev_device_ioctl (FU_UDEV_DEVICE (self), + HIDIOCSFEATURE(txsz), tx, + NULL, error)) + return FALSE; + if (rxsz == 0) + return TRUE; + + /* GetFeature */ + buf = g_malloc0 (bufsz); + buf[0] = tx[0]; /* report number */ + if (!fu_udev_device_ioctl (FU_UDEV_DEVICE (self), + HIDIOCGFEATURE(bufsz), buf, + NULL, error)) + return FALSE; + if (g_getenv ("FWUPD_ELANTP_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "GetReport", buf, bufsz); + + /* success */ + return fu_memcpy_safe (rx, rxsz, 0x0, /* dst */ + buf, bufsz, 0x3, /* src */ + rxsz, error); +} + +static gboolean +fu_elantp_hid_device_read_cmd (FuElantpHidDevice *self, guint16 reg, + guint8 *rx, gsize rxsz, GError **error) +{ + guint8 buf[5] = { 0x0d, 0x05, 0x03 }; + fu_common_write_uint16 (buf + 0x3, reg, G_LITTLE_ENDIAN); + return fu_elantp_hid_device_send_cmd (self, buf, sizeof(buf), rx, rxsz, error); +} + +static gint +fu_elantp_hid_device_write_cmd (FuElantpHidDevice *self, + guint16 reg, guint16 cmd, + GError **error) +{ + guint8 buf[5] = { 0x0d }; + fu_common_write_uint16 (buf + 0x1, reg, G_LITTLE_ENDIAN); + fu_common_write_uint16 (buf + 0x3, cmd, G_LITTLE_ENDIAN); + return fu_elantp_hid_device_send_cmd (self, buf, sizeof(buf), NULL, 0, error); +} + +static gboolean +fu_elantp_hid_device_ensure_iap_ctrl (FuElantpHidDevice *self, GError **error) +{ + guint8 buf[2] = { 0x0 }; + if (!fu_elantp_hid_device_read_cmd (self, ETP_CMD_I2C_IAP_CTRL, buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read IAPControl: "); + return FALSE; + } + self->iap_ctrl = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + + /* in bootloader mode? */ + if ((self->iap_ctrl & ETP_I2C_MAIN_MODE_ON) == 0) + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + else + fu_device_remove_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + + return TRUE; +} + +static gboolean +fu_elantp_hid_device_setup (FuDevice *device, GError **error) +{ + FuElantpHidDevice *self = FU_ELANTP_HID_DEVICE (device); + FuUdevDevice *udev_device = FU_UDEV_DEVICE (device); + guint16 fwver; + guint16 iap_ver; + guint16 tmp; + guint8 buf[2] = { 0x0 }; + guint8 ic_type; + g_autofree gchar *instance_id1 = NULL; + g_autofree gchar *instance_id2 = NULL; + g_autofree gchar *instance_id_ic_type = NULL; + g_autofree gchar *version_bl = NULL; + g_autofree gchar *version = NULL; + + /* get pattern */ + if (!fu_elantp_hid_device_read_cmd (self, + ETP_CMD_I2C_GET_HID_ID, + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read HID ID: "); + return FALSE; + } + tmp = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + self->pattern = tmp != 0xffff ? (tmp & 0xff00) >> 8 : 0; + + /* get current firmware version */ + if (!fu_elantp_hid_device_read_cmd (self, + ETP_CMD_I2C_FW_VERSION, + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read fw version: "); + return FALSE; + } + fwver = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + if (fwver == 0xFFFF || fwver == ETP_CMD_I2C_FW_VERSION) + fwver = 0; + version = fu_common_version_from_uint16 (fwver, FWUPD_VERSION_FORMAT_HEX); + fu_device_set_version (device, version); + + /* get IAP firmware version */ + if (!fu_elantp_hid_device_read_cmd (self, + self->pattern == 0 ? ETP_CMD_I2C_IAP_VERSION : ETP_CMD_I2C_IAP_VERSION_2, + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read bootloader version: "); + return FALSE; + } + if (self->pattern >= 1) { + iap_ver = buf[1]; + } else { + iap_ver = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + } + version_bl = fu_common_version_from_uint16 (iap_ver, FWUPD_VERSION_FORMAT_HEX); + fu_device_set_version_bootloader (device, version_bl); + + /* get module ID */ + if (!fu_elantp_hid_device_read_cmd (self, + ETP_CMD_GET_MODULE_ID, + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read module ID: "); + return FALSE; + } + self->module_id = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + + /* define the extra instance IDs */ + instance_id1 = g_strdup_printf ("HIDRAW\\VEN_%04X&DEV_%04X&MOD_%04X", + fu_udev_device_get_vendor (udev_device), + fu_udev_device_get_model (udev_device), + self->module_id); + fu_device_add_instance_id (device, instance_id1); + + /* get OSM version */ + if (!fu_elantp_hid_device_read_cmd (self, ETP_CMD_I2C_OSM_VERSION, buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read OSM version: "); + return FALSE; + } + tmp = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + if (tmp == ETP_CMD_I2C_OSM_VERSION || tmp == 0xFFFF) { + if (!fu_elantp_hid_device_read_cmd (self, ETP_CMD_I2C_IAP_ICBODY, buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read IC body: "); + return FALSE; + } + ic_type = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN) & 0xFF; + } else { + ic_type = (tmp >> 8) & 0xFF; + } + instance_id_ic_type = g_strdup_printf ("ELANTP\\ICTYPE_%02X", ic_type); + fu_device_add_instance_id (device, instance_id_ic_type); + + /* define the extra instance IDs (ic_type + module_id) */ + instance_id2 = g_strdup_printf ("ELANTP\\ICTYPE_%02X&MOD_%04X", + ic_type, self->module_id); + fu_device_add_instance_id (device, instance_id2); + + /* no quirk entry */ + if (self->ic_page_count == 0x0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "no page count for ELANTP\\ICTYPE_%02X", + ic_type); + return FALSE; + } + + /* The ic_page_count is based on 64 bytes/page. */ + fu_device_set_firmware_size (device, (guint64) self->ic_page_count * (guint64) 64); + + /* is in bootloader mode */ + if (!fu_elantp_hid_device_ensure_iap_ctrl (self, error)) + return FALSE; + + /* success */ + return TRUE; +} + +static FuFirmware * +fu_elantp_hid_device_prepare_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + FuElantpHidDevice *self = FU_ELANTP_HID_DEVICE (device); + guint16 module_id; + g_autoptr(FuFirmware) firmware = fu_elantp_firmware_new (); + + /* check is compatible with hardware */ + if (!fu_firmware_parse (firmware, fw, flags, error)) + return NULL; + module_id = fu_elantp_firmware_get_module_id (FU_ELANTP_FIRMWARE (firmware)); + if (self->module_id != module_id) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "firmware incompatible, got 0x%04x, expected 0x%04x", + module_id, self->module_id); + return NULL; + } + + /* success */ + return g_steal_pointer (&firmware); +} + +static gboolean +fu_elantp_hid_device_write_firmware (FuDevice *device, + FuFirmware *firmware, + FwupdInstallFlags flags, + GError **error) +{ + FuElantpHidDevice *self = FU_ELANTP_HID_DEVICE (device); + FuElantpFirmware *firmware_elantp = FU_ELANTP_FIRMWARE (firmware); + gsize bufsz = 0; + guint16 checksum = 0; + guint16 checksum_device = 0; + guint16 iap_addr; + const guint8 *buf; + guint8 csum_buf[2] = { 0x0 }; + g_autoptr(GBytes) fw = NULL; + g_autoptr(GPtrArray) chunks = NULL; + + /* simple image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + + /* detach */ + if (!fu_elantp_hid_device_detach (device, error)) + return FALSE; + + /* write each block */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + buf = g_bytes_get_data (fw, &bufsz); + iap_addr = fu_elantp_firmware_get_iap_addr (firmware_elantp); + chunks = fu_chunk_array_new (buf + iap_addr, bufsz - iap_addr, 0x0, 0x0, self->fw_page_size); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + guint16 csum_tmp = fu_elantp_calc_checksum (fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk)); + gsize blksz = self->fw_page_size + 3; + g_autofree guint8 *blk = g_malloc0 (blksz); + + /* write block */ + blk[0] = 0x0B; /* report ID */ + if (!fu_memcpy_safe (blk, blksz, 0x1, /* dst */ + fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk), 0x0, /* src */ + fu_chunk_get_data_sz (chk), error)) + return FALSE; + fu_common_write_uint16 (blk + fu_chunk_get_data_sz (chk) + 1, + csum_tmp, G_LITTLE_ENDIAN); + + if (!fu_elantp_hid_device_send_cmd (self, blk, blksz, NULL, 0, error)) + return FALSE; + g_usleep (self->fw_page_size == 512 ? + ELANTP_DELAY_WRITE_BLOCK_512 * 1000 : + ELANTP_DELAY_WRITE_BLOCK * 1000); + + if (!fu_elantp_hid_device_ensure_iap_ctrl (self, error)) + return FALSE; + if (self->iap_ctrl & (ETP_FW_IAP_PAGE_ERR | ETP_FW_IAP_INTF_ERR)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "bootloader reports failed write: 0x%x", + self->iap_ctrl); + return FALSE; + } + + /* update progress */ + checksum += csum_tmp; + fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len); + } + + /* verify the written checksum */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_VERIFY); + if (!fu_elantp_hid_device_read_cmd (self, ETP_CMD_I2C_IAP_CHECKSUM, + csum_buf, sizeof(csum_buf), error)) + return FALSE; + if (!fu_common_read_uint16_safe (csum_buf, sizeof(csum_buf), 0x0, + &checksum_device, G_LITTLE_ENDIAN, error)) + return FALSE; + if (checksum != checksum_device) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "checksum failed 0x%04x != 0x%04x", + checksum, checksum_device); + return FALSE; + } + + /* wait for a reset */ + fu_device_set_progress (device, 0); + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + g_usleep (ELANTP_DELAY_COMPLETE * 1000); + return TRUE; +} + +static gboolean +fu_elantp_hid_device_detach (FuDevice *device, GError **error) +{ + FuElantpHidDevice *self = FU_ELANTP_HID_DEVICE (device); + guint16 iap_ver; + guint16 ic_type; + guint8 buf[2] = { 0x0 }; + guint16 tmp; + + /* sanity check */ + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { + g_debug ("in bootloader mode, reset IC"); + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + if (!fu_elantp_hid_device_write_cmd (self, + ETP_CMD_I2C_IAP_RESET, + ETP_I2C_IAP_RESET, + error)) + return FALSE; + g_usleep (ELANTP_DELAY_RESET * 1000); + } + + /* get OSM version */ + if (!fu_elantp_hid_device_read_cmd (self, ETP_CMD_I2C_OSM_VERSION, buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read OSM version: "); + return FALSE; + } + tmp = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + if (tmp == ETP_CMD_I2C_OSM_VERSION || tmp == 0xFFFF) { + if (!fu_elantp_hid_device_read_cmd (self, ETP_CMD_I2C_IAP_ICBODY, buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read IC body: "); + return FALSE; + } + ic_type = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN) & 0xFF; + } else { + ic_type = (tmp >> 8) & 0xFF; + } + + /* get IAP firmware version */ + if (!fu_elantp_hid_device_read_cmd (self, + self->pattern == 0 ? ETP_CMD_I2C_IAP_VERSION : ETP_CMD_I2C_IAP_VERSION_2, + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read bootloader version: "); + return FALSE; + } + if (self->pattern >= 1) { + iap_ver = buf[1]; + } else { + iap_ver = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + } + if (ic_type >= 0x10) { + if (iap_ver >= 1) { + /* set the IAP type, presumably some kind of ABI */ + if (iap_ver >= 2 && (ic_type == 0x14 || ic_type==0x15)) { + self->fw_page_size = 512; + } else { + self->fw_page_size = 128; + } + + if (!fu_elantp_hid_device_write_cmd (self, + ETP_CMD_I2C_IAP_TYPE, + self->fw_page_size / 2, + error)) + return FALSE; + if (!fu_elantp_hid_device_read_cmd (self, ETP_CMD_I2C_IAP_TYPE, + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read IAP type: "); + return FALSE; + } + self->iap_type = fu_common_read_uint16 (buf, G_LITTLE_ENDIAN); + if (self->iap_type != self->fw_page_size / 2) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to set IAP type"); + return FALSE; + } + + } + } + if (!fu_elantp_hid_device_write_cmd (self, + ETP_CMD_I2C_IAP, + self->iap_password, + error)) + return FALSE; + g_usleep (ELANTP_DELAY_UNLOCK * 1000); + if (!fu_elantp_hid_device_ensure_iap_ctrl (self, error)) + return FALSE; + if ((self->iap_ctrl & ETP_FW_IAP_CHECK_PW) == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "unexpected bootloader password"); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_elantp_hid_device_attach (FuDevice *device, GError **error) +{ + FuElantpHidDevice *self = FU_ELANTP_HID_DEVICE (device); + + /* sanity check */ + if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { + g_debug ("already in runtime mode, skipping"); + return TRUE; + } + + /* reset back to runtime */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + if (!fu_elantp_hid_device_write_cmd (self, ETP_CMD_I2C_IAP_RESET, ETP_I2C_IAP_RESET, error)) + return FALSE; + g_usleep (ELANTP_DELAY_RESET * 1000); + if (!fu_elantp_hid_device_write_cmd (self, ETP_CMD_I2C_IAP_RESET, ETP_I2C_ENABLE_REPORT, error)) { + g_prefix_error (error, "cannot enable TP report: "); + return FALSE; + } + if (!fu_elantp_hid_device_write_cmd (self, 0x0306, 0x003, error)) { + g_prefix_error (error, "cannot switch to TP PTP mode: "); + return FALSE; + } + if (!fu_elantp_hid_device_ensure_iap_ctrl (self, error)) + return FALSE; + + /* success */ + return TRUE; +} + +static gboolean +fu_elantp_hid_device_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + FuElantpHidDevice *self = FU_ELANTP_HID_DEVICE (device); + if (g_strcmp0 (key, "ElantpIcPageCount") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp > 0xffff) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "ElantpIcPageCount only supports " + "values <= 0xffff"); + return FALSE; + } + self->ic_page_count = (guint16) tmp; + return TRUE; + } + if (g_strcmp0 (key, "ElantpIapPassword") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp > 0xffff) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "ElantpIapPassword only supports " + "values <= 0xffff"); + return FALSE; + } + self->iap_password = (guint16) tmp; + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; +} + +static void +fu_elantp_hid_device_init (FuElantpHidDevice *self) +{ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_set_summary (FU_DEVICE (self), "Elan Touchpad"); + fu_device_add_icon (FU_DEVICE (self), "input-touchpad"); + fu_device_add_protocol (FU_DEVICE (self), "tw.com.emc.elantp"); + fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_HEX); + fu_device_set_priority (FU_DEVICE (self), 1); /* better than i2c */ + fu_udev_device_set_flags (FU_UDEV_DEVICE (self), + FU_UDEV_DEVICE_FLAG_OPEN_READ | + FU_UDEV_DEVICE_FLAG_OPEN_WRITE | + FU_UDEV_DEVICE_FLAG_OPEN_NONBLOCK); +} + +static void +fu_elantp_hid_device_finalize (GObject *object) +{ + G_OBJECT_CLASS (fu_elantp_hid_device_parent_class)->finalize (object); +} + +static void +fu_elantp_hid_device_class_init (FuElantpHidDeviceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + object_class->finalize = fu_elantp_hid_device_finalize; + klass_device->to_string = fu_elantp_hid_device_to_string; + klass_device->attach = fu_elantp_hid_device_attach; + klass_device->set_quirk_kv = fu_elantp_hid_device_set_quirk_kv; + klass_device->setup = fu_elantp_hid_device_setup; + klass_device->reload = fu_elantp_hid_device_setup; + klass_device->write_firmware = fu_elantp_hid_device_write_firmware; + klass_device->prepare_firmware = fu_elantp_hid_device_prepare_firmware; + klass_device->probe = fu_elantp_hid_device_probe; +} diff -Nru fwupd-1.4.5/plugins/elantp/fu-elantp-hid-device.h fwupd-1.5.8/plugins/elantp/fu-elantp-hid-device.h --- fwupd-1.4.5/plugins/elantp/fu-elantp-hid-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/elantp/fu-elantp-hid-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,12 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +#define FU_TYPE_ELANTP_HID_DEVICE (fu_elantp_hid_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuElantpHidDevice, fu_elantp_hid_device, FU, ELANTP_HID_DEVICE, FuUdevDevice) diff -Nru fwupd-1.4.5/plugins/elantp/fu-elantp-i2c-device.c fwupd-1.5.8/plugins/elantp/fu-elantp-i2c-device.c --- fwupd-1.4.5/plugins/elantp/fu-elantp-i2c-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/elantp/fu-elantp-i2c-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,662 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include + +#include "config.h" + +#include "fu-elantp-common.h" +#include "fu-elantp-firmware.h" +#include "fu-elantp-i2c-device.h" +#include "fu-chunk.h" + +struct _FuElantpI2cDevice { + FuUdevDevice parent_instance; + guint16 i2c_addr; + guint16 ic_page_count; + guint16 iap_type; + guint16 iap_ctrl; + guint16 iap_password; + guint16 module_id; + guint16 fw_page_size; + guint8 pattern; +}; + +G_DEFINE_TYPE (FuElantpI2cDevice, fu_elantp_i2c_device, FU_TYPE_UDEV_DEVICE) + +static gboolean fu_elantp_i2c_device_detach (FuDevice *device, GError **error); + +static void +fu_elantp_i2c_device_to_string (FuDevice *device, guint idt, GString *str) +{ + FuElantpI2cDevice *self = FU_ELANTP_I2C_DEVICE (device); + fu_common_string_append_kx (str, idt, "I2cAddr", self->i2c_addr); + fu_common_string_append_kx (str, idt, "ModuleId", self->module_id); + fu_common_string_append_kx (str, idt, "Pattern", self->pattern); + fu_common_string_append_kx (str, idt, "FwPageSize", self->fw_page_size); + fu_common_string_append_kx (str, idt, "IcPageCount", self->ic_page_count); + fu_common_string_append_kx (str, idt, "IapType", self->iap_type); + fu_common_string_append_kx (str, idt, "IapCtrl", self->iap_ctrl); +} + +static gboolean +fu_elantp_i2c_device_probe (FuDevice *device, GError **error) +{ + /* FuUdevDevice->probe */ + if (!FU_DEVICE_CLASS (fu_elantp_i2c_device_parent_class)->probe (device, error)) + return FALSE; + + /* check is valid */ + if (g_strcmp0 (fu_udev_device_get_subsystem (FU_UDEV_DEVICE (device)), "i2c-dev") != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "is not correct subsystem=%s, expected i2c-dev", + fu_udev_device_get_subsystem (FU_UDEV_DEVICE (device))); + return FALSE; + } + if (fu_udev_device_get_device_file (FU_UDEV_DEVICE (device)) == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "no device file"); + return FALSE; + } + + /* set the physical ID */ + return fu_udev_device_set_physical_id (FU_UDEV_DEVICE (device), "i2c", error); +} + +static gboolean +fu_elantp_i2c_device_send_cmd (FuElantpI2cDevice *self, + guint8 *tx, gssize txsz, + guint8 *rx, gssize rxsz, + GError **error) +{ + if (g_getenv ("FWUPD_ELANTP_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "Write", tx, txsz); + if (!fu_udev_device_pwrite_full (FU_UDEV_DEVICE (self), 0, tx, txsz, error)) + return FALSE; + if (rxsz == 0) + return TRUE; + if (!fu_udev_device_pread_full (FU_UDEV_DEVICE (self), 0, rx, rxsz, error)) + return FALSE; + if (g_getenv ("FWUPD_ELANTP_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "Read", rx, rxsz); + return TRUE; +} + +static gboolean +fu_elantp_i2c_device_write_cmd (FuElantpI2cDevice *self, guint16 reg, guint16 cmd, GError **error) +{ + guint8 buf[4]; + fu_common_write_uint16 (buf + 0x0, reg, G_LITTLE_ENDIAN); + fu_common_write_uint16 (buf + 0x2, cmd, G_LITTLE_ENDIAN); + return fu_elantp_i2c_device_send_cmd (self, buf, sizeof(buf), NULL, 0, error); +} + +static gboolean +fu_elantp_i2c_device_read_cmd (FuElantpI2cDevice *self, guint16 reg, + guint8 *rx, gsize rxsz, GError **error) +{ + guint8 buf[2]; + fu_common_write_uint16 (buf + 0x0, reg, G_LITTLE_ENDIAN); + return fu_elantp_i2c_device_send_cmd (self, buf, sizeof(buf), + rx, rxsz, error); +} + +static gboolean +fu_elantp_i2c_device_ensure_iap_ctrl (FuElantpI2cDevice *self, GError **error) +{ + guint8 buf[2] = { 0x0 }; + if (!fu_elantp_i2c_device_read_cmd (self, ETP_CMD_I2C_IAP_CTRL, buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read IAPControl: "); + return FALSE; + } + if (!fu_common_read_uint16_safe (buf, sizeof(buf), 0x0, &self->iap_ctrl, + G_LITTLE_ENDIAN, error)) + return FALSE; + + /* in bootloader mode? */ + if ((self->iap_ctrl & ETP_I2C_MAIN_MODE_ON) == 0) + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + else + fu_device_remove_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + + return TRUE; +} + +static gboolean +fu_elantp_i2c_device_setup (FuDevice *device, GError **error) +{ + FuElantpI2cDevice *self = FU_ELANTP_I2C_DEVICE (device); + guint16 fwver; + guint16 iap_ver; + guint16 tmp; + guint16 pid; + guint16 vid; + guint8 buf[30] = { 0x0 }; + guint8 ic_type; + g_autofree gchar *instance_id1 = NULL; + g_autofree gchar *instance_id2 = NULL; + g_autofree gchar *instance_id_ic_type = NULL; + g_autofree gchar *version_bl = NULL; + g_autofree gchar *version = NULL; + + /* read the I2C descriptor */ + if (!fu_elantp_i2c_device_read_cmd (self, ETP_CMD_GET_HID_DESCRIPTOR, + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to get HID descriptor: "); + return FALSE; + } + if (!fu_common_read_uint16_safe (buf, sizeof(buf), 20, + &vid, G_LITTLE_ENDIAN, error)) + return FALSE; + if (!fu_common_read_uint16_safe (buf, sizeof(buf), 22, + &pid, G_LITTLE_ENDIAN, error)) + return FALSE; + + /* set the vendor ID */ + if (vid != 0x0000) { + g_autofree gchar *vendor_id = NULL; + vendor_id = g_strdup_printf ("HIDRAW:0x%04X", vid); + fu_device_add_vendor_id (device, vendor_id); + } + + /* add GUIDs in order of priority */ + if (vid != 0x0 && pid != 0x0) { + g_autofree gchar *devid = NULL; + devid = g_strdup_printf ("HIDRAW\\VID_%04X&PID_%04X", + vid, pid); + fu_device_add_instance_id (device, devid); + } + + /* get pattern */ + if (!fu_elantp_i2c_device_read_cmd (self, + ETP_CMD_I2C_GET_HID_ID, + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read I2C ID: "); + return FALSE; + } + if (!fu_common_read_uint16_safe (buf, sizeof(buf), 0x0, + &tmp, G_LITTLE_ENDIAN, error)) + return FALSE; + self->pattern = tmp != 0xffff ? (tmp & 0xff00) >> 8 : 0; + + /* get current firmware version */ + if (!fu_elantp_i2c_device_read_cmd (self, + ETP_CMD_I2C_FW_VERSION, + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read fw version: "); + return FALSE; + } + if (!fu_common_read_uint16_safe (buf, sizeof(buf), 0x0, + &fwver, G_LITTLE_ENDIAN, error)) + return FALSE; + if (fwver == 0xFFFF || fwver == ETP_CMD_I2C_FW_VERSION) + fwver = 0; + version = fu_common_version_from_uint16 (fwver, FWUPD_VERSION_FORMAT_HEX); + fu_device_set_version (device, version); + + /* get IAP firmware version */ + if (!fu_elantp_i2c_device_read_cmd (self, + self->pattern == 0 ? ETP_CMD_I2C_IAP_VERSION : ETP_CMD_I2C_IAP_VERSION_2, + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read bootloader version: "); + return FALSE; + } + if (self->pattern >= 1) { + iap_ver = buf[1]; + } else { + if (!fu_common_read_uint16_safe (buf, sizeof(buf), 0x0, + &iap_ver, G_LITTLE_ENDIAN, error)) + return FALSE; + } + version_bl = fu_common_version_from_uint16 (iap_ver, FWUPD_VERSION_FORMAT_HEX); + fu_device_set_version_bootloader (device, version_bl); + + /* get module ID */ + if (!fu_elantp_i2c_device_read_cmd (self, + ETP_CMD_GET_MODULE_ID, + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read module ID: "); + return FALSE; + } + if (!fu_common_read_uint16_safe (buf, sizeof(buf), 0x0, + &self->module_id, + G_LITTLE_ENDIAN, error)) + return FALSE; + + /* define the extra instance IDs */ + instance_id1 = g_strdup_printf ("HIDRAW\\VEN_%04X&DEV_%04X&MOD_%04X", + vid, pid, self->module_id); + fu_device_add_instance_id (device, instance_id1); + + /* get OSM version */ + if (!fu_elantp_i2c_device_read_cmd (self, ETP_CMD_I2C_OSM_VERSION, buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read OSM version: "); + return FALSE; + } + if (!fu_common_read_uint16_safe (buf, sizeof(buf), 0x0, + &tmp, G_LITTLE_ENDIAN, error)) + return FALSE; + if (tmp == ETP_CMD_I2C_OSM_VERSION || tmp == 0xFFFF) { + if (!fu_elantp_i2c_device_read_cmd (self, ETP_CMD_I2C_IAP_ICBODY, buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read IC body: "); + return FALSE; + } + if (!fu_common_read_uint16_safe (buf, sizeof(buf), 0x0, + &tmp, G_LITTLE_ENDIAN, error)) + return FALSE; + ic_type = tmp & 0xFF; + } else { + ic_type = (tmp >> 8) & 0xFF; + } + instance_id_ic_type = g_strdup_printf ("ELANTP\\ICTYPE_%02X", ic_type); + fu_device_add_instance_id (device, instance_id_ic_type); + + /* define the extra instance IDs (ic_type + module_id) */ + instance_id2 = g_strdup_printf ("ELANTP\\ICTYPE_%02X&MOD_%04X", + ic_type, self->module_id); + fu_device_add_instance_id (device, instance_id2); + + /* no quirk entry */ + if (self->ic_page_count == 0x0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "no page count for ELANTP\\ICTYPE_%02X", + ic_type); + return FALSE; + } + fu_device_set_firmware_size (device, (guint64) self->ic_page_count * (guint64) 64); + + /* is in bootloader mode */ + if (!fu_elantp_i2c_device_ensure_iap_ctrl (self, error)) + return FALSE; + + /* success */ + return TRUE; +} + +static gboolean +fu_elantp_i2c_device_open (FuDevice *device, GError **error) +{ + FuElantpI2cDevice *self = FU_ELANTP_I2C_DEVICE (device); + gint addr = self->i2c_addr; + guint8 tx_buf[] = { 0x02, 0x01 }; + + /* FuUdevDevice->open */ + if (!FU_DEVICE_CLASS (fu_elantp_i2c_device_parent_class)->open (device, error)) + return FALSE; + + /* set target address */ + if (!fu_udev_device_ioctl (FU_UDEV_DEVICE (device), I2C_SLAVE, + GINT_TO_POINTER (addr), NULL, NULL)) { + if (!fu_udev_device_ioctl (FU_UDEV_DEVICE (device), I2C_SLAVE_FORCE, + GINT_TO_POINTER (addr), NULL, error)) { + g_prefix_error (error, + "failed to set target address to 0x%x: ", + self->i2c_addr); + return FALSE; + } + } + + /* read i2c device */ + return fu_udev_device_pwrite_full (FU_UDEV_DEVICE (device), 0x0, tx_buf, sizeof(tx_buf), error); +} + +static FuFirmware * +fu_elantp_i2c_device_prepare_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + FuElantpI2cDevice *self = FU_ELANTP_I2C_DEVICE (device); + guint16 module_id; + g_autoptr(FuFirmware) firmware = fu_elantp_firmware_new (); + + /* check is compatible with hardware */ + if (!fu_firmware_parse (firmware, fw, flags, error)) + return NULL; + module_id = fu_elantp_firmware_get_module_id (FU_ELANTP_FIRMWARE (firmware)); + if (self->module_id != module_id) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "firmware incompatible, got 0x%04x, expected 0x%04x", + module_id, self->module_id); + return NULL; + } + + /* success */ + return g_steal_pointer (&firmware); +} + +static gboolean +fu_elantp_i2c_device_write_firmware (FuDevice *device, + FuFirmware *firmware, + FwupdInstallFlags flags, + GError **error) +{ + FuElantpI2cDevice *self = FU_ELANTP_I2C_DEVICE (device); + FuElantpFirmware *firmware_elantp = FU_ELANTP_FIRMWARE (firmware); + gsize bufsz = 0; + guint16 checksum = 0; + guint16 checksum_device = 0; + guint16 iap_addr; + const guint8 *buf; + guint8 csum_buf[2] = { 0x0 }; + g_autoptr(GBytes) fw = NULL; + g_autoptr(GPtrArray) chunks = NULL; + + /* simple image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + + /* detach */ + if (!fu_elantp_i2c_device_detach (device, error)) + return FALSE; + + /* write each block */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + buf = g_bytes_get_data (fw, &bufsz); + iap_addr = fu_elantp_firmware_get_iap_addr (firmware_elantp); + chunks = fu_chunk_array_new (buf + iap_addr, bufsz - iap_addr, 0x0, 0x0, self->fw_page_size); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + guint16 csum_tmp = fu_elantp_calc_checksum (fu_chunk_get_data (chk), fu_chunk_get_data_sz (chk)); + gsize blksz = self->fw_page_size + 4; + g_autofree guint8 *blk = g_malloc0 (blksz); + + /* write block */ + blk[0] = ETP_I2C_IAP_REG_L; + blk[1] = ETP_I2C_IAP_REG_H; + if (!fu_memcpy_safe (blk, blksz, 0x2, /* dst */ + fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk), 0x0, /* src */ + fu_chunk_get_data_sz (chk), error)) + return FALSE; + + fu_common_write_uint16 (blk + fu_chunk_get_data_sz (chk) + 2, + csum_tmp, G_LITTLE_ENDIAN); + + if (!fu_elantp_i2c_device_send_cmd (self, blk, blksz, NULL, 0, error)) + return FALSE; + g_usleep (self->fw_page_size == 512 ? + ELANTP_DELAY_WRITE_BLOCK_512 * 1000 : + ELANTP_DELAY_WRITE_BLOCK * 1000); + + if (!fu_elantp_i2c_device_ensure_iap_ctrl (self, error)) + return FALSE; + if (self->iap_ctrl & (ETP_FW_IAP_PAGE_ERR | ETP_FW_IAP_INTF_ERR)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "bootloader reports failed write: 0x%x", + self->iap_ctrl); + return FALSE; + } + + /* update progress */ + checksum += csum_tmp; + fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len); + } + + /* verify the written checksum */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_VERIFY); + if (!fu_elantp_i2c_device_read_cmd (self, ETP_CMD_I2C_IAP_CHECKSUM, + csum_buf, sizeof(csum_buf), error)) + return FALSE; + if (!fu_common_read_uint16_safe (csum_buf, sizeof(csum_buf), 0x0, + &checksum_device, G_LITTLE_ENDIAN, error)) + return FALSE; + if (checksum != checksum_device) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "checksum failed 0x%04x != 0x%04x", + checksum, checksum_device); + return FALSE; + } + + /* wait for a reset */ + fu_device_set_progress (device, 0); + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + g_usleep (ELANTP_DELAY_COMPLETE * 1000); + return TRUE; +} + +static gboolean +fu_elantp_i2c_device_detach (FuDevice *device, GError **error) +{ + guint16 iap_ver; + guint16 ic_type; + guint8 buf[2] = { 0x0 }; + guint16 tmp; + FuElantpI2cDevice *self = FU_ELANTP_I2C_DEVICE (device); + + /* sanity check */ + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { + g_debug ("in bootloader mode, reset IC"); + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + if (!fu_elantp_i2c_device_write_cmd (self, + ETP_CMD_I2C_IAP_RESET, + ETP_I2C_IAP_RESET, + error)) + return FALSE; + g_usleep (ELANTP_DELAY_RESET * 1000); + } + /* get OSM version */ + if (!fu_elantp_i2c_device_read_cmd (self, ETP_CMD_I2C_OSM_VERSION, buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read OSM version: "); + return FALSE; + } + if (!fu_common_read_uint16_safe (buf, sizeof(buf), 0x0, + &tmp, G_LITTLE_ENDIAN, error)) + return FALSE; + if (tmp == ETP_CMD_I2C_OSM_VERSION || tmp == 0xFFFF) { + if (!fu_elantp_i2c_device_read_cmd (self, ETP_CMD_I2C_IAP_ICBODY, buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read IC body: "); + return FALSE; + } + if (!fu_common_read_uint16_safe (buf, sizeof(buf), 0x0, + &ic_type, G_LITTLE_ENDIAN, error)) + return FALSE; + } else { + ic_type = (tmp >> 8) & 0xFF; + } + + /* get IAP firmware version */ + if (!fu_elantp_i2c_device_read_cmd (self, + self->pattern == 0 ? ETP_CMD_I2C_IAP_VERSION : ETP_CMD_I2C_IAP_VERSION_2, + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read bootloader version: "); + return FALSE; + } + if (self->pattern >= 1) { + iap_ver = buf[1]; + } else { + if (!fu_common_read_uint16_safe (buf, sizeof(buf), 0x0, + &iap_ver, G_LITTLE_ENDIAN, error)) + return FALSE; + } + + /* set the page size */ + self->fw_page_size = 64; + if (ic_type >= 0x10) { + if (iap_ver >= 1) { + if (iap_ver >= 2 && (ic_type == 0x14 || ic_type==0x15)) { + self->fw_page_size = 512; + } else { + self->fw_page_size = 128; + } + /* set the IAP type, presumably some kind of ABI */ + if (!fu_elantp_i2c_device_write_cmd (self, + ETP_CMD_I2C_IAP_TYPE, + self->fw_page_size / 2, + error)) + return FALSE; + if (!fu_elantp_i2c_device_read_cmd (self, ETP_CMD_I2C_IAP_TYPE , + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to read IAP type: "); + return FALSE; + } + if (!fu_common_read_uint16_safe (buf, sizeof(buf), 0x0, + &self->iap_type, + G_LITTLE_ENDIAN, error)) + return FALSE; + if (self->iap_type != self->fw_page_size / 2) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to set IAP type"); + return FALSE; + } + } + } + if (!fu_elantp_i2c_device_write_cmd (self, + ETP_CMD_I2C_IAP, + self->iap_password, + error)) + return FALSE; + g_usleep (ELANTP_DELAY_UNLOCK * 1000); + if (!fu_elantp_i2c_device_ensure_iap_ctrl (self, error)) + return FALSE; + if ((self->iap_ctrl & ETP_FW_IAP_CHECK_PW) == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "unexpected bootloader password"); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_elantp_i2c_device_attach (FuDevice *device, GError **error) +{ + FuElantpI2cDevice *self = FU_ELANTP_I2C_DEVICE (device); + + /* sanity check */ + if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { + g_debug ("already in runtime mode, skipping"); + return TRUE; + } + + /* reset back to runtime */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + if (!fu_elantp_i2c_device_write_cmd (self, ETP_CMD_I2C_IAP_RESET, ETP_I2C_IAP_RESET, error)) + return FALSE; + g_usleep (ELANTP_DELAY_RESET * 1000); + if (!fu_elantp_i2c_device_write_cmd (self, ETP_CMD_I2C_IAP_RESET, ETP_I2C_ENABLE_REPORT, error)) { + g_prefix_error (error, "cannot enable TP report: "); + return FALSE; + } + if (!fu_elantp_i2c_device_write_cmd (self, 0x0306, 0x003, error)) { + g_prefix_error (error, "cannot switch to TP PTP mode: "); + return FALSE; + } + if (!fu_elantp_i2c_device_ensure_iap_ctrl (self, error)) + return FALSE; + + /* success */ + return TRUE; +} + +static gboolean +fu_elantp_i2c_device_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + FuElantpI2cDevice *self = FU_ELANTP_I2C_DEVICE (device); + if (g_strcmp0 (key, "ElantpIcPageCount") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp > 0xffff) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "ElantpIcPageCount only supports " + "values <= 0xffff"); + return FALSE; + } + self->ic_page_count = (guint16) tmp; + return TRUE; + } + if (g_strcmp0 (key, "ElantpIapPassword") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp > 0xffff) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "ElantpIapPassword only supports " + "values <= 0xffff"); + return FALSE; + } + self->iap_password = (guint16) tmp; + return TRUE; + } + if (g_strcmp0 (key, "ElantpI2cTargetAddress") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp > 0xffff) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "ElantpI2cTargetAddress only supports " + "values <= 0xffff"); + return FALSE; + } + self->i2c_addr = (guint16) tmp; + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; +} + +static void +fu_elantp_i2c_device_init (FuElantpI2cDevice *self) +{ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NEEDS_REBOOT); + fu_device_set_summary (FU_DEVICE (self), "Elan Touchpad (I²C Recovery)"); + fu_device_add_icon (FU_DEVICE (self), "input-touchpad"); + fu_device_add_protocol (FU_DEVICE (self), "tw.com.emc.elantp"); + fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_HEX); + fu_udev_device_set_flags (FU_UDEV_DEVICE (self), + FU_UDEV_DEVICE_FLAG_OPEN_READ | + FU_UDEV_DEVICE_FLAG_OPEN_WRITE); +} + +static void +fu_elantp_i2c_device_finalize (GObject *object) +{ + G_OBJECT_CLASS (fu_elantp_i2c_device_parent_class)->finalize (object); +} + +static void +fu_elantp_i2c_device_class_init (FuElantpI2cDeviceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + object_class->finalize = fu_elantp_i2c_device_finalize; + klass_device->to_string = fu_elantp_i2c_device_to_string; + klass_device->attach = fu_elantp_i2c_device_attach; + klass_device->set_quirk_kv = fu_elantp_i2c_device_set_quirk_kv; + klass_device->setup = fu_elantp_i2c_device_setup; + klass_device->reload = fu_elantp_i2c_device_setup; + klass_device->write_firmware = fu_elantp_i2c_device_write_firmware; + klass_device->prepare_firmware = fu_elantp_i2c_device_prepare_firmware; + klass_device->probe = fu_elantp_i2c_device_probe; + klass_device->open = fu_elantp_i2c_device_open; +} diff -Nru fwupd-1.4.5/plugins/elantp/fu-elantp-i2c-device.h fwupd-1.5.8/plugins/elantp/fu-elantp-i2c-device.h --- fwupd-1.4.5/plugins/elantp/fu-elantp-i2c-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/elantp/fu-elantp-i2c-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,12 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +#define FU_TYPE_ELANTP_I2C_DEVICE (fu_elantp_i2c_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuElantpI2cDevice, fu_elantp_i2c_device, FU, ELANTP_I2C_DEVICE, FuUdevDevice) diff -Nru fwupd-1.4.5/plugins/elantp/fu-plugin-elantp.c fwupd-1.5.8/plugins/elantp/fu-plugin-elantp.c --- fwupd-1.4.5/plugins/elantp/fu-plugin-elantp.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/elantp/fu-plugin-elantp.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" + +#include "fu-elantp-firmware.h" +#include "fu-elantp-hid-device.h" +#include "fu-elantp-i2c-device.h" + +gboolean +fu_plugin_device_created (FuPlugin *plugin, FuDevice *dev, GError **error) +{ + if (fu_device_get_specialized_gtype (dev) == FU_TYPE_ELANTP_I2C_DEVICE && + !fu_plugin_has_custom_flag (plugin, "elantp-recovery")) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "not required"); + return FALSE; + } + return TRUE; +} + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_udev_subsystem (plugin, "i2c-dev"); + fu_plugin_add_udev_subsystem (plugin, "hidraw"); + fu_plugin_add_firmware_gtype (plugin, NULL, FU_TYPE_ELANTP_FIRMWARE); + fu_plugin_add_possible_quirk_key (plugin, "ElantpI2cTargetAddress"); + fu_plugin_add_possible_quirk_key (plugin, "ElantpIapPassword"); + fu_plugin_add_possible_quirk_key (plugin, "ElantpIcPageCount"); + fu_plugin_set_device_gtype (plugin, FU_TYPE_ELANTP_I2C_DEVICE); + fu_plugin_set_device_gtype (plugin, FU_TYPE_ELANTP_HID_DEVICE); +} diff -Nru fwupd-1.4.5/plugins/elantp/meson.build fwupd-1.5.8/plugins/elantp/meson.build --- fwupd-1.4.5/plugins/elantp/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/elantp/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,38 @@ +if get_option('gudev') +cargs = ['-DG_LOG_DOMAIN="FuPluginElantp"'] + +install_data([ + 'elantp.quirk', + ], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_elantp', + fu_hash, + sources : [ + 'fu-plugin-elantp.c', + 'fu-elantp-common.c', + 'fu-elantp-firmware.c', # fuzzing + 'fu-elantp-hid-device.c', + 'fu-elantp-i2c-device.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + c_args : [ + cargs, + '-DLOCALSTATEDIR="' + localstatedir + '"', + ], + link_with : [ + fwupd, + fwupdplugin, + ], + dependencies : [ + plugin_deps, + ], +) +endif diff -Nru fwupd-1.4.5/plugins/elantp/README.md fwupd-1.5.8/plugins/elantp/README.md --- fwupd-1.4.5/plugins/elantp/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/elantp/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,68 @@ +Elan TouchPad +============= + +Introduction +------------ + +This plugin allows updating Touchpad devices from Elan. Devices are enumerated +using HID and raw I²C nodes. The I²C mode is used for firmware recovery. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecified binary file format. + +This plugin supports the following protocol ID: + + * tw.com.emc.elantp + +GUID Generation +--------------- + +These device uses the standard DeviceInstanceId values, e.g. + + * `HIDRAW\VEN_04F3&DEV_3010` + +Additionally another instance ID is added which corresponds to the module ID: + + * `HIDRAW\VEN_04F3&DEV_3010&MOD_1234` + +These devices also use custom GUID values for the IC configuration, e.g. + + * `ELANTP\ICTYPE_09` + + Additionally another instance ID is added which corresponds to the IC type & module ID: + + * `ELANTP\ICTYPE_09&MOD_1234` + +Update Behavior +--------------- + +The device usually presents in HID mode, and the firmware is written to the +device by switching to a IAP mode where the touchpad is nonfunctional. +Once complete the device is reset to get out of IAP mode and to load the new +firmware version. + +On flash failure the device is nonfunctional, but is recoverable by writing +to the i2c device. This is typically much slower than updating the device +using HID and also requires a model-specific HWID quirk to match. + +Vendor ID Security +------------------ + +The vendor ID is set from the HID vendor, for example set to `HIDRAW:0x17EF` + +Quirk use +--------- + +This plugin uses the following plugin-specific quirks: + +| Quirk | Description | Minimum fwupd version | +|------------------------|-------------------------------------------|-----------------------| +| `ElantpIcPageCount` | The IC page count | 1.4.6 | +| `ElantpIapPassword` | The IAP password | 1.4.6 | + +External interface access +------------------------- +This plugin requires ioctl access to `HIDIOCSFEATURE` and `HIDIOCGFEATURE`. diff -Nru fwupd-1.4.5/plugins/emmc/emmc.quirk fwupd-1.5.8/plugins/emmc/emmc.quirk --- fwupd-1.4.5/plugins/emmc/emmc.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/emmc/emmc.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,3 @@ # match all devices with this udev subsystem -[DeviceInstanceId=BLOCK] +[BLOCK] Plugin = emmc diff -Nru fwupd-1.4.5/plugins/emmc/fu-emmc-device.c fwupd-1.5.8/plugins/emmc/fu-emmc-device.c --- fwupd-1.4.5/plugins/emmc/fu-emmc-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/emmc/fu-emmc-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -74,6 +74,7 @@ fu_emmc_device_to_string (FuDevice *device, guint idt, GString *str) { FuEmmcDevice *self = FU_EMMC_DEVICE (device); + FU_DEVICE_CLASS (fu_emmc_device_parent_class)->to_string (device, idt, str); fu_common_string_append_ku (str, idt, "SectorSize", self->sect_size); } @@ -127,9 +128,9 @@ } static gboolean -fu_emmc_device_probe (FuUdevDevice *device, GError **error) +fu_emmc_device_probe (FuDevice *device, GError **error) { - GUdevDevice *udev_device = fu_udev_device_get_dev (device); + GUdevDevice *udev_device = fu_udev_device_get_dev (FU_UDEV_DEVICE (device)); guint64 flag; guint64 oemid = 0; guint64 manfid = 0; @@ -140,6 +141,10 @@ g_autofree gchar *man_oem_name = NULL; g_autofree gchar *vendor_id = NULL; + /* FuUdevDevice->probe */ + if (!FU_DEVICE_CLASS (fu_emmc_device_parent_class)->probe (device, error)) + return FALSE; + udev_parent = g_udev_device_get_parent_with_subsystem (udev_device, "mmc", NULL); if (udev_parent == NULL) { g_set_error_literal (error, @@ -167,7 +172,7 @@ FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "%s does not support field firmware updates", - fu_device_get_name (FU_DEVICE (device))); + fu_device_get_name (device)); return FALSE; } @@ -182,9 +187,9 @@ } /* name */ - fu_device_set_name (FU_DEVICE (device), tmp); + fu_device_set_name (device, tmp); name_only = g_strdup_printf ("EMMC\\%s", fu_device_get_name (device)); - fu_device_add_instance_id (FU_DEVICE (device), name_only); + fu_device_add_instance_id (device, name_only); /* manfid + oemid, manfid + oemid + name */ if (!fu_emmc_device_get_sysattr_guint64 (udev_parent, "manfid", &manfid, error)) @@ -193,32 +198,32 @@ return FALSE; man_oem = g_strdup_printf ("EMMC\\%04" G_GUINT64_FORMAT "&%04" G_GUINT64_FORMAT, manfid, oemid); - fu_device_add_instance_id (FU_DEVICE (device), man_oem); + fu_device_add_instance_id (device, man_oem); man_oem_name = g_strdup_printf ("EMMC\\%04" G_GUINT64_FORMAT "&%04" G_GUINT64_FORMAT "&%s", manfid, oemid, fu_device_get_name (device)); - fu_device_add_instance_id (FU_DEVICE (device), man_oem_name); + fu_device_add_instance_id (device, man_oem_name); /* set the vendor */ tmp = g_udev_device_get_sysfs_attr (udev_parent, "manfid"); vendor_id = g_strdup_printf ("EMMC:%s", tmp); - fu_device_set_vendor_id (FU_DEVICE (device), vendor_id); - fu_device_set_vendor (FU_DEVICE (device), fu_emmc_device_get_manufacturer (manfid)); + fu_device_add_vendor_id (device, vendor_id); + fu_device_set_vendor (device, fu_emmc_device_get_manufacturer (manfid)); /* set the physical ID */ - if (!fu_udev_device_set_physical_id (device, "mmc", error)) + if (!fu_udev_device_set_physical_id (FU_UDEV_DEVICE (device), "mmc", error)) return FALSE; /* internal */ if (!fu_emmc_device_get_sysattr_guint64 (udev_device, "removable", &flag, error)) return FALSE; if (flag == 0) - fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_INTERNAL); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_INTERNAL); - /* firwmare version */ + /* firmware version */ tmp = g_udev_device_get_sysfs_attr (udev_parent, "fwrev"); if (tmp != NULL) { - fu_device_set_version_format (FU_DEVICE (device), FWUPD_VERSION_FORMAT_NUMBER); - fu_device_set_version (FU_DEVICE (device), tmp); + fu_device_set_version_format (device, FWUPD_VERSION_FORMAT_NUMBER); + fu_device_set_version (device, tmp); } return TRUE; @@ -382,16 +387,20 @@ for (guint i = 0; i < chunks->len; i++) { FuChunk *chk = g_ptr_array_index (chunks, i); - mmc_ioc_cmd_set_data (multi_cmd->cmds[1], chk->data); + mmc_ioc_cmd_set_data (multi_cmd->cmds[1], fu_chunk_get_data (chk)); if (!fu_udev_device_ioctl (FU_UDEV_DEVICE (self), MMC_IOC_MULTI_CMD, (guint8 *) multi_cmd, NULL, error)) { + g_autoptr(GError) error_local = NULL; g_prefix_error (error, "multi-cmd failed: "); /* multi-cmd ioctl failed before exiting from ffu mode */ - fu_udev_device_ioctl (FU_UDEV_DEVICE (self), - MMC_IOC_CMD, (guint8 *) &multi_cmd->cmds[2], - NULL, NULL); + if (!fu_udev_device_ioctl (FU_UDEV_DEVICE (self), + MMC_IOC_CMD, (guint8 *) &multi_cmd->cmds[2], + NULL, &error_local)) { + g_prefix_error (error, "%s: ", + error_local->message); + } return FALSE; } @@ -455,11 +464,15 @@ if (!fu_udev_device_ioctl (FU_UDEV_DEVICE (self), MMC_IOC_MULTI_CMD, (guint8 *) multi_cmd, NULL, error)) { + g_autoptr(GError) error_local = NULL; /* In case multi-cmd ioctl failed before exiting from ffu mode */ g_prefix_error (error, "multi-cmd failed setting install mode: "); - fu_udev_device_ioctl (FU_UDEV_DEVICE (self), - MMC_IOC_CMD, (guint8 *) &multi_cmd->cmds[2], - NULL, NULL); + if (!fu_udev_device_ioctl (FU_UDEV_DEVICE (self), + MMC_IOC_CMD, (guint8 *) &multi_cmd->cmds[2], + NULL, &error_local)) { + g_prefix_error (error, "%s: ", + error_local->message); + } return FALSE; } @@ -482,7 +495,7 @@ static void fu_emmc_device_init (FuEmmcDevice *self) { - fu_device_set_protocol (FU_DEVICE (self), "org.jedec.mmc"); + fu_device_add_protocol (FU_DEVICE (self), "org.jedec.mmc"); fu_device_add_icon (FU_DEVICE (self), "media-memory"); } @@ -497,11 +510,10 @@ { GObjectClass *object_class = G_OBJECT_CLASS (klass); FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - FuUdevDeviceClass *klass_udev_device = FU_UDEV_DEVICE_CLASS (klass); object_class->finalize = fu_emmc_device_finalize; klass_device->setup = fu_emmc_device_setup; klass_device->to_string = fu_emmc_device_to_string; klass_device->prepare_firmware = fu_emmc_device_prepare_firmware; - klass_udev_device->probe = fu_emmc_device_probe; + klass_device->probe = fu_emmc_device_probe; klass_device->write_firmware = fu_emmc_device_write_firmware; } diff -Nru fwupd-1.4.5/plugins/emmc/fu-plugin-emmc.c fwupd-1.5.8/plugins/emmc/fu-plugin-emmc.c --- fwupd-1.4.5/plugins/emmc/fu-plugin-emmc.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/emmc/fu-plugin-emmc.c 2021-03-31 20:08:32.000000000 +0000 @@ -7,7 +7,6 @@ #include "config.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #include "fu-emmc-device.h" diff -Nru fwupd-1.4.5/plugins/emmc/meson.build fwupd-1.5.8/plugins/emmc/meson.build --- fwupd-1.4.5/plugins/emmc/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/emmc/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,7 @@ +if get_option('plugin_emmc') +if not get_option('gudev') + error('gudev is required for plugin_emmc') +endif cargs = ['-DG_LOG_DOMAIN="FuPluginEmmc"'] install_data(['emmc.quirk'], @@ -25,3 +29,4 @@ plugin_deps, ], ) +endif diff -Nru fwupd-1.4.5/plugins/emmc/README.md fwupd-1.5.8/plugins/emmc/README.md --- fwupd-1.4.5/plugins/emmc/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/emmc/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -20,7 +20,17 @@ * `EMMC\%MANFID%&%OEMID%` * `EMMC\%MANFID%&%OEMID%&%NAME%` +Update Behavior +--------------- + +The firmware is deployed when the device is in normal runtime mode, but it is +only activated when the device is rebooted. + Vendor ID Security ------------------ The vendor ID is set from the EMMC vendor, for example set to `EMMC:{$manfid}` + +External interface access +------------------------- +This plugin requires ioctl `MMC_IOC_CMD` and `MMC_IOC_MULTI_CMD` access. diff -Nru fwupd-1.4.5/plugins/ep963x/ep963x.quirk fwupd-1.5.8/plugins/ep963x/ep963x.quirk --- fwupd-1.4.5/plugins/ep963x/ep963x.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/ep963x/ep963x.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,2 +1,2 @@ -[DeviceInstanceId=USB\VID_17EF&PID_7226] +[USB\VID_17EF&PID_7226] Plugin = ep963x diff -Nru fwupd-1.4.5/plugins/ep963x/fu-ep963x-device.c fwupd-1.5.8/plugins/ep963x/fu-ep963x-device.c --- fwupd-1.4.5/plugins/ep963x/fu-ep963x-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/ep963x/fu-ep963x-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -182,7 +182,6 @@ GError **error) { g_autoptr(FuFirmware) firmware = fu_ep963x_firmware_new (); - fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); if (!fu_firmware_parse (firmware, fw, flags, error)) return NULL; return g_steal_pointer (&firmware); @@ -247,7 +246,7 @@ blocks = fu_chunk_array_new_from_bytes (fw, 0x00, 0x00, FU_EP963_TRANSFER_BLOCK_SIZE); for (guint i = 0; i < blocks->len; i++) { - FuChunk *blk = g_ptr_array_index (blocks, i); + FuChunk *chk2 = g_ptr_array_index (blocks, i); guint8 buf[] = { i }; g_autoptr(GPtrArray) chunks = NULL; @@ -265,8 +264,9 @@ } /* 4 byte chunks */ - chunks = fu_chunk_array_new (blk->data, blk->data_sz, - blk->address, 0x0, + chunks = fu_chunk_array_new (fu_chunk_get_data (chk2), + fu_chunk_get_data_sz (chk2), + fu_chunk_get_address (chk2), 0x0, FU_EP963_TRANSFER_CHUNK_SIZE); for (guint j = 0; j < chunks->len; j++) { FuChunk *chk = g_ptr_array_index (chunks, j); @@ -276,13 +276,14 @@ if (!fu_ep963x_device_write (self, FU_EP963_USB_CONTROL_ID, FU_EP963_OPCODE_SUBMCU_WRITE_BLOCK_DATA, - chk->data, chk->data_sz, + fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk), &error_loop)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_WRITE, "failed to write 0x%x: %s", - (guint) chk->address, + (guint) fu_chunk_get_address (chk), error_loop->message); return FALSE; } @@ -297,7 +298,7 @@ FWUPD_ERROR, FWUPD_ERROR_WRITE, "failed to write 0x%x: %s", - (guint) blk->address, + (guint) fu_chunk_get_address (chk2), error_local->message); return FALSE; } @@ -318,7 +319,7 @@ fu_ep963x_device_init (FuEp963xDevice *self) { fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); - fu_device_set_protocol (FU_DEVICE (self), "tw.com.exploretech.ep963x"); + fu_device_add_protocol (FU_DEVICE (self), "tw.com.exploretech.ep963x"); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_NUMBER); fu_device_set_remove_delay (FU_DEVICE (self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); fu_device_set_firmware_size (FU_DEVICE (self), FU_EP963_FIRMWARE_SIZE); diff -Nru fwupd-1.4.5/plugins/ep963x/fu-plugin-ep963x.c fwupd-1.5.8/plugins/ep963x/fu-plugin-ep963x.c --- fwupd-1.4.5/plugins/ep963x/fu-plugin-ep963x.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/ep963x/fu-plugin-ep963x.c 2021-03-31 20:08:32.000000000 +0000 @@ -7,7 +7,6 @@ #include "config.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #include "fu-ep963x-device.h" #include "fu-ep963x-firmware.h" @@ -17,5 +16,5 @@ { fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_set_device_gtype (plugin, FU_TYPE_EP963X_DEVICE); - fu_plugin_add_firmware_gtype (plugin, "ep963x", FU_TYPE_EP963X_FIRMWARE); + fu_plugin_add_firmware_gtype (plugin, NULL, FU_TYPE_EP963X_FIRMWARE); } diff -Nru fwupd-1.4.5/plugins/ep963x/README.md fwupd-1.5.8/plugins/ep963x/README.md --- fwupd-1.4.5/plugins/ep963x/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/ep963x/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -25,7 +25,18 @@ * `USB\VID_17EF&PID_7226` * `USB\VID_17EF` +Update Behavior +--------------- + +The device usually presents in runtime mode, but on detach re-enumerates with +the same USB PID in an unlocked mode. On attach the device again re-enumerates +back to the runtime locked mode. + Vendor ID Security ------------------ The vendor ID is set from the USB vendor, in this instance set to `USB:0x17EF` + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff -Nru fwupd-1.4.5/plugins/fastboot/fastboot.quirk fwupd-1.5.8/plugins/fastboot/fastboot.quirk --- fwupd-1.4.5/plugins/fastboot/fastboot.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/fastboot/fastboot.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,3 @@ # All fastboot devices -[DeviceInstanceId=USB\CLASS_FF&SUBCLASS_42&PROT_03] +[USB\CLASS_FF&SUBCLASS_42&PROT_03] Plugin = fastboot diff -Nru fwupd-1.4.5/plugins/fastboot/fu-fastboot-device.c fwupd-1.5.8/plugins/fastboot/fu-fastboot-device.c --- fwupd-1.4.5/plugins/fastboot/fu-fastboot-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/fastboot/fu-fastboot-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -54,10 +54,14 @@ } static gboolean -fu_fastboot_device_open (FuUsbDevice *device, GError **error) +fu_fastboot_device_open (FuDevice *device, GError **error) { FuFastbootDevice *self = FU_FASTBOOT_DEVICE (device); - GUsbDevice *usb_device = fu_usb_device_get_dev (device); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + + /* FuUsbDevice->open */ + if (!FU_DEVICE_CLASS (fu_fastboot_device_parent_class)->open (device, error)) + return FALSE; if (!g_usb_device_claim_interface (usb_device, self->intf_nr, G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, @@ -90,7 +94,12 @@ GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); gboolean ret; gsize actual_len = 0; - g_autofree guint8 *buf2 = g_memdup (buf, (guint) buflen); + g_autofree guint8 *buf2 = NULL; + + /* make mutable */ + buf2 = fu_memdup_safe (buf, buflen, error); + if (buf2 == NULL) + return FALSE; fu_fastboot_buffer_dump ("writing", buf, buflen); ret = g_usb_device_bulk_transfer (usb_device, @@ -281,7 +290,10 @@ self->blocksz); for (guint i = 0; i < chunks->len; i++) { FuChunk *chk = g_ptr_array_index (chunks, i); - if (!fu_fastboot_device_write (device, chk->data, chk->data_sz, error)) + if (!fu_fastboot_device_write (device, + fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk), + error)) return FALSE; fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len * 2); } @@ -631,10 +643,10 @@ } static gboolean -fu_fastboot_device_close (FuUsbDevice *device, GError **error) +fu_fastboot_device_close (FuDevice *device, GError **error) { FuFastbootDevice *self = FU_FASTBOOT_DEVICE (device); - GUsbDevice *usb_device = fu_usb_device_get_dev (device); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); /* we're done here */ if (!g_usb_device_release_interface (usb_device, self->intf_nr, @@ -644,8 +656,8 @@ return FALSE; } - /* success */ - return TRUE; + /* FuUsbDevice->close */ + return FU_DEVICE_CLASS (fu_fastboot_device_parent_class)->close (device, error); } static gboolean @@ -656,7 +668,7 @@ { FuFastbootDevice *self = FU_FASTBOOT_DEVICE (device); - /* load slave address from quirks */ + /* load from quirks */ if (g_strcmp0 (key, "FastbootBlockSize") == 0) { guint64 tmp = fu_common_strtoull (value); if (tmp >= 0x40 && tmp < 0x100000) { @@ -696,10 +708,11 @@ { /* this is a safe default, even using USBv1 */ self->blocksz = 512; - fu_device_set_protocol (FU_DEVICE (self), "com.google.fastboot"); + fu_device_add_protocol (FU_DEVICE (self), "com.google.fastboot"); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_ADD_COUNTERPART_GUIDS); + fu_device_add_internal_flag (FU_DEVICE (self), FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID); fu_device_set_remove_delay (FU_DEVICE (self), FASTBOOT_REMOVE_DELAY_RE_ENUMERATE); } @@ -707,13 +720,12 @@ fu_fastboot_device_class_init (FuFastbootDeviceClass *klass) { FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); klass_device->probe = fu_fastboot_device_probe; klass_device->setup = fu_fastboot_device_setup; klass_device->write_firmware = fu_fastboot_device_write_firmware; klass_device->attach = fu_fastboot_device_attach; klass_device->to_string = fu_fastboot_device_to_string; klass_device->set_quirk_kv = fu_fastboot_device_set_quirk_kv; - klass_usb_device->open = fu_fastboot_device_open; - klass_usb_device->close = fu_fastboot_device_close; + klass_device->open = fu_fastboot_device_open; + klass_device->close = fu_fastboot_device_close; } diff -Nru fwupd-1.4.5/plugins/fastboot/fu-plugin-fastboot.c fwupd-1.5.8/plugins/fastboot/fu-plugin-fastboot.c --- fwupd-1.4.5/plugins/fastboot/fu-plugin-fastboot.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/fastboot/fu-plugin-fastboot.c 2021-03-31 20:08:32.000000000 +0000 @@ -7,7 +7,6 @@ #include "config.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #include "fu-fastboot-device.h" diff -Nru fwupd-1.4.5/plugins/fastboot/meson.build fwupd-1.5.8/plugins/fastboot/meson.build --- fwupd-1.4.5/plugins/fastboot/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/fastboot/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,4 @@ +if get_option('gusb') cargs = ['-DG_LOG_DOMAIN="FuPluginFastboot"'] install_data(['fastboot.quirk'], @@ -26,3 +27,4 @@ plugin_deps, ], ) +endif diff -Nru fwupd-1.4.5/plugins/fastboot/README.md fwupd-1.5.8/plugins/fastboot/README.md --- fwupd-1.4.5/plugins/fastboot/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/fastboot/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -31,6 +31,17 @@ * `USB\VID_18D1&PID_4EE0` * `USB\VID_18D1` +Update Behavior +--------------- + +A fastboot device usually presents in runtime mode (or with no interface), +but if the user puts the device into fastboot mode using a physical button +it then enumerates with a USB descriptor. On attach the device reboots to +runtime mode which *may* mean the device "goes away". + +For this reason the `REPLUG_MATCH_GUID` internal device flag is used so that +the bootloader and runtime modes are treated as the same device. + Quirk use --------- This plugin uses the following plugin-specific quirk: @@ -43,3 +54,7 @@ ------------------ The vendor ID is set from the USB vendor, for example `USB:0x18D1` + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff -Nru fwupd-1.4.5/plugins/flashrom/flashrom.quirk fwupd-1.5.8/plugins/flashrom/flashrom.quirk --- fwupd-1.4.5/plugins/flashrom/flashrom.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/flashrom/flashrom.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,8 +1,35 @@ # Purism -[HwId=a0ce5085-2dea-5086-ae72-45810a186ad0] -DeviceId=librem15v3 +[a0ce5085-2dea-5086-ae72-45810a186ad0] +Plugin=flashrom # Libretrend -[HwId=52b68c34-6b31-5ecc-8a5c-de37e666ccd5] -DeviceId=LT1000 +[52b68c34-6b31-5ecc-8a5c-de37e666ccd5] +Plugin=flashrom VersionFormat=quad + +# Star LabTop Mk III (HwId) +[013b60e5-1023-5bee-8ae5-14cae21377b7] +Plugin=flashrom +PciBcrAddr = 0x0 + +# Star LabTop Mk IV (HwId) +[baf1d04e-fd16-5e6a-93cc-1c23d171f879] +Plugin=flashrom + +# Star Lite Mk II (HwId) +[013b60e5-1023-5bee-8ae5-14cae21377b7] +Plugin=flashrom + +# Star Lite Mk III (HwId) +[d5521faa-c50b-5d64-971d-8fd400030c51] +Plugin=flashrom + +# Star LabTop Mk III (coreboot GUID) +[d33219e2-b84c-53a8-a624-27af9752dba6] +Branch=coreboot +VersionFormat=number + +# Star LabTop Mk IV (coreboot GUID) +[0ee5867c-93f0-5fb4-adf1-9d686ea1183a] +Branch=coreboot +VersionFormat=number diff -Nru fwupd-1.4.5/plugins/flashrom/fu-flashrom-device.c fwupd-1.5.8/plugins/flashrom/fu-flashrom-device.c --- fwupd-1.4.5/plugins/flashrom/fu-flashrom-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/flashrom/fu-flashrom-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2017 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-flashrom-device.h" + +struct _FuFlashromDevice { + FuDevice parent_instance; +}; + +G_DEFINE_TYPE (FuFlashromDevice, fu_flashrom_device, FU_TYPE_DEVICE) + +static void +fu_flashrom_device_init (FuFlashromDevice *self) +{ + fu_device_add_protocol (FU_DEVICE (self), "org.flashrom"); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NEEDS_REBOOT); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_REQUIRE_AC); + fu_device_add_instance_id (FU_DEVICE (self), "main-system-firmware"); + fu_device_add_internal_flag (FU_DEVICE (self), FU_DEVICE_INTERNAL_FLAG_ENSURE_SEMVER); + fu_device_set_physical_id (FU_DEVICE (self), "flashrom"); + fu_device_set_logical_id (FU_DEVICE (self), "bios"); + fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_add_icon (FU_DEVICE (self), "computer"); +} + +static void +fu_flashrom_device_class_init (FuFlashromDeviceClass *klass) +{ +} + +FuDevice * +fu_flashrom_device_new (void) +{ + return FU_DEVICE (g_object_new (FU_TYPE_FLASHROM_DEVICE, NULL)); +} diff -Nru fwupd-1.4.5/plugins/flashrom/fu-flashrom-device.h fwupd-1.5.8/plugins/flashrom/fu-flashrom-device.h --- fwupd-1.4.5/plugins/flashrom/fu-flashrom-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/flashrom/fu-flashrom-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2017 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +#define FU_TYPE_FLASHROM_DEVICE (fu_flashrom_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuFlashromDevice, fu_flashrom_device, FU, FLASHROM_DEVICE, FuDevice) + +FuDevice *fu_flashrom_device_new (void); diff -Nru fwupd-1.4.5/plugins/flashrom/fu-plugin-flashrom.c fwupd-1.5.8/plugins/flashrom/fu-plugin-flashrom.c --- fwupd-1.4.5/plugins/flashrom/fu-plugin-flashrom.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/flashrom/fu-plugin-flashrom.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,6 +1,7 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2017 Richard Hughes + * Copyright (C) 2019 9elements Agency GmbH * * Licensed under the GNU General Public License Version 2 * @@ -24,8 +25,9 @@ #include #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" -#include "libflashrom.h" +#include "fu-flashrom-device.h" + +#include #define SELFCHECK_TRUE 1 @@ -41,6 +43,9 @@ { fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_METADATA_SOURCE, "linux_lockdown"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_CONFLICTS, "coreboot"); /* obsoleted */ + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_REQUIRE_HWID); } void @@ -59,18 +64,21 @@ #pragma clang diagnostic ignored "-Wformat-nonliteral" g_autofree gchar *tmp = g_strdup_vprintf (fmt, args); #pragma clang diagnostic pop + g_autofree gchar *str = fu_common_strstrip (tmp); + if (g_strcmp0 (str, "OK.") == 0 || g_strcmp0 (str, ".") == 0) + return 0; switch (lvl) { case FLASHROM_MSG_ERROR: case FLASHROM_MSG_WARN: - g_warning ("%s", tmp); + g_warning ("%s", str); break; case FLASHROM_MSG_INFO: - g_debug ("%s", tmp); + g_debug ("%s", str); break; case FLASHROM_MSG_DEBUG: case FLASHROM_MSG_DEBUG2: if (g_getenv ("FWUPD_FLASHROM_VERBOSE") != NULL) - g_debug ("%s", tmp); + g_debug ("%s", str); break; case FLASHROM_MSG_SPEW: break; @@ -80,48 +88,114 @@ return 0; } +static void +fu_plugin_flashrom_device_set_version (FuPlugin *plugin, FuDevice *device) +{ + const gchar *version; + const gchar *version_major; + const gchar *version_minor; + + /* as-is */ + version = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_BIOS_VERSION); + if (version != NULL) { + /* some Lenovo hardware requires a specific prefix for the EC, + * so strip it before we use ensure-semver */ + if (strlen (version) > 9 && g_str_has_prefix (version, "CBET")) + version += 9; + + /* this may not "stick" if there are no numeric chars */ + fu_device_set_version (device, version); + if (fu_device_get_version (device) != NULL) + return; + } + + /* component parts only */ + version_major = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_BIOS_MAJOR_RELEASE); + version_minor = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_BIOS_MINOR_RELEASE); + if (version_major != NULL && version_minor != NULL) { + g_autofree gchar *tmp = g_strdup_printf ("%s.%s.0", + version_major, + version_minor); + fu_device_set_version (device, tmp); + return; + } +} +static void +fu_plugin_flashrom_device_set_bios_info (FuPlugin *plugin, FuDevice *device) +{ + const guint8 *buf; + gsize bufsz; + guint32 bios_char = 0x0; + guint8 bios_sz = 0x0; + g_autoptr(GBytes) bios_table = NULL; + + /* get SMBIOS info */ + bios_table = fu_plugin_get_smbios_data (plugin, FU_SMBIOS_STRUCTURE_TYPE_BIOS); + if (bios_table == NULL) + return; + + /* ROM size */ + buf = g_bytes_get_data (bios_table, &bufsz); + if (fu_common_read_uint8_safe (buf, bufsz, 0x9, &bios_sz, NULL)) { + guint64 firmware_size = (bios_sz + 1) * 64 * 1024; + fu_device_set_firmware_size_max (device, firmware_size); + } + + /* BIOS characteristics */ + if (fu_common_read_uint32_safe (buf, bufsz, 0xa, &bios_char, G_LITTLE_ENDIAN, NULL)) { + if ((bios_char & (1 << 11)) == 0) + fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + } +} + +static void +fu_plugin_flashrom_device_set_hwids (FuPlugin *plugin, FuDevice *device) +{ + static const gchar *hwids[] = { + "HardwareID-3", + "HardwareID-4", + "HardwareID-5", + "HardwareID-6", + "HardwareID-10", + /* a more useful one for coreboot branch detection */ + FU_HWIDS_KEY_MANUFACTURER "&" + FU_HWIDS_KEY_FAMILY "&" + FU_HWIDS_KEY_PRODUCT_NAME "&" + FU_HWIDS_KEY_PRODUCT_SKU "&" + FU_HWIDS_KEY_BIOS_VENDOR, + }; + /* don't include FU_HWIDS_KEY_BIOS_VERSION */ + for (guint i = 0; i < G_N_ELEMENTS (hwids); i++) { + g_autofree gchar *str = NULL; + str = fu_plugin_get_hwid_replace_value (plugin, hwids[i], NULL); + if (str != NULL) + fu_device_add_instance_id (device, str); + } +} + gboolean fu_plugin_coldplug (FuPlugin *plugin, GError **error) { FuPluginData *data = fu_plugin_get_data (plugin); - GPtrArray *hwids = fu_plugin_get_hwids (plugin); const gchar *dmi_vendor; - g_autoptr(GPtrArray) devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + gint rc; + g_autoptr(FuDevice) device = fu_flashrom_device_new (); - dmi_vendor = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_BIOS_VENDOR); - for (guint i = 0; i < hwids->len; i++) { - const gchar *guid = g_ptr_array_index (hwids, i); - const gchar *quirk_str; - g_autofree gchar *quirk_key_prefixed = NULL; - quirk_key_prefixed = g_strdup_printf ("HwId=%s", guid); - quirk_str = fu_plugin_lookup_quirk_by_id (plugin, - quirk_key_prefixed, - "DeviceId"); - if (quirk_str != NULL) { - g_autofree gchar *device_id = g_strdup_printf ("flashrom-%s", quirk_str); - g_autoptr(FuDevice) dev = fu_device_new (); - fu_device_set_id (dev, device_id); - fu_device_set_quirks (dev, fu_plugin_get_quirks (plugin)); - fu_device_set_protocol (dev, "org.flashrom"); - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_INTERNAL); - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); - fu_device_set_name (dev, fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_PRODUCT_NAME)); - fu_device_set_vendor (dev, fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_MANUFACTURER)); - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_ENSURE_SEMVER); - fu_device_set_version (dev, fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_BIOS_VERSION)); - fu_device_add_guid (dev, guid); - if (dmi_vendor != NULL) { - g_autofree gchar *vendor_id = g_strdup_printf ("DMI:%s", dmi_vendor); - fu_device_set_vendor_id (FU_DEVICE (dev), vendor_id); - } - g_ptr_array_add (devices, g_steal_pointer (&dev)); - break; - } - } + fu_device_set_quirks (device, fu_plugin_get_quirks (plugin)); + fu_device_set_name (device, fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_PRODUCT_NAME)); + fu_device_set_vendor (device, fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_MANUFACTURER)); - /* nothing to do, so don't bother initializing flashrom */ - if (devices->len == 0) - return TRUE; + /* use same VendorID logic as with UEFI */ + dmi_vendor = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_BIOS_VENDOR); + if (dmi_vendor != NULL) { + g_autofree gchar *vendor_id = g_strdup_printf ("DMI:%s", dmi_vendor); + fu_device_add_vendor_id (FU_DEVICE (device), vendor_id); + } + fu_plugin_flashrom_device_set_version (plugin, device); + fu_plugin_flashrom_device_set_hwids (plugin, device); + fu_plugin_flashrom_device_set_bios_info (plugin, device); + if (!fu_device_setup (device, error)) + return FALSE; /* actually probe hardware to check for support */ if (flashrom_init (SELFCHECK_TRUE)) { @@ -139,11 +213,26 @@ "programmer initialization failed"); return FALSE; } - if (flashrom_flash_probe (&data->flashctx, data->flashprog, NULL)) { + rc = flashrom_flash_probe (&data->flashctx, data->flashprog, NULL); + if (rc == 3) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "flash probe failed: multiple chips were found"); + return FALSE; + } + if (rc == 2) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, - "flash probe failed"); + "flash probe failed: no chip was found"); + return FALSE; + } + if (rc != 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "flash probe failed: unknown error"); return FALSE; } data->flash_size = flashrom_flash_getsize (data->flashctx); @@ -155,12 +244,9 @@ return FALSE; } - /* add devices */ - for (guint i = 0; i < devices->len; i++) { - FuDevice *dev = g_ptr_array_index (devices, i); - fu_plugin_device_add (plugin, dev); - fu_plugin_cache_add (plugin, fu_device_get_id (dev), dev); - } + /* success */ + fu_plugin_device_add (plugin, device); + fu_plugin_cache_add (plugin, fu_device_get_id (device), device); return TRUE; } @@ -245,6 +331,7 @@ } fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + fu_device_set_progress (device, 0); /* urgh */ rc = flashrom_image_write (data->flashctx, (void *) buf, sz, NULL /* refbuffer */); if (rc != 0) { g_set_error (error, diff -Nru fwupd-1.4.5/plugins/flashrom/meson.build fwupd-1.5.8/plugins/flashrom/meson.build --- fwupd-1.4.5/plugins/flashrom/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/flashrom/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,4 @@ +if get_option('plugin_flashrom') cargs = ['-DG_LOG_DOMAIN="FuPluginFlashrom"'] install_data(['flashrom.quirk'], @@ -7,6 +8,7 @@ shared_module('fu_plugin_flashrom', fu_hash, sources : [ + 'fu-flashrom-device.c', 'fu-plugin-flashrom.c', ], include_directories : [ @@ -29,3 +31,4 @@ libflashrom, ], ) +endif diff -Nru fwupd-1.4.5/plugins/flashrom/README.md fwupd-1.5.8/plugins/flashrom/README.md --- fwupd-1.4.5/plugins/flashrom/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/flashrom/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -17,14 +17,52 @@ * org.flashrom +Coreboot Version String +----------------------- + +The coreboot version string can have an optional prefix (see below). +After the optional prefix the *major*, *minor* string follows and finally +the *build string*, containing the exact commit and repository state, follows. + +For example `4.10-989-gc8a4e4b9c5-dirty` + +**Exception on Lenovo devices:** + +The thinkpad_acpi kernel module requires a specific pattern in the DMI version +string. To satisfy those requirements coreboot adds the CBETxxxx prefix to the +DMI version string on all Lenovo devices. + +For example `CBET4000 4.10-989-gc8a4e4b9c5-dirty` + +The coreboot DMI version string always starts with `CBET`. + GUID Generation --------------- +These device uses hardware ID values which are derived from SMBIOS. + + * HardwareID-3 + * HardwareID-4 + * HardwareID-5 + * HardwareID-6 + * HardwareID-10 + These device uses hardware ID values which are derived from SMBIOS. They should match the values provided by `fwupdtool hwids` or the `ComputerHardwareIds.exe` Windows utility. +Update Behavior +--------------- + +The firmware is deployed to the SPI chip when the machine is in normal runtime +mode, but it is only used when the device is rebooted. + Vendor ID Security ------------------ The vendor ID is set from the BIOS vendor, for example `DMI:Google` + +External interface access +--- +This plugin requires access to all interfaces that `libflashrom` has been compiled for. +This typically is `/sys/bus/spi` but there may be other interfaces as well. diff -Nru fwupd-1.4.5/plugins/fresco-pd/fresco-pd.quirk fwupd-1.5.8/plugins/fresco-pd/fresco-pd.quirk --- fwupd-1.4.5/plugins/fresco-pd/fresco-pd.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/fresco-pd/fresco-pd.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,7 +1,7 @@ # FL7102 -[Guid=USB\VID_1D5C&PID_7102] +[USB\VID_1D5C&PID_7102] Plugin = fresco_pd # FL7112 -[Guid=USB\VID_1D5C&PID_7112] +[USB\VID_1D5C&PID_7112] Plugin = fresco_pd diff -Nru fwupd-1.4.5/plugins/fresco-pd/fu-fresco-pd-device.c fwupd-1.5.8/plugins/fresco-pd/fu-fresco-pd-device.c --- fwupd-1.4.5/plugins/fresco-pd/fu-fresco-pd-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/fresco-pd/fu-fresco-pd-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -203,19 +203,7 @@ guint8 customer_id; g_autoptr(FuFirmware) firmware = fu_fresco_pd_firmware_new (); - /* check size */ - if (g_bytes_get_size (fw) < fu_device_get_firmware_size_min (device)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "firmware too small, got 0x%x, expected >= 0x%x", - (guint) g_bytes_get_size (fw), - (guint) fu_device_get_firmware_size_min (device)); - return NULL; - } - /* check firmware is suitable */ - fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); if (!fu_firmware_parse (firmware, fw, flags, error)) return NULL; customer_id = fu_fresco_pd_firmware_get_customer_id (FU_FRESCO_PD_FIRMWARE (firmware)); @@ -399,7 +387,8 @@ { fu_device_add_icon (FU_DEVICE (self), "audio-card"); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); - fu_device_set_protocol (FU_DEVICE (self), "com.frescologic.pd"); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_protocol (FU_DEVICE (self), "com.frescologic.pd"); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_QUAD); fu_device_set_install_duration (FU_DEVICE (self), 15); fu_device_set_remove_delay (FU_DEVICE (self), 20000); diff -Nru fwupd-1.4.5/plugins/fresco-pd/fu-plugin-fresco-pd.c fwupd-1.5.8/plugins/fresco-pd/fu-plugin-fresco-pd.c --- fwupd-1.4.5/plugins/fresco-pd/fu-plugin-fresco-pd.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/fresco-pd/fu-plugin-fresco-pd.c 2021-03-31 20:08:32.000000000 +0000 @@ -7,7 +7,6 @@ #include "config.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #include "fu-fresco-pd-device.h" #include "fu-fresco-pd-firmware.h" @@ -17,5 +16,5 @@ { fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_set_device_gtype (plugin, FU_TYPE_FRESCO_PD_DEVICE); - fu_plugin_add_firmware_gtype (plugin, "fresco-pd", FU_TYPE_FRESCO_PD_FIRMWARE); + fu_plugin_add_firmware_gtype (plugin, NULL, FU_TYPE_FRESCO_PD_FIRMWARE); } diff -Nru fwupd-1.4.5/plugins/fresco-pd/meson.build fwupd-1.5.8/plugins/fresco-pd/meson.build --- fwupd-1.4.5/plugins/fresco-pd/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/fresco-pd/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,4 @@ +if get_option('gusb') cargs = ['-DG_LOG_DOMAIN="FuPluginFrescoPd"'] install_data(['fresco-pd.quirk'], @@ -28,3 +29,4 @@ plugin_deps, ], ) +endif diff -Nru fwupd-1.4.5/plugins/fresco-pd/README.md fwupd-1.5.8/plugins/fresco-pd/README.md --- fwupd-1.4.5/plugins/fresco-pd/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/fresco-pd/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -29,7 +29,17 @@ * `USB\VID_1D5C&PID_7102&CID_01` +Update Behavior +--------------- + +The firmware is deployed when the device is in normal runtime mode, and the +device will reset when the new firmware has been written. + Vendor ID Security ------------------ The vendor ID is set from the USB vendor, in this instance set to `USB:0x1D5C` + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff -Nru fwupd-1.4.5/plugins/goodix-moc/fu-goodixmoc-common.h fwupd-1.5.8/plugins/goodix-moc/fu-goodixmoc-common.h --- fwupd-1.4.5/plugins/goodix-moc/fu-goodixmoc-common.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/goodix-moc/fu-goodixmoc-common.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2016 Richard Hughes + * Copyright (C) 2020 boger wang + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +/* protocol */ +#define GX_CMD_ACK 0xAA +#define GX_CMD_VERSION 0xD0 +#define GX_CMD_RESET 0xB4 +#define GX_CMD_UPGRADE 0x80 +#define GX_CMD_UPGRADE_INIT 0x00 +#define GX_CMD_UPGRADE_DATA 0x01 +#define GX_CMD1_DEFAULT 0x00 + +#define GX_SIZE_CRC32 4 + +/* type covert */ +#define MAKE_CMD_EX(cmd0, cmd1) ((guint16)(((cmd0) << 8) | (cmd1))) + +typedef struct { + guint8 format[2]; + guint8 fwtype[8]; + guint8 fwversion[8]; + guint8 customer[8]; + guint8 mcu[8]; + guint8 sensor[8]; + guint8 algversion[8]; + guint8 interface[8]; + guint8 protocol[8]; + guint8 flashVersion[8]; + guint8 reserved[62]; +} GxfpVersionInfo; + +typedef struct { + guint8 cmd; + gboolean configured; +} GxfpAckMsg; + +typedef struct { + guint8 result; + union { + GxfpAckMsg ack_msg; + GxfpVersionInfo version_info; + }; +} GxfpCmdResp; + +typedef enum { + GX_PKG_TYPE_NORMAL = 0x80, + GX_PKG_TYPE_EOP = 0, +} GxPkgType; + +typedef struct __attribute__((__packed__)) { + guint8 cmd0; + guint8 cmd1; + guint8 pkg_flag; + guint8 reserved; + guint16 len; + guint8 crc8; + guint8 rev_crc8; +} GxfpPkgHeader; diff -Nru fwupd-1.4.5/plugins/goodix-moc/fu-goodixmoc-device.c fwupd-1.5.8/plugins/goodix-moc/fu-goodixmoc-device.c --- fwupd-1.4.5/plugins/goodix-moc/fu-goodixmoc-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/goodix-moc/fu-goodixmoc-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,433 @@ +/* + * Copyright (C) 2016 Richard Hughes + * Copyright (C) 2020 boger wang + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-chunk.h" + +#include "fu-goodixmoc-common.h" +#include "fu-goodixmoc-device.h" + +struct _FuGoodixMocDevice { + FuUsbDevice parent_instance; + guint8 dummy_seq; +}; + +G_DEFINE_TYPE (FuGoodixMocDevice, fu_goodixmoc_device, FU_TYPE_USB_DEVICE) + +#define GX_USB_BULK_EP_IN (3 | 0x80) +#define GX_USB_BULK_EP_OUT (1 | 0x00) +#define GX_USB_INTERFACE 0 + +#define GX_USB_DATAIN_TIMEOUT 2000 /* ms */ +#define GX_USB_DATAOUT_TIMEOUT 200 /* ms */ +#define GX_FLASH_TRANSFER_BLOCK_SIZE 1000 /* 1000 */ + +static gboolean +goodixmoc_device_cmd_send (FuGoodixMocDevice *self, + guint8 cmd0, + guint8 cmd1, + GxPkgType type, + GByteArray *req, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + guint32 crc_all = 0; + guint32 crc_hdr = 0; + gsize actual_len = 0; + g_autoptr(GByteArray) buf = g_byte_array_new (); + + /* build header */ + fu_byte_array_append_uint8 (buf, cmd0); + fu_byte_array_append_uint8 (buf, cmd1); + fu_byte_array_append_uint8 (buf, type); /* pkg_flag */ + fu_byte_array_append_uint8 (buf, self->dummy_seq++); /* reserved */ + fu_byte_array_append_uint16 (buf, req->len + GX_SIZE_CRC32, G_LITTLE_ENDIAN); + crc_hdr = fu_common_crc8 (buf->data, buf->len); + fu_byte_array_append_uint8 (buf, crc_hdr); + fu_byte_array_append_uint8 (buf, ~crc_hdr); + g_byte_array_append (buf, req->data, req->len); + crc_all = fu_common_crc32 (buf->data, buf->len); + fu_byte_array_append_uint32 (buf, crc_all, G_LITTLE_ENDIAN); + + /* send zero length package */ + if (!g_usb_device_bulk_transfer (usb_device, + GX_USB_BULK_EP_OUT, + NULL, + 0, + NULL, + GX_USB_DATAOUT_TIMEOUT, NULL, error)) { + g_prefix_error (error, "failed to req: "); + return FALSE; + } + if (g_getenv ("FWUPD_GOODIXFP_VERBOSE") != NULL) { + fu_common_dump_full (G_LOG_DOMAIN, "REQST", + buf->data, buf->len, 16, + FU_DUMP_FLAGS_SHOW_ADDRESSES); + } + + /* send data */ + if (!g_usb_device_bulk_transfer (usb_device, + GX_USB_BULK_EP_OUT, + buf->data, + buf->len, + &actual_len, + GX_USB_DATAOUT_TIMEOUT, NULL, error)) { + g_prefix_error (error, "failed to req: "); + return FALSE; + } + if (actual_len != buf->len) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "invalid length"); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +goodixmoc_device_cmd_recv (FuGoodixMocDevice *self, + GxfpCmdResp *presponse, + gboolean data_reply, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + guint32 crc_actual = 0; + guint32 crc_calculated = 0; + gsize actual_len = 0; + gsize offset = 0; + + g_return_val_if_fail (presponse != NULL, FALSE); + + /* + * package format + * | zlp | ack | zlp | data | + */ + while (1) { + guint16 header_len = 0x0; + guint8 header_cmd0 = 0x0; + g_autoptr(GByteArray) reply = g_byte_array_new (); + fu_byte_array_set_size (reply, GX_FLASH_TRANSFER_BLOCK_SIZE); + if (!g_usb_device_bulk_transfer (usb_device, + GX_USB_BULK_EP_IN, + reply->data, + reply->len, + &actual_len, /* allowed to return short read */ + GX_USB_DATAIN_TIMEOUT, + NULL, error)) { + g_prefix_error (error, "failed to reply: "); + return FALSE; + } + + /* receive zero length package */ + if (actual_len == 0) + continue; + if (g_getenv ("FWUPD_GOODIXFP_VERBOSE") != NULL) { + fu_common_dump_full (G_LOG_DOMAIN, "REPLY", + reply->data, actual_len, 16, + FU_DUMP_FLAGS_SHOW_ADDRESSES); + } + + /* parse package header */ + if (!fu_common_read_uint8_safe (reply->data, reply->len, 0x0, + &header_cmd0, error)) + return FALSE; + if (!fu_common_read_uint16_safe (reply->data, reply->len, 0x4, + &header_len, G_LITTLE_ENDIAN, + error)) + return FALSE; + offset = sizeof(GxfpPkgHeader) + header_len - GX_SIZE_CRC32; + crc_actual = fu_common_crc32 (reply->data, offset); + if (!fu_common_read_uint32_safe (reply->data, + reply->len, + offset, + &crc_calculated, + G_LITTLE_ENDIAN, + error)) + return FALSE; + if (crc_actual != crc_calculated) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "invalid checksum, got 0x%x, expected 0x%x", + crc_calculated, crc_actual); + return FALSE; + } + + /* parse package data */ + if (!fu_common_read_uint8_safe (reply->data, reply->len, + sizeof(GxfpPkgHeader) + 0x00, + &presponse->result, error)) + return FALSE; + if (header_cmd0 == GX_CMD_ACK) { + if (header_len == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "invalid bufsz"); + return FALSE; + } + if (!fu_common_read_uint8_safe (reply->data, reply->len, + sizeof(GxfpPkgHeader) + 0x01, + &presponse->ack_msg.cmd, error)) + return FALSE; + } else if (header_cmd0 == GX_CMD_VERSION) { + if (!fu_memcpy_safe ((guint8 *) &presponse->version_info, + sizeof(presponse->version_info), 0x0, /* dst */ + reply->data, reply->len, + sizeof(GxfpPkgHeader) + 0x01, /* src */ + sizeof(GxfpVersionInfo), error)) + return FALSE; + } + + /* continue after ack received */ + if (header_cmd0 == GX_CMD_ACK && data_reply) + continue; + break; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_goodixmoc_device_cmd_xfer (FuGoodixMocDevice *device, + guint8 cmd0, + guint8 cmd1, + GxPkgType type, + GByteArray *req, + GxfpCmdResp *presponse, + gboolean data_reply, + GError **error) +{ + FuGoodixMocDevice *self = FU_GOODIXMOC_DEVICE(device); + if (!goodixmoc_device_cmd_send (self, cmd0, cmd1, type, req, error)) + return FALSE; + return goodixmoc_device_cmd_recv (self, presponse, data_reply, error); +} + +static gboolean +fu_goodixmoc_device_setup_version (FuGoodixMocDevice *self, GError **error) +{ + GxfpCmdResp rsp = { 0 }; + g_autofree gchar *version = NULL; + g_autoptr(GByteArray) req = g_byte_array_new (); + + fu_byte_array_append_uint8 (req, 0); /* dummy */ + if (!fu_goodixmoc_device_cmd_xfer (self, GX_CMD_VERSION, GX_CMD1_DEFAULT, + GX_PKG_TYPE_EOP, req, &rsp, TRUE, error)) + return FALSE; + version = g_strndup ((const gchar *) rsp.version_info.fwversion, + sizeof(rsp.version_info.fwversion)); + fu_device_set_version (FU_DEVICE (self), version); + return TRUE; +} + +static gboolean +fu_goodixmoc_device_update_init (FuGoodixMocDevice *self, GError **error) +{ + GxfpCmdResp rsp = { 0 }; + g_autoptr(GByteArray) req = g_byte_array_new (); + + /* update initial */ + if (!fu_goodixmoc_device_cmd_xfer (self, GX_CMD_UPGRADE, GX_CMD_UPGRADE_INIT, + GX_PKG_TYPE_EOP, + req, + &rsp, + TRUE, + error)) { + g_prefix_error (error, "failed to send initial update: "); + return FALSE; + } + + /* check result */ + if (rsp.result != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "initial update failed [0x%x]", + rsp.result); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_goodixmoc_device_attach (FuDevice *device, GError **error) +{ + FuGoodixMocDevice *self = FU_GOODIXMOC_DEVICE(device); + GxfpCmdResp rsp = { 0 }; + g_autoptr(GByteArray) req = g_byte_array_new (); + + /* reset device */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + if (!fu_goodixmoc_device_cmd_xfer (self, GX_CMD_RESET, 0x03, + GX_PKG_TYPE_EOP, + req, + &rsp, + FALSE, + error)) { + g_prefix_error (error, "failed to send reset device: "); + return FALSE; + } + + /* check result */ + if (rsp.result != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "failed to reset device [0x%x]", + rsp.result); + return FALSE; + } + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + return TRUE; +} + +static gboolean +fu_goodixmoc_device_open (FuDevice *device, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + + /* FuUsbDevice->open */ + if (!FU_DEVICE_CLASS (fu_goodixmoc_device_parent_class)->open (device, error)) + return FALSE; + + return g_usb_device_claim_interface (usb_device, GX_USB_INTERFACE, + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + error); +} + +static gboolean +fu_goodixmoc_device_setup (FuDevice *device, GError **error) +{ + FuGoodixMocDevice *self = FU_GOODIXMOC_DEVICE (device); + + /* ensure version */ + if (!fu_goodixmoc_device_setup_version (self, error)) { + g_prefix_error (error, "failed to get firmware version: "); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_goodixmoc_device_write_firmware (FuDevice *device, + FuFirmware *firmware, + FwupdInstallFlags flags, + GError **error) +{ + FuGoodixMocDevice *self = FU_GOODIXMOC_DEVICE(device); + GxPkgType pkg_eop = GX_PKG_TYPE_NORMAL; + GxfpCmdResp rsp = { 0 }; + gboolean wait_data_reply = FALSE; + g_autoptr(GBytes) fw = NULL; + g_autoptr(GError) error_local = NULL; + g_autoptr(GPtrArray) chunks = NULL; + + /* get default image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + + /* build packets */ + chunks = fu_chunk_array_new_from_bytes (fw, + 0x00, + 0x00, /* page_sz */ + GX_FLASH_TRANSFER_BLOCK_SIZE); + + /* don't auto-boot firmware */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + if (!fu_goodixmoc_device_update_init (self, &error_local)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "failed to initial update: %s", + error_local->message); + return FALSE; + } + + /* write each block */ + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + g_autoptr(GByteArray) req = g_byte_array_new (); + g_autoptr(GError) error_block = NULL; + + g_byte_array_append (req, + fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk)); + + /* the last chunk */ + if (i == chunks->len - 1) { + wait_data_reply = TRUE; + pkg_eop = GX_PKG_TYPE_EOP; + } + if (!fu_goodixmoc_device_cmd_xfer (self, + GX_CMD_UPGRADE, + GX_CMD_UPGRADE_DATA, + pkg_eop, + req, + &rsp, + wait_data_reply, + &error_block)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "failed to write: %s", + error_block->message); + return FALSE; + } + + /* check update status */ + if (wait_data_reply && rsp.result != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "failed to verify firmware [0x%x]", + rsp.result); + return FALSE; + } + + /* update progress */ + fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len); + } + + /* success! */ + return TRUE; +} + +static void +fu_goodixmoc_device_init (FuGoodixMocDevice *self) +{ + fu_device_add_flag (FU_DEVICE(self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_flag (FU_DEVICE(self), FWUPD_DEVICE_FLAG_SELF_RECOVERY); + fu_device_add_flag (FU_DEVICE(self), FWUPD_DEVICE_FLAG_USE_RUNTIME_VERSION); + fu_device_set_version_format (FU_DEVICE(self), FWUPD_VERSION_FORMAT_PLAIN); + fu_device_set_remove_delay (FU_DEVICE(self), 5000); + fu_device_add_protocol (FU_DEVICE (self), "com.goodix.goodixmoc"); + fu_device_set_name (FU_DEVICE(self), "Fingerprint Sensor"); + fu_device_set_summary (FU_DEVICE(self), "Match-On-Chip Fingerprint Sensor"); + fu_device_set_vendor (FU_DEVICE(self), "Goodix"); + fu_device_set_install_duration (FU_DEVICE(self), 10); + fu_device_set_firmware_size_min (FU_DEVICE(self), 0x20000); + fu_device_set_firmware_size_max (FU_DEVICE(self), 0x30000); +} + +static void +fu_goodixmoc_device_class_init(FuGoodixMocDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS(klass); + klass_device->write_firmware = fu_goodixmoc_device_write_firmware; + klass_device->setup = fu_goodixmoc_device_setup; + klass_device->attach = fu_goodixmoc_device_attach; + klass_device->open = fu_goodixmoc_device_open; +} diff -Nru fwupd-1.4.5/plugins/goodix-moc/fu-goodixmoc-device.h fwupd-1.5.8/plugins/goodix-moc/fu-goodixmoc-device.h --- fwupd-1.4.5/plugins/goodix-moc/fu-goodixmoc-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/goodix-moc/fu-goodixmoc-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2016 Richard Hughes + * Copyright (C) 2020 boger wang + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +#define FU_TYPE_GOODIXMOC_DEVICE (fu_goodixmoc_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuGoodixMocDevice, fu_goodixmoc_device, FU, GOODIXMOC_DEVICE, FuUsbDevice) diff -Nru fwupd-1.4.5/plugins/goodix-moc/fu-plugin-goodixmoc.c fwupd-1.5.8/plugins/goodix-moc/fu-plugin-goodixmoc.c --- fwupd-1.4.5/plugins/goodix-moc/fu-plugin-goodixmoc.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/goodix-moc/fu-plugin-goodixmoc.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2015 Richard Hughes + * Copyright (C) 2020 boger wang + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" +#include "fu-goodixmoc-device.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_set_device_gtype (plugin, FU_TYPE_GOODIXMOC_DEVICE); +} diff -Nru fwupd-1.4.5/plugins/goodix-moc/goodixmoc.quirk fwupd-1.5.8/plugins/goodix-moc/goodixmoc.quirk --- fwupd-1.4.5/plugins/goodix-moc/goodixmoc.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/goodix-moc/goodixmoc.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,13 @@ +# Goodix Fingerprint sensor +[USB\VID_27C6&PID_60A2] +Plugin = goodixmoc +[USB\VID_27C6&PID_6384] +Plugin = goodixmoc +[USB\VID_27C6&PID_639C] +Plugin = goodixmoc +[USB\VID_27C6&PID_63AC] +Plugin = goodixmoc +[USB\VID_27C6&PID_6594] +Plugin = goodixmoc +[USB\VID_27C6&PID_6496] +Plugin = goodixmoc diff -Nru fwupd-1.4.5/plugins/goodix-moc/meson.build fwupd-1.5.8/plugins/goodix-moc/meson.build --- fwupd-1.4.5/plugins/goodix-moc/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/goodix-moc/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,32 @@ +if get_option('gusb') +cargs = ['-DG_LOG_DOMAIN="FuPluginGoodixMoc"'] + +install_data([ + 'goodixmoc.quirk', + ], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_goodixmoc', + fu_hash, + sources : [ + 'fu-goodixmoc-device.c', + 'fu-plugin-goodixmoc.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) +endif diff -Nru fwupd-1.4.5/plugins/goodix-moc/README.md fwupd-1.5.8/plugins/goodix-moc/README.md --- fwupd-1.4.5/plugins/goodix-moc/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/goodix-moc/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,41 @@ +Goodix Fingerprint Sensor Support +================================= + +Introduction +------------ + +The plugin used for update firmware for fingerprint sensors from Goodix. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +a packed binary file format. + +This plugin supports the following protocol ID: + + * com.goodix.goodixmoc + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_27C6&PID_6001&REV_0001` + * `USB\VID_27C6&PID_6001` + * `USB\VID_27C6` + +Update Behavior +--------------- + +The firmware is deployed when the device is in normal runtime mode, and the +device will reset when the new firmware has been written. + +Vendor ID Security +------------------ + +The vendor ID is set from the USB vendor, in this instance set to `USB:0x27C6` + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff -Nru fwupd-1.4.5/plugins/hailuck/data/lspci-bl.txt fwupd-1.5.8/plugins/hailuck/data/lspci-bl.txt --- fwupd-1.4.5/plugins/hailuck/data/lspci-bl.txt 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/hailuck/data/lspci-bl.txt 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,47 @@ +Bus 003 Device 003: ID 0603:1020 Novatek Microelectronics Corp. +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 1.10 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 8 + idVendor 0x0603 Novatek Microelectronics Corp. + idProduct 0x1020 + bcdDevice 3.01 + iManufacturer 0 + iProduct 0 + iSerial 0 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0022 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0xa0 + (Bus Powered) + Remote Wakeup + MaxPower 100mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 3 Human Interface Device + bInterfaceSubClass 1 Boot Interface Subclass + bInterfaceProtocol 1 Keyboard + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0008 1x 8 bytes + bInterval 10 diff -Nru fwupd-1.4.5/plugins/hailuck/data/lspci.txt fwupd-1.5.8/plugins/hailuck/data/lspci.txt --- fwupd-1.4.5/plugins/hailuck/data/lspci.txt 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/hailuck/data/lspci.txt 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,89 @@ +Bus 003 Device 008: ID 258a:001e HAILUCK CO.,LTD USB KEYBOARD +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 1.10 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 8 + idVendor 0x258a + idProduct 0x001e + bcdDevice 1.00 + iManufacturer 1 HAILUCK CO.,LTD + iProduct 2 USB KEYBOARD + iSerial 0 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x003b + bNumInterfaces 2 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0xa0 + (Bus Powered) + Remote Wakeup + MaxPower 100mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 3 Human Interface Device + bInterfaceSubClass 1 Boot Interface Subclass + bInterfaceProtocol 1 Keyboard + iInterface 0 + HID Device Descriptor: + bLength 9 + bDescriptorType 33 + bcdHID 1.10 + bCountryCode 0 Not supported + bNumDescriptors 1 + bDescriptorType 34 Report + wDescriptorLength 65 + Report Descriptors: + ** UNAVAILABLE ** + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0008 1x 8 bytes + bInterval 10 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 3 Human Interface Device + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 0 + HID Device Descriptor: + bLength 9 + bDescriptorType 33 + bcdHID 1.10 + bCountryCode 0 Not supported + bNumDescriptors 1 + bDescriptorType 34 Report + wDescriptorLength 487 + Report Descriptors: + ** UNAVAILABLE ** + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0008 1x 8 bytes + bInterval 10 +Device Status: 0x0000 + (Bus Powered) diff -Nru fwupd-1.4.5/plugins/hailuck/fu-hailuck-bl-device.c fwupd-1.5.8/plugins/hailuck/fu-hailuck-bl-device.c --- fwupd-1.4.5/plugins/hailuck/fu-hailuck-bl-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/hailuck/fu-hailuck-bl-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-chunk.h" +#include "fu-hailuck-common.h" +#include "fu-hailuck-bl-device.h" +#include "fu-hailuck-kbd-firmware.h" + +struct _FuHailuckBlDevice { + FuHidDevice parent_instance; +}; + +G_DEFINE_TYPE (FuHailuckBlDevice, fu_hailuck_bl_device, FU_TYPE_HID_DEVICE) + +static gboolean +fu_hailuck_bl_device_attach (FuDevice *device, GError **error) +{ + guint8 buf[6] = { + FU_HAILUCK_REPORT_ID_SHORT, + FU_HAILUCK_CMD_ATTACH, + }; + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + if (!fu_hid_device_set_report (FU_HID_DEVICE (device), + buf[0], buf, sizeof(buf), 1000, + FU_HID_DEVICE_FLAG_IS_FEATURE, error)) + return FALSE; + if (!g_usb_device_reset (fu_usb_device_get_dev (FU_USB_DEVICE (device)), error)) + return FALSE; + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + return TRUE; +} + +static gboolean +fu_hailuck_bl_device_probe (FuDevice *device, GError **error) +{ + g_autofree gchar *devid = NULL; + + /* FuUsbDevice->probe */ + if (!FU_DEVICE_CLASS (fu_hailuck_bl_device_parent_class)->probe (device, error)) + return FALSE; + + /* add extra keyboard-specific GUID */ + devid = g_strdup_printf ("USB\\VID_%04X&PID_%04X&MODE_KBD", + fu_usb_device_get_vid (FU_USB_DEVICE (device)), + fu_usb_device_get_pid (FU_USB_DEVICE (device))); + fu_device_add_instance_id (device, devid); + + /* success */ + return TRUE; +} + +static gboolean +fu_hailuck_bl_device_read_block_start (FuHailuckBlDevice *self, + guint32 length, + GError **error) +{ + guint8 buf[6] = { + FU_HAILUCK_REPORT_ID_SHORT, + FU_HAILUCK_CMD_READ_BLOCK_START, + }; + fu_common_write_uint16 (buf + 4, length, G_LITTLE_ENDIAN); + return fu_hid_device_set_report (FU_HID_DEVICE (self), buf[0], + buf, sizeof(buf), 100, + FU_HID_DEVICE_FLAG_IS_FEATURE, error); +} + +static gboolean +fu_hailuck_bl_device_read_block (FuHailuckBlDevice *self, + guint8 *data, gsize data_sz, + GError **error) +{ + gsize bufsz = data_sz + 2; + g_autofree guint8 *buf = g_malloc0 (bufsz); + + buf[0] = FU_HAILUCK_REPORT_ID_LONG; + buf[1] = FU_HAILUCK_CMD_READ_BLOCK; + if (!fu_hid_device_get_report (FU_HID_DEVICE (self), buf[0], + buf, bufsz, 2000, + FU_HID_DEVICE_FLAG_IS_FEATURE, + error)) + return FALSE; + if (!fu_memcpy_safe (data, data_sz, 0x0, /* dst */ + buf, bufsz, 0x02, /* src */ + data_sz, error)) + return FALSE; + + /* success */ + g_usleep (10000); + return TRUE; +} + +static GBytes * +fu_hailuck_bl_device_dump_firmware (FuDevice *device, GError **error) +{ + FuHailuckBlDevice *self = FU_HAILUCK_BL_DEVICE (device); + gsize fwsz = fu_device_get_firmware_size_max (device); + g_autoptr(GByteArray) fwbuf = g_byte_array_new (); + g_autoptr(GPtrArray) chunks = NULL; + + /* tell device amount of data to send */ + fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_READ); + if (!fu_hailuck_bl_device_read_block_start (self, fwsz, error)) + return NULL; + + /* recieve data back */ + fu_byte_array_set_size (fwbuf, fwsz); + chunks = fu_chunk_array_mutable_new (fwbuf->data, fwbuf->len, 0x0, 0x0, 2048); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + if (!fu_hailuck_bl_device_read_block (self, + fu_chunk_get_data_out (chk), + fu_chunk_get_data_sz (chk), + error)) + return NULL; + fu_device_set_progress_full (device, i, chunks->len - 1); + } + + /* success */ + return g_byte_array_free_to_bytes (g_steal_pointer (&fwbuf)); +} + +static gboolean +fu_hailuck_bl_device_erase (FuHailuckBlDevice *self, GError **error) +{ + guint8 buf[6] = { + FU_HAILUCK_REPORT_ID_SHORT, + FU_HAILUCK_CMD_ERASE, + }; + if (!fu_hid_device_set_report (FU_HID_DEVICE (self), buf[0], + buf, sizeof(buf), 100, + FU_HID_DEVICE_FLAG_IS_FEATURE, error)) + return FALSE; + fu_device_sleep_with_progress (FU_DEVICE (self), 2); + return TRUE; +} + +static gboolean +fu_hailuck_bl_device_write_block_start (FuHailuckBlDevice *self, + guint32 length, GError **error) +{ + guint8 buf[6] = { + FU_HAILUCK_REPORT_ID_SHORT, + FU_HAILUCK_CMD_WRITE_BLOCK_START, + }; + fu_common_write_uint16 (buf + 4, length, G_LITTLE_ENDIAN); + return fu_hid_device_set_report (FU_HID_DEVICE (self), buf[0], + buf, sizeof(buf), 100, + FU_HID_DEVICE_FLAG_IS_FEATURE, error); +} + +static gboolean +fu_hailuck_bl_device_write_block (FuHailuckBlDevice *self, + const guint8 *data, gsize data_sz, + GError **error) +{ + gsize bufsz = data_sz + 2; + g_autofree guint8 *buf = g_malloc0 (bufsz); + + buf[0] = FU_HAILUCK_REPORT_ID_LONG; + buf[1] = FU_HAILUCK_CMD_WRITE_BLOCK; + if (!fu_memcpy_safe (buf, bufsz, 0x02, /* dst */ + data, data_sz, 0x0, /* src */ + data_sz, error)) + return FALSE; + if (!fu_hid_device_set_report (FU_HID_DEVICE (self), buf[0], + buf, bufsz, 2000, + FU_HID_DEVICE_FLAG_IS_FEATURE, + error)) + return FALSE; + + /* success */ + g_usleep (10000); + return TRUE; +} + +static FuFirmware * +fu_hailuck_bl_device_prepare_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuFirmware) firmware = fu_hailuck_kbd_firmware_new (); + if (!fu_firmware_parse (firmware, fw, flags, error)) + return NULL; + return g_steal_pointer (&firmware); +} + +static gboolean +fu_hailuck_bl_device_write_firmware (FuDevice *device, + FuFirmware *firmware, + FwupdInstallFlags flags, + GError **error) +{ + FuHailuckBlDevice *self = FU_HAILUCK_BL_DEVICE (device); + FuChunk *chk0; + g_autoptr(GBytes) fw = NULL; + g_autoptr(GBytes) fw_new = NULL; + g_autoptr(GPtrArray) chunks = NULL; + g_autofree guint8 *chk0_data = NULL; + + /* get default image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + + /* erase all contents */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE); + if (!fu_hailuck_bl_device_erase (self, error)) + return FALSE; + + /* tell device amount of data to expect */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + if (!fu_hailuck_bl_device_write_block_start (self, g_bytes_get_size (fw), error)) + return FALSE; + + /* build packets */ + chunks = fu_chunk_array_new_from_bytes (fw, 0x0, 0x00, 2048); + + /* intentionally corrupt first chunk so that CRC fails */ + chk0 = g_ptr_array_index (chunks, 0); + chk0_data = fu_memdup_safe (fu_chunk_get_data (chk0), + fu_chunk_get_data_sz (chk0), + error); + if (chk0_data == NULL) + return FALSE; + chk0_data[0] = 0x00; + if (!fu_hailuck_bl_device_write_block (self, + chk0_data, + fu_chunk_get_data_sz (chk0), + error)) + return FALSE; + + /* send the rest of the chunks */ + for (guint i = 1; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + if (!fu_hailuck_bl_device_write_block (self, + fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk), + error)) + return FALSE; + fu_device_set_progress_full (device, i, chunks->len); + } + + /* retry write of first block */ + if (!fu_hailuck_bl_device_write_block_start (self, g_bytes_get_size (fw), error)) + return FALSE; + if (!fu_hailuck_bl_device_write_block (self, + fu_chunk_get_data (chk0), + fu_chunk_get_data_sz (chk0), + error)) + return FALSE; + fu_device_set_progress_full (device, chunks->len, chunks->len); + + /* verify */ + fw_new = fu_hailuck_bl_device_dump_firmware (device, error); + return fu_common_bytes_compare (fw, fw_new, error); +} + +static void +fu_hailuck_bl_device_init (FuHailuckBlDevice *self) +{ + fu_device_set_firmware_size (FU_DEVICE (self), 0x4000); + fu_device_add_protocol (FU_DEVICE (self), "com.hailuck.kbd"); + fu_device_set_name (FU_DEVICE (self), "Keyboard [bootloader]"); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_internal_flag (FU_DEVICE (self), FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID); + fu_device_add_icon (FU_DEVICE (self), "input-keyboard"); + fu_hid_device_add_flag (FU_HID_DEVICE (self), FU_HID_DEVICE_FLAG_NO_KERNEL_REBIND); + fu_device_set_remove_delay (FU_DEVICE (self), + FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); +} + +static void +fu_hailuck_bl_device_class_init (FuHailuckBlDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + klass_device->dump_firmware = fu_hailuck_bl_device_dump_firmware; + klass_device->prepare_firmware = fu_hailuck_bl_device_prepare_firmware; + klass_device->write_firmware = fu_hailuck_bl_device_write_firmware; + klass_device->attach = fu_hailuck_bl_device_attach; + klass_device->probe = fu_hailuck_bl_device_probe; +} diff -Nru fwupd-1.4.5/plugins/hailuck/fu-hailuck-bl-device.h fwupd-1.5.8/plugins/hailuck/fu-hailuck-bl-device.h --- fwupd-1.4.5/plugins/hailuck/fu-hailuck-bl-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/hailuck/fu-hailuck-bl-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" +#include "fu-hid-device.h" + +#define FU_TYPE_HAILUCK_BL_DEVICE (fu_hailuck_bl_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuHailuckBlDevice, fu_hailuck_bl_device, FU, HAILUCK_BL_DEVICE, FuHidDevice) diff -Nru fwupd-1.4.5/plugins/hailuck/fu-hailuck-common.c fwupd-1.5.8/plugins/hailuck/fu-hailuck-common.c --- fwupd-1.4.5/plugins/hailuck/fu-hailuck-common.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/hailuck/fu-hailuck-common.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-hailuck-common.h" + +const gchar * +fu_hailuck_cmd_to_string (guint8 cmd) +{ + if (cmd == FU_HAILUCK_CMD_ERASE) + return "erase"; + if (cmd == FU_HAILUCK_CMD_READ_BLOCK_START) + return "read-block-start"; + if (cmd == FU_HAILUCK_CMD_WRITE_BLOCK_START) + return "write-block-start"; + if (cmd == FU_HAILUCK_CMD_READ_BLOCK) + return "read-block"; + if (cmd == FU_HAILUCK_CMD_WRITE_BLOCK) + return "write-block"; + if (cmd == FU_HAILUCK_CMD_GET_STATUS) + return "get-status"; + if (cmd == FU_HAILUCK_CMD_DETACH) + return "detach"; + if (cmd == FU_HAILUCK_CMD_ATTACH) + return "attach"; + if (cmd == FU_HAILUCK_CMD_WRITE_TP) + return "write-tp"; + if (cmd == FU_HAILUCK_CMD_I2C_CHECK_CHECKSUM) + return "i2c-check-checksum"; + if (cmd == FU_HAILUCK_CMD_I2C_ENTER_BL) + return "i2c-enter-bl"; + if (cmd == FU_HAILUCK_CMD_I2C_ERASE) + return "i2c-erase"; + if (cmd == FU_HAILUCK_CMD_I2C_PROGRAM) + return "i2c-program"; + if (cmd == FU_HAILUCK_CMD_I2C_VERIFY_BLOCK) + return "i2c-verify-block"; + if (cmd == FU_HAILUCK_CMD_I2C_VERIFY_CHECKSUM) + return "i2c-verify-checksum"; + if (cmd == FU_HAILUCK_CMD_I2C_PROGRAMPASS) + return "i2c-programpass"; + if (cmd == FU_HAILUCK_CMD_I2C_END_PROGRAM) + return "i2c-end-program"; + return NULL; +} diff -Nru fwupd-1.4.5/plugins/hailuck/fu-hailuck-common.h fwupd-1.5.8/plugins/hailuck/fu-hailuck-common.h --- fwupd-1.4.5/plugins/hailuck/fu-hailuck-common.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/hailuck/fu-hailuck-common.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#define FU_HAILUCK_REPORT_ID_SHORT 0x05 +#define FU_HAILUCK_REPORT_ID_LONG 0x06 + +#define FU_HAILUCK_CMD_ERASE 0x45 +#define FU_HAILUCK_CMD_READ_BLOCK_START 0x52 +#define FU_HAILUCK_CMD_ATTACH 0x55 /* guessed */ +#define FU_HAILUCK_CMD_WRITE_BLOCK_START 0x57 +#define FU_HAILUCK_CMD_READ_BLOCK 0x72 +#define FU_HAILUCK_CMD_DETACH 0x75 /* guessed */ +#define FU_HAILUCK_CMD_WRITE_BLOCK 0x77 +#define FU_HAILUCK_CMD_GET_STATUS 0xA1 +#define FU_HAILUCK_CMD_WRITE_TP 0xD0 /* guessed */ +#define FU_HAILUCK_CMD_I2C_CHECK_CHECKSUM 0xF0 +#define FU_HAILUCK_CMD_I2C_ENTER_BL 0xF1 +#define FU_HAILUCK_CMD_I2C_ERASE 0xF2 +#define FU_HAILUCK_CMD_I2C_PROGRAM 0xF3 +#define FU_HAILUCK_CMD_I2C_VERIFY_BLOCK 0xF4 +#define FU_HAILUCK_CMD_I2C_VERIFY_CHECKSUM 0xF5 +#define FU_HAILUCK_CMD_I2C_PROGRAMPASS 0xF6 +#define FU_HAILUCK_CMD_I2C_END_PROGRAM 0xF7 + +const gchar *fu_hailuck_cmd_to_string (guint8 cmd); diff -Nru fwupd-1.4.5/plugins/hailuck/fu-hailuck-kbd-device.c fwupd-1.5.8/plugins/hailuck/fu-hailuck-kbd-device.c --- fwupd-1.4.5/plugins/hailuck/fu-hailuck-kbd-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/hailuck/fu-hailuck-kbd-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-hailuck-common.h" +#include "fu-hailuck-kbd-device.h" +#include "fu-hailuck-tp-device.h" + +struct _FuHailuckKbdDevice { + FuHidDevice parent_instance; +}; + +G_DEFINE_TYPE (FuHailuckKbdDevice, fu_hailuck_kbd_device, FU_TYPE_HID_DEVICE) + +static gboolean +fu_hailuck_kbd_device_detach (FuDevice *device, GError **error) +{ + guint8 buf[6] = { + FU_HAILUCK_REPORT_ID_SHORT, + FU_HAILUCK_CMD_DETACH + }; + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + if (!fu_hid_device_set_report (FU_HID_DEVICE (device), + buf[0], buf, sizeof(buf), 1000, + FU_HID_DEVICE_FLAG_IS_FEATURE, error)) + return FALSE; + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + return TRUE; +} + +static gboolean +fu_hailuck_kbd_device_probe (FuDevice *device, GError **error) +{ + g_autofree gchar *devid = NULL; + g_autoptr(FuHailuckTpDevice) tp_device = fu_hailuck_tp_device_new (FU_DEVICE (device)); + + /* FuUsbDevice->probe */ + if (!FU_DEVICE_CLASS (fu_hailuck_kbd_device_parent_class)->probe (device, error)) + return FALSE; + + /* add extra keyboard-specific GUID */ + devid = g_strdup_printf ("USB\\VID_%04X&PID_%04X&MODE_KBD", + fu_usb_device_get_vid (FU_USB_DEVICE (device)), + fu_usb_device_get_pid (FU_USB_DEVICE (device))); + fu_device_add_instance_id (device, devid); + + /* add touchpad */ + if (!fu_device_probe (FU_DEVICE (tp_device), error)) + return FALSE; + + /* assume the TP has the same version as the keyboard */ + fu_device_set_version (FU_DEVICE (tp_device), + fu_device_get_version (device)); + fu_device_set_version_format (FU_DEVICE (tp_device), + fu_device_get_version_format (device)); + fu_device_add_child (device, FU_DEVICE (tp_device)); + + /* success */ + return TRUE; +} + +static void +fu_hailuck_kbd_device_init (FuHailuckKbdDevice *self) +{ + fu_device_set_firmware_size (FU_DEVICE (self), 0x4000); + fu_device_add_protocol (FU_DEVICE (self), "com.hailuck.kbd"); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_internal_flag (FU_DEVICE (self), FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID); + fu_device_add_icon (FU_DEVICE (self), "input-keyboard"); + fu_hid_device_set_interface (FU_HID_DEVICE (self), 0x1); + fu_device_set_remove_delay (FU_DEVICE (self), + FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); +} + +static void +fu_hailuck_kbd_device_class_init (FuHailuckKbdDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + klass_device->detach = fu_hailuck_kbd_device_detach; + klass_device->probe = fu_hailuck_kbd_device_probe; +} diff -Nru fwupd-1.4.5/plugins/hailuck/fu-hailuck-kbd-device.h fwupd-1.5.8/plugins/hailuck/fu-hailuck-kbd-device.h --- fwupd-1.4.5/plugins/hailuck/fu-hailuck-kbd-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/hailuck/fu-hailuck-kbd-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" +#include "fu-hid-device.h" + +#define FU_TYPE_HAILUCK_KBD_DEVICE (fu_hailuck_kbd_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuHailuckKbdDevice, fu_hailuck_kbd_device, FU, HAILUCK_KBD_DEVICE, FuHidDevice) diff -Nru fwupd-1.4.5/plugins/hailuck/fu-hailuck-kbd-firmware.c fwupd-1.5.8/plugins/hailuck/fu-hailuck-kbd-firmware.c --- fwupd-1.4.5/plugins/hailuck/fu-hailuck-kbd-firmware.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/hailuck/fu-hailuck-kbd-firmware.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-common.h" + +#include "fu-hailuck-kbd-firmware.h" + +struct _FuHailuckKbdFirmware { + FuIhexFirmwareClass parent_instance; +}; + +G_DEFINE_TYPE (FuHailuckKbdFirmware, fu_hailuck_kbd_firmware, FU_TYPE_IHEX_FIRMWARE) + +static gboolean +fu_hailuck_kbd_firmware_parse (FuFirmware *firmware, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error) +{ + GPtrArray *records = fu_ihex_firmware_get_records (FU_IHEX_FIRMWARE (firmware)); + g_autoptr(FuFirmwareImage) img = NULL; + g_autoptr(GByteArray) buf = g_byte_array_new (); + g_autoptr(GBytes) fw_new = NULL; + + for (guint j = 0; j < records->len; j++) { + FuIhexFirmwareRecord *rcd = g_ptr_array_index (records, j); + if (rcd->record_type == FU_IHEX_FIRMWARE_RECORD_TYPE_EOF) + break; + if (rcd->record_type != FU_IHEX_FIRMWARE_RECORD_TYPE_DATA) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "only record 0x0 supported, got 0x%02x", + rcd->record_type); + return FALSE; + } + if (rcd->data->len == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "record 0x%x had zero size", j); + return FALSE; + } + if (rcd->addr + rcd->data->len > buf->len) { + if (rcd->addr + rcd->data->len == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "buffer would have zero size"); + return FALSE; + } + fu_byte_array_set_size (buf, rcd->addr + rcd->data->len); + } + if (!fu_memcpy_safe (buf->data, buf->len, rcd->addr, + rcd->data->data, rcd->data->len, 0x0, + rcd->data->len, error)) + return FALSE; + } + + /* set the main function executed on system init */ + if (buf->len > 0x37FD && buf->data[1] == 0x38 && buf->data[2] == 0x00) { + buf->data[0] = buf->data[0x37FB]; + buf->data[1] = buf->data[0x37FC]; + buf->data[2] = buf->data[0x37FD]; + buf->data[0x37FB] = 0x00; + buf->data[0x37FC] = 0x00; + buf->data[0x37FD] = 0x00; + } + + /* whole image */ + fw_new = g_byte_array_free_to_bytes (g_steal_pointer (&buf)); + img = fu_firmware_image_new (fw_new); + fu_firmware_add_image (firmware, img); + return TRUE; +} + +static void +fu_hailuck_kbd_firmware_init (FuHailuckKbdFirmware *self) +{ +} + +static void +fu_hailuck_kbd_firmware_class_init (FuHailuckKbdFirmwareClass *klass) +{ + FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); + klass_firmware->parse = fu_hailuck_kbd_firmware_parse; +} + +FuFirmware * +fu_hailuck_kbd_firmware_new (void) +{ + return FU_FIRMWARE (g_object_new (FU_TYPE_HAILUCK_KBD_FIRMWARE, NULL)); +} diff -Nru fwupd-1.4.5/plugins/hailuck/fu-hailuck-kbd-firmware.h fwupd-1.5.8/plugins/hailuck/fu-hailuck-kbd-firmware.h --- fwupd-1.4.5/plugins/hailuck/fu-hailuck-kbd-firmware.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/hailuck/fu-hailuck-kbd-firmware.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-ihex-firmware.h" + +#define FU_TYPE_HAILUCK_KBD_FIRMWARE (fu_hailuck_kbd_firmware_get_type ()) +G_DECLARE_FINAL_TYPE (FuHailuckKbdFirmware, fu_hailuck_kbd_firmware, FU, HAILUCK_KBD_FIRMWARE, FuIhexFirmware) + +FuFirmware *fu_hailuck_kbd_firmware_new (void); diff -Nru fwupd-1.4.5/plugins/hailuck/fu-hailuck-tp-device.c fwupd-1.5.8/plugins/hailuck/fu-hailuck-tp-device.c --- fwupd-1.4.5/plugins/hailuck/fu-hailuck-tp-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/hailuck/fu-hailuck-tp-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-chunk.h" +#include "fu-hid-device.h" + +#include "fu-hailuck-common.h" +#include "fu-hailuck-tp-device.h" + +struct _FuHailuckTpDevice { + FuDevice parent_instance; +}; + +G_DEFINE_TYPE (FuHailuckTpDevice, fu_hailuck_tp_device, FU_TYPE_DEVICE) + +static gboolean +fu_hailuck_tp_device_probe (FuDevice *device, GError **error) +{ + FuDevice *parent = fu_device_get_parent (device); + g_autofree gchar *devid1 = NULL; + g_autofree gchar *devid2 = NULL; + + devid1 = g_strdup_printf ("USB\\VID_%04X&PID_%04X", + fu_usb_device_get_vid (FU_USB_DEVICE (parent)), + fu_usb_device_get_pid (FU_USB_DEVICE (parent))); + fu_device_add_instance_id (device, devid1); + devid2 = g_strdup_printf ("USB\\VID_%04X&PID_%04X&MODE_TP", + fu_usb_device_get_vid (FU_USB_DEVICE (parent)), + fu_usb_device_get_pid (FU_USB_DEVICE (parent))); + fu_device_add_instance_id (device, devid2); + + return TRUE; +} + +static gboolean +fu_hailuck_tp_device_open (FuDevice *device, GError **error) +{ + FuDevice *parent = fu_device_get_parent (device); + return fu_device_open (parent, error); +} + +static gboolean +fu_hailuck_tp_device_close (FuDevice *device, GError **error) +{ + FuDevice *parent = fu_device_get_parent (device); + return fu_device_close (parent, error); +} + +typedef struct { + guint8 type; + guint8 success; /* if 0xff, then cmd-0x10 */ +} FuHailuckTpDeviceReq; + +static gboolean +fu_hailuck_tp_device_cmd_cb (FuDevice *device, gpointer user_data, GError **error) +{ + FuDevice *parent = fu_device_get_parent (device); + FuHailuckTpDeviceReq *req = (FuHailuckTpDeviceReq *) user_data; + guint8 buf[6] = { + FU_HAILUCK_REPORT_ID_SHORT, + FU_HAILUCK_CMD_GET_STATUS, + req->type, + }; + guint8 success_tmp = req->success; + if (!fu_hid_device_set_report (FU_HID_DEVICE (parent), buf[0], + buf, sizeof(buf), 1000, + FU_HID_DEVICE_FLAG_IS_FEATURE, error)) + return FALSE; + if (!fu_hid_device_get_report (FU_HID_DEVICE (parent), buf[0], + buf, sizeof(buf), 2000, + FU_HID_DEVICE_FLAG_IS_FEATURE | + FU_HID_DEVICE_FLAG_ALLOW_TRUNC, + error)) + return FALSE; + if (success_tmp == 0xff) + success_tmp = req->type - 0x10; + if (buf[0] != FU_HAILUCK_REPORT_ID_SHORT || buf[1] != success_tmp) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "report mismatch for type=0x%02x[%s]: " + "expected=0x%02x, received=0x%02x", + req->type, + fu_hailuck_cmd_to_string (req->type), + success_tmp, buf[1]); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_hailuck_tp_device_write_firmware (FuDevice *device, + FuFirmware *firmware, + FwupdInstallFlags flags, + GError **error) +{ + FuDevice *parent = fu_device_get_parent (device); + const guint block_size = 1024; + g_autoptr(GBytes) fw = NULL; + g_autoptr(GPtrArray) chunks = NULL; + FuHailuckTpDeviceReq req = { + .type = 0xff, + .success = 0xff, + }; + + /* get default image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + + /* erase */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE); + req.type = FU_HAILUCK_CMD_I2C_ERASE; + if (!fu_device_retry (device, fu_hailuck_tp_device_cmd_cb, 100, &req, error)) { + g_prefix_error (error, "failed to erase: "); + return FALSE; + } + g_usleep (10000); + + /* write */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + chunks = fu_chunk_array_new_from_bytes (fw, 0x0, 0x0, block_size); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + g_autoptr(GByteArray) buf = g_byte_array_new (); + + /* write block */ + fu_byte_array_append_uint8 (buf, FU_HAILUCK_REPORT_ID_LONG); + fu_byte_array_append_uint8 (buf, FU_HAILUCK_CMD_WRITE_TP); + fu_byte_array_append_uint16 (buf, 0xCCCC, G_LITTLE_ENDIAN); + fu_byte_array_append_uint16 (buf, fu_chunk_get_address (chk), G_LITTLE_ENDIAN); + fu_byte_array_append_uint16 (buf, 0xCCCC, G_LITTLE_ENDIAN); + g_byte_array_append (buf, fu_chunk_get_data (chk), fu_chunk_get_data_sz (chk)); + fu_byte_array_append_uint8 (buf, 0xEE); + fu_byte_array_append_uint8 (buf, 0xD2); + fu_byte_array_append_uint16 (buf, 0xCCCC, G_LITTLE_ENDIAN); + fu_byte_array_append_uint16 (buf, 0xCCCC, G_LITTLE_ENDIAN); + fu_byte_array_append_uint16 (buf, 0xCCCC, G_LITTLE_ENDIAN); + if (buf->len != block_size + 16) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "packet mismatch: len=0x%04x, expected=0x%04x", + buf->len, block_size + 16); + return FALSE; + } + if (!fu_hid_device_set_report (FU_HID_DEVICE (parent), buf->data[0], + buf->data, buf->len, 1000, + FU_HID_DEVICE_FLAG_IS_FEATURE, error)) { + g_prefix_error (error, "failed to write block 0x%x: ", i); + return FALSE; + } + g_usleep (150 * 1000); + + /* verify block */ + req.type = FU_HAILUCK_CMD_I2C_VERIFY_BLOCK; + if (!fu_device_retry (device, fu_hailuck_tp_device_cmd_cb, 100, &req, error)) { + g_prefix_error (error, "failed to verify block 0x%x: ", i); + return FALSE; + } + + /* update progress */ + fu_device_set_progress_full (device, i, chunks->len - 1); + } + g_usleep (50 * 1000); + + /* end-program */ + req.type = FU_HAILUCK_CMD_I2C_END_PROGRAM; + if (!fu_device_retry (device, fu_hailuck_tp_device_cmd_cb, 100, &req, error)) { + g_prefix_error (error, "failed to end program: "); + return FALSE; + } + g_usleep (50 * 1000); + + /* verify checksum */ + req.type = FU_HAILUCK_CMD_I2C_VERIFY_CHECKSUM; + if (!fu_device_retry (device, fu_hailuck_tp_device_cmd_cb, 100, &req, error)) { + g_prefix_error (error, "failed to verify: "); + return FALSE; + } + g_usleep (50 * 1000); + + /* signal that programming has completed */ + req.type = FU_HAILUCK_CMD_I2C_PROGRAMPASS; + req.success = 0x0; + if (!fu_device_retry (device, fu_hailuck_tp_device_cmd_cb, 100, &req, error)) { + g_prefix_error (error, "failed to program: "); + return FALSE; + } + + /* success! */ + return TRUE; +} + +static void +fu_hailuck_tp_device_init (FuHailuckTpDevice *self) +{ + fu_device_retry_set_delay (FU_DEVICE (self), 50); /* ms */ + fu_device_set_firmware_size (FU_DEVICE (self), 0x6018); + fu_device_add_protocol (FU_DEVICE (self), "com.hailuck.tp"); + fu_device_set_logical_id (FU_DEVICE (self), "TP"); + fu_device_set_name (FU_DEVICE (self), "Touchpad"); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_icon (FU_DEVICE (self), "input-touchpad"); + fu_device_set_remove_delay (FU_DEVICE (self), + FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); +} + +static void +fu_hailuck_tp_device_class_init (FuHailuckTpDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + klass_device->write_firmware = fu_hailuck_tp_device_write_firmware; + klass_device->open = fu_hailuck_tp_device_open; + klass_device->close = fu_hailuck_tp_device_close; + klass_device->probe = fu_hailuck_tp_device_probe; +} + +FuHailuckTpDevice * +fu_hailuck_tp_device_new (FuDevice *device) +{ + FuHailuckTpDevice *self; + self = g_object_new (FU_TYPE_HAILUCK_TP_DEVICE, + "parent", device, + NULL); + return FU_HAILUCK_TP_DEVICE (self); +} diff -Nru fwupd-1.4.5/plugins/hailuck/fu-hailuck-tp-device.h fwupd-1.5.8/plugins/hailuck/fu-hailuck-tp-device.h --- fwupd-1.4.5/plugins/hailuck/fu-hailuck-tp-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/hailuck/fu-hailuck-tp-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +#define FU_TYPE_HAILUCK_TP_DEVICE (fu_hailuck_tp_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuHailuckTpDevice, fu_hailuck_tp_device, FU, HAILUCK_TP_DEVICE, FuDevice) + +FuHailuckTpDevice *fu_hailuck_tp_device_new (FuDevice *parent); diff -Nru fwupd-1.4.5/plugins/hailuck/fu-plugin-hailuck.c fwupd-1.5.8/plugins/hailuck/fu-plugin-hailuck.c --- fwupd-1.4.5/plugins/hailuck/fu-plugin-hailuck.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/hailuck/fu-plugin-hailuck.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" + +#include "fu-hailuck-bl-device.h" +#include "fu-hailuck-kbd-device.h" +#include "fu-hailuck-kbd-firmware.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_firmware_gtype (plugin, NULL, FU_TYPE_HAILUCK_KBD_FIRMWARE); + fu_plugin_set_device_gtype (plugin, FU_TYPE_HAILUCK_BL_DEVICE); + fu_plugin_set_device_gtype (plugin, FU_TYPE_HAILUCK_KBD_DEVICE); +} diff -Nru fwupd-1.4.5/plugins/hailuck/hailuck.quirk fwupd-1.5.8/plugins/hailuck/hailuck.quirk --- fwupd-1.4.5/plugins/hailuck/hailuck.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/hailuck/hailuck.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,25 @@ +# bootloader + +[USB\VID_0603&PID_1020] +Plugin = hailuck +GType = FuHailuckBlDevice +#Flags = is-bootloader + +[USB\VID_258A&PID_001E] +Plugin = hailuck +GType = FuHailuckKbdDevice +Vendor = PINE64 +CounterpartGuid = USB\VID_0603&PID_1020 + +[USB\VID_258A&PID_001E&MODE_KBD] +Name = Keyboard + +[USB\VID_258A&PID_001F] +Plugin = hailuck +GType = FuHailuckKbdDevice +CounterpartGuid = USB\VID_0603&PID_1020 + +[USB\VID_258A&PID_000D] +Plugin = hailuck +GType = FuHailuckKbdDevice +CounterpartGuid = USB\VID_0603&PID_1020 diff -Nru fwupd-1.4.5/plugins/hailuck/meson.build fwupd-1.5.8/plugins/hailuck/meson.build --- fwupd-1.4.5/plugins/hailuck/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/hailuck/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,36 @@ +if get_option('gusb') +cargs = ['-DG_LOG_DOMAIN="FuPluginNovatek"'] + +install_data([ + 'hailuck.quirk', + ], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_hailuck', + fu_hash, + sources : [ + 'fu-hailuck-common.c', + 'fu-hailuck-bl-device.c', + 'fu-hailuck-kbd-device.c', + 'fu-hailuck-kbd-firmware.c', # fuzzing + 'fu-hailuck-tp-device.c', + 'fu-plugin-hailuck.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) +endif diff -Nru fwupd-1.4.5/plugins/hailuck/README.md fwupd-1.5.8/plugins/hailuck/README.md --- fwupd-1.4.5/plugins/hailuck/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/hailuck/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,48 @@ +Hailuck Support +=============== + +Introduction +------------ + +Hailuck produce the firmware used on the keyboard and trackpad used in the +Pinebook Pro laptops. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +a packed binary file format. + +This plugin supports the following protocol ID: + + * com.hailuck.kbd + * com.hailuck.tp + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_0603&PID_1020` + +Update Behavior +--------------- + +The keyboard device usually presents in runtime mode, but on detach it +re-enumerates with a different USB VID and PID in bootloader mode. On attach +the device again re-enumerates back to the runtime mode. + +For this reason the `REPLUG_MATCH_GUID` internal device flag is used so that +the bootloader and runtime modes are treated as the same device. + +The touchpad firmware is deployed when the device is in normal runtime mode, +and the device will reset when the new firmware has been written. + +Vendor ID Security +------------------ + +The vendor ID is set from the USB vendor, in this instance set to `USB:0x0603` + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff -Nru fwupd-1.4.5/plugins/iommu/fu-plugin-iommu.c fwupd-1.5.8/plugins/iommu/fu-plugin-iommu.c --- fwupd-1.4.5/plugins/iommu/fu-plugin-iommu.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/iommu/fu-plugin-iommu.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" + +struct FuPluginData { + gboolean has_iommu; +}; + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_udev_subsystem (plugin, "iommu"); +} + +gboolean +fu_plugin_backend_device_added (FuPlugin *plugin, FuDevice *device, GError **error) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + + /* interesting device? */ + if (!FU_IS_UDEV_DEVICE (device)) + return TRUE; + if (g_strcmp0 (fu_udev_device_get_subsystem (FU_UDEV_DEVICE (device)), "iommu") != 0) + return TRUE; + priv->has_iommu = TRUE; + + return TRUE; +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_IOMMU); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fu_security_attrs_append (attrs, attr); + + if (!data->has_iommu) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); +} diff -Nru fwupd-1.4.5/plugins/iommu/iommu.quirk fwupd-1.5.8/plugins/iommu/iommu.quirk --- fwupd-1.4.5/plugins/iommu/iommu.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/iommu/iommu.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,3 @@ +# match all devices with this udev subsystem +[IOMMU] +Plugin = iommu diff -Nru fwupd-1.4.5/plugins/iommu/meson.build fwupd-1.5.8/plugins/iommu/meson.build --- fwupd-1.4.5/plugins/iommu/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/iommu/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,31 @@ +if host_machine.system() == 'linux' +cargs = ['-DG_LOG_DOMAIN="FuPluginIommu"'] + +install_data([ + 'iommu.quirk', + ], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_iommu', + fu_hash, + sources : [ + 'fu-plugin-iommu.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupdplugin, + fwupd, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) +endif diff -Nru fwupd-1.4.5/plugins/iommu/README.md fwupd-1.5.8/plugins/iommu/README.md --- fwupd-1.4.5/plugins/iommu/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/iommu/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,11 @@ +Linux IOMMU +================== + +Introduction +------------ + +This plugin checks if an IOMMU is available on the system. + +External interface access +------------------------- +This plugin requires no extra access. diff -Nru fwupd-1.4.5/plugins/jabra/fu-jabra-device.c fwupd-1.5.8/plugins/jabra/fu-jabra-device.c --- fwupd-1.4.5/plugins/jabra/fu-jabra-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/jabra/fu-jabra-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -6,6 +6,8 @@ #include "config.h" +#include + #include "fu-firmware-common.h" #include "fu-jabra-device.h" @@ -48,6 +50,7 @@ { FuJabraDevice *self = FU_JABRA_DEVICE (device); GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + gsize magiclen = strlen (self->magic); guint8 adr = 0x00; guint8 rep = 0x00; guint8 iface_hid; @@ -55,8 +58,10 @@ g_autoptr(GError) error_local = NULL; /* parse string and create magic packet */ - rep = fu_firmware_strparse_uint8 (self->magic + 0); - adr = fu_firmware_strparse_uint8 (self->magic + 2); + if (!fu_firmware_strparse_uint8_safe (self->magic, magiclen, 0, &rep, error)) + return FALSE; + if (!fu_firmware_strparse_uint8_safe (self->magic, magiclen, 2, &adr, error)) + return FALSE; buf[0] = rep; buf[1] = adr; buf[2] = 0x00; @@ -143,7 +148,9 @@ { fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_ADD_COUNTERPART_GUIDS); + fu_device_add_internal_flag (FU_DEVICE (self), FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID); fu_device_set_remove_delay (FU_DEVICE (self), 20000); /* 10+10s! */ + fu_device_add_protocol (FU_DEVICE (self), "org.usb.dfu"); } static void diff -Nru fwupd-1.4.5/plugins/jabra/fu-plugin-jabra.c fwupd-1.5.8/plugins/jabra/fu-plugin-jabra.c --- fwupd-1.4.5/plugins/jabra/fu-plugin-jabra.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/jabra/fu-plugin-jabra.c 2021-03-31 20:08:32.000000000 +0000 @@ -7,7 +7,6 @@ #include "config.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #include "fu-jabra-device.h" @@ -16,6 +15,7 @@ { fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_set_device_gtype (plugin, FU_TYPE_JABRA_DEVICE); + fu_plugin_add_possible_quirk_key (plugin, "JabraMagic"); } /* slightly weirdly, this takes us from appIDLE back into the actual @@ -37,7 +37,7 @@ locker = fu_device_locker_new (device, error); if (locker == NULL) return FALSE; - g_debug ("performing extra reset into firmware mode"); + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); if (!g_usb_device_reset (usb_device, &error_local)) { g_set_error (error, @@ -50,7 +50,6 @@ } /* wait for device to re-appear */ - fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); return TRUE; } diff -Nru fwupd-1.4.5/plugins/jabra/jabra.quirk fwupd-1.5.8/plugins/jabra/jabra.quirk --- fwupd-1.4.5/plugins/jabra/jabra.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/jabra/jabra.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,23 +1,23 @@ # Jabra 410 [runtime] -[DeviceInstanceId=USB\VID_0B0E&PID_0412] +[USB\VID_0B0E&PID_0412] Plugin = jabra JabraMagic = 0201 CounterpartGuid = USB\VID_0B0E&PID_0411 # Jabra 510 [runtime] -[DeviceInstanceId=USB\VID_0B0E&PID_0420] +[USB\VID_0B0E&PID_0420] Plugin = jabra JabraMagic = 0201 CounterpartGuid = USB\VID_0B0E&PID_0421 # Jabra 710 [runtime] -[DeviceInstanceId=USB\VID_0B0E&PID_2475] +[USB\VID_0B0E&PID_2475] Plugin = jabra JabraMagic = 0508 CounterpartGuid = USB\VID_0B0E&PID_0982 # Jabra 810 [runtime] -[DeviceInstanceId=USB\VID_0B0E&PID_2456] +[USB\VID_0B0E&PID_2456] Plugin = jabra JabraMagic = 0508 CounterpartGuid = USB\VID_0B0E&PID_0971 diff -Nru fwupd-1.4.5/plugins/jabra/meson.build fwupd-1.5.8/plugins/jabra/meson.build --- fwupd-1.4.5/plugins/jabra/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/jabra/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,4 @@ +if get_option('gusb') cargs = ['-DG_LOG_DOMAIN="FuPluginJabra"'] install_data(['jabra.quirk'], @@ -26,3 +27,4 @@ plugin_deps, ], ) +endif diff -Nru fwupd-1.4.5/plugins/jabra/README.md fwupd-1.5.8/plugins/jabra/README.md --- fwupd-1.4.5/plugins/jabra/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/jabra/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -22,7 +22,23 @@ |---------------|----------------------------------------------|---------------| |`JabraMagic` | Two magic bytes sent to detach into DFU mode.|1.3.3 | +Update Behavior +--------------- + +The device usually presents in runtime mode, but on detach re-enumerates with a +different USB VID and PID in DFU APP mode. The device is then further detached +by the `dfu` plugin. + +On DFU attach the device again re-enumerates back to the Jabra runtime mode. + +For this reason the `REPLUG_MATCH_GUID` internal device flag is used so that +the bootloader and runtime modes are treated as the same device. + Vendor ID Security ------------------ The vendor ID is set from the USB vendor, in this instance set to `USB:0x0A12` + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff -Nru fwupd-1.4.5/plugins/linux-lockdown/fu-plugin-linux-lockdown.c fwupd-1.5.8/plugins/linux-lockdown/fu-plugin-linux-lockdown.c --- fwupd-1.4.5/plugins/linux-lockdown/fu-plugin-linux-lockdown.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/linux-lockdown/fu-plugin-linux-lockdown.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" + +typedef enum { + FU_PLUGIN_LINUX_LOCKDOWN_UNKNOWN, + FU_PLUGIN_LINUX_LOCKDOWN_INVALID, + FU_PLUGIN_LINUX_LOCKDOWN_NONE, + FU_PLUGIN_LINUX_LOCKDOWN_INTEGRITY, + FU_PLUGIN_LINUX_LOCKDOWN_CONFIDENTIALITY, +} FuPluginLinuxLockdown; + +struct FuPluginData { + GFile *file; + GFileMonitor *monitor; + FuPluginLinuxLockdown lockdown; +}; + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + +void +fu_plugin_destroy (FuPlugin *plugin) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + if (data->file != NULL) + g_object_unref (data->file); + if (data->monitor != NULL) { + g_file_monitor_cancel (data->monitor); + g_object_unref (data->monitor); + } +} + +static const gchar * +fu_plugin_linux_lockdown_to_string (FuPluginLinuxLockdown lockdown) +{ + if (lockdown == FU_PLUGIN_LINUX_LOCKDOWN_NONE) + return "none"; + if (lockdown == FU_PLUGIN_LINUX_LOCKDOWN_INTEGRITY) + return "integrity"; + if (lockdown == FU_PLUGIN_LINUX_LOCKDOWN_CONFIDENTIALITY) + return "confidentiality"; + if (lockdown == FU_PLUGIN_LINUX_LOCKDOWN_INVALID) + return "invalid"; + return NULL; +} + +static void +fu_plugin_linux_lockdown_rescan (FuPlugin *plugin) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + gsize bufsz = 0; + g_autofree gchar *buf = NULL; + + /* load file */ + if (!g_file_load_contents (data->file, NULL, &buf, &bufsz, NULL, NULL)) { + data->lockdown = FU_PLUGIN_LINUX_LOCKDOWN_INVALID; + } else if (g_strstr_len (buf, bufsz, "[none]") != NULL) { + data->lockdown = FU_PLUGIN_LINUX_LOCKDOWN_NONE; + } else if (g_strstr_len (buf, bufsz, "[integrity]") != NULL) { + data->lockdown = FU_PLUGIN_LINUX_LOCKDOWN_INTEGRITY; + } else if (g_strstr_len (buf, bufsz, "[confidentiality]") != NULL) { + data->lockdown = FU_PLUGIN_LINUX_LOCKDOWN_CONFIDENTIALITY; + } else { + data->lockdown = FU_PLUGIN_LINUX_LOCKDOWN_UNKNOWN; + } + + /* update metadata */ + fu_plugin_add_report_metadata (plugin, "LinuxLockdown", + fu_plugin_linux_lockdown_to_string (data->lockdown)); +} + +static void +fu_plugin_linux_lockdown_changed_cb (GFileMonitor *monitor, + GFile *file, + GFile *other_file, + GFileMonitorEvent event_type, + gpointer user_data) +{ + FuPlugin *plugin = FU_PLUGIN (user_data); + fu_plugin_linux_lockdown_rescan (plugin); + fu_plugin_security_changed (plugin); +} + +gboolean +fu_plugin_startup (FuPlugin *plugin, GError **error) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + g_autofree gchar *path = NULL; + g_autofree gchar *fn = NULL; + + path = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_SECURITY); + fn = g_build_filename (path, "lockdown", NULL); + data->file = g_file_new_for_path (fn); + data->monitor = g_file_monitor (data->file, G_FILE_MONITOR_NONE, NULL, error); + if (data->monitor == NULL) + return FALSE; + g_signal_connect (data->monitor, "changed", + G_CALLBACK (fu_plugin_linux_lockdown_changed_cb), plugin); + fu_plugin_linux_lockdown_rescan (plugin); + return TRUE; +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_KERNEL_LOCKDOWN); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); + fu_security_attrs_append (attrs, attr); + + /* load file */ + if (data->lockdown == FU_PLUGIN_LINUX_LOCKDOWN_INVALID || + data->lockdown == FU_PLUGIN_LINUX_LOCKDOWN_UNKNOWN) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); + return; + } + if (data->lockdown == FU_PLUGIN_LINUX_LOCKDOWN_NONE) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); +} diff -Nru fwupd-1.4.5/plugins/linux-lockdown/meson.build fwupd-1.5.8/plugins/linux-lockdown/meson.build --- fwupd-1.4.5/plugins/linux-lockdown/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/linux-lockdown/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,25 @@ +if host_machine.system() == 'linux' +cargs = ['-DG_LOG_DOMAIN="FuPluginLinuxLockdown"'] + +shared_module('fu_plugin_linux_lockdown', + fu_hash, + sources : [ + 'fu-plugin-linux-lockdown.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) +endif diff -Nru fwupd-1.4.5/plugins/linux-lockdown/README.md fwupd-1.5.8/plugins/linux-lockdown/README.md --- fwupd-1.4.5/plugins/linux-lockdown/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/linux-lockdown/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,12 @@ +Linux Kernel Lockdown +===================== + +Introduction +------------ + +This plugin checks if the currently running kernel is locked down. The result +will be stored in an security attribute for HSI. + +External interface access +------------------------- +This plugin requires read access to `/sys/sys/kernel/security`. diff -Nru fwupd-1.4.5/plugins/linux-sleep/fu-plugin-linux-sleep.c fwupd-1.5.8/plugins/linux-sleep/fu-plugin-linux-sleep.c --- fwupd-1.4.5/plugins/linux-sleep/fu-plugin-linux-sleep.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/linux-sleep/fu-plugin-linux-sleep.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + gsize bufsz = 0; + g_autofree gchar *buf = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GError) error_local = NULL; + g_autoptr(GFile) file = g_file_new_for_path ("/sys/power/mem_sleep"); + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_RAM); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL); + fu_security_attrs_append (attrs, attr); + + /* load file */ + if (!g_file_load_contents (file, NULL, &buf, &bufsz, NULL, &error_local)) { + g_autofree gchar *fn = g_file_get_path (file); + g_warning ("could not open %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); + return; + } + if (g_strstr_len (buf, bufsz, "[deep]") != NULL) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); +} diff -Nru fwupd-1.4.5/plugins/linux-sleep/meson.build fwupd-1.5.8/plugins/linux-sleep/meson.build --- fwupd-1.4.5/plugins/linux-sleep/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/linux-sleep/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,25 @@ +if host_machine.system() == 'linux' +cargs = ['-DG_LOG_DOMAIN="FuPluginLinuxSleep"'] + +shared_module('fu_plugin_linux_sleep', + fu_hash, + sources : [ + 'fu-plugin-linux-sleep.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) +endif diff -Nru fwupd-1.4.5/plugins/linux-sleep/README.md fwupd-1.5.8/plugins/linux-sleep/README.md --- fwupd-1.4.5/plugins/linux-sleep/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/linux-sleep/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,12 @@ +Linux Kernel Sleep +================== + +Introduction +------------ + +This plugin checks if s3 sleep is available. The result will be stored in an +security attribute for HSI. + +External interface access +------------------------- +This plugin requires read access to `/sys/power/mem_sleep`. diff -Nru fwupd-1.4.5/plugins/linux-swap/fu-linux-swap.c fwupd-1.5.8/plugins/linux-swap/fu-linux-swap.c --- fwupd-1.4.5/plugins/linux-swap/fu-linux-swap.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/linux-swap/fu-linux-swap.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" +#include "fu-linux-swap.h" + +struct _FuLinuxSwap { + GObject parent_instance; + guint encrypted_cnt; + guint enabled_cnt; +}; + +G_DEFINE_TYPE (FuLinuxSwap, fu_linux_swap, G_TYPE_OBJECT) + +static gchar * +fu_strdup_nospaces (const gchar *line) +{ + GString *str = g_string_new (NULL); + for (guint i = 0; line[i] != '\0' && !g_ascii_isspace (line[i]); i++) + g_string_append_c (str, line[i]); + return g_string_free (str, FALSE); +} + +static gboolean +fu_linux_swap_verify_partition (FuLinuxSwap *self, const gchar *fn, GError **error) +{ + g_autoptr(FuVolume) volume = NULL; + + /* find the device */ + volume = fu_common_get_volume_by_device (fn, error); + if (volume == NULL) + return FALSE; + + /* this isn't technically encrypted, but isn't on disk in plaintext */ + if (g_str_has_prefix (fn, "/dev/zram")) { + g_debug ("%s is zram, assuming encrypted", fn); + self->encrypted_cnt++; + return TRUE; + } + + /* is this mount point encrypted */ + if (fu_volume_is_encrypted (volume)) { + g_debug ("%s partition is encrypted", fn); + self->encrypted_cnt++; + } else { + g_debug ("%s partition is unencrypted", fn); + } + + /* success */ + return TRUE; +} + +static gboolean +fu_linux_swap_verify_file (FuLinuxSwap *self, const gchar *fn, GError **error) +{ + guint32 devnum; + g_autoptr(GFile) file = NULL; + g_autoptr(GFileInfo) info = NULL; + g_autoptr(FuVolume) volume = NULL; + + /* get the device number for the file */ + file = g_file_new_for_path (fn); + info = g_file_query_info (file, G_FILE_ATTRIBUTE_UNIX_DEVICE, + G_FILE_QUERY_INFO_NONE, NULL, error); + if (info == NULL) + return FALSE; + devnum = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_DEVICE); + + /* find the device */ + volume = fu_common_get_volume_by_devnum (devnum, error); + if (volume == NULL) + return FALSE; + + /* is this mount point encrypted */ + if (fu_volume_is_encrypted (volume)) { + g_debug ("%s file is encrypted", fn); + self->encrypted_cnt++; + } else { + g_debug ("%s file is unencrypted", fn); + } + + /* success */ + return TRUE; +} + +FuLinuxSwap * +fu_linux_swap_new (const gchar *buf, gsize bufsz, GError **error) +{ + FuLinuxSwap *self = g_object_new (FU_TYPE_LINUX_SWAP, NULL); + g_auto(GStrv) lines = NULL; + + /* look at each line in /proc/swaps */ + if (bufsz == 0) + bufsz = strlen (buf); + lines = fu_common_strnsplit (buf, bufsz, "\n", -1); + if (g_strv_length (lines) > 2) { + for (guint i = 1; lines[i] != NULL && lines[i][0] != '\0'; i++) { + g_autofree gchar *fn = NULL; + g_autofree gchar *ty = NULL; + + /* split */ + if (g_utf8_strlen (lines[i], -1) < 45) + continue; + fn = fu_strdup_nospaces (lines[i]); + ty = fu_strdup_nospaces (lines[i] + 40); + + /* partition, so use UDisks to see if backed by crypto */ + if (g_strcmp0 (ty, "partition") == 0) { + self->enabled_cnt++; + if (!fu_linux_swap_verify_partition (self, fn, error)) + return NULL; + } else if (g_strcmp0 (ty, "file") == 0) { + self->enabled_cnt++; + if (!fu_linux_swap_verify_file (self, fn, error)) + return NULL; + } else { + g_warning ("unknown swap type: %s [%s]", ty, fn); + } + } + } + return self; +} + +/* success if *all* the swap devices are encrypted */ +gboolean +fu_linux_swap_get_encrypted (FuLinuxSwap *self) +{ + g_return_val_if_fail (FU_IS_LINUX_SWAP (self), FALSE); + return self->enabled_cnt > 0 && self->enabled_cnt == self->encrypted_cnt; +} + +gboolean +fu_linux_swap_get_enabled (FuLinuxSwap *self) +{ + g_return_val_if_fail (FU_IS_LINUX_SWAP (self), FALSE); + return self->enabled_cnt > 0; +} + +static void +fu_linux_swap_class_init (FuLinuxSwapClass *klass) +{ +} + +static void +fu_linux_swap_init (FuLinuxSwap *self) +{ +} diff -Nru fwupd-1.4.5/plugins/linux-swap/fu-linux-swap.h fwupd-1.5.8/plugins/linux-swap/fu-linux-swap.h --- fwupd-1.4.5/plugins/linux-swap/fu-linux-swap.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/linux-swap/fu-linux-swap.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#define FU_TYPE_LINUX_SWAP (fu_linux_swap_get_type ()) +G_DECLARE_FINAL_TYPE (FuLinuxSwap, fu_linux_swap, FU, LINUX_SWAP, GObject) + +FuLinuxSwap *fu_linux_swap_new (const gchar *buf, + gsize bufsz, + GError **error); +gboolean fu_linux_swap_get_enabled (FuLinuxSwap *self); +gboolean fu_linux_swap_get_encrypted (FuLinuxSwap *self); diff -Nru fwupd-1.4.5/plugins/linux-swap/fu-plugin-linux-swap.c fwupd-1.5.8/plugins/linux-swap/fu-plugin-linux-swap.c --- fwupd-1.4.5/plugins/linux-swap/fu-plugin-linux-swap.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/linux-swap/fu-plugin-linux-swap.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" +#include "fu-linux-swap.h" + +struct FuPluginData { + GFile *file; + GFileMonitor *monitor; +}; + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + +void +fu_plugin_destroy (FuPlugin *plugin) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + if (data->file != NULL) + g_object_unref (data->file); + if (data->monitor != NULL) { + g_file_monitor_cancel (data->monitor); + g_object_unref (data->monitor); + } +} + +static void +fu_plugin_linux_swap_changed_cb (GFileMonitor *monitor, + GFile *file, + GFile *other_file, + GFileMonitorEvent event_type, + gpointer user_data) +{ + FuPlugin *plugin = FU_PLUGIN (user_data); + fu_plugin_security_changed (plugin); +} + +gboolean +fu_plugin_startup (FuPlugin *plugin, GError **error) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + g_autofree gchar *fn = NULL; + g_autofree gchar *procfs = NULL; + + procfs = fu_common_get_path (FU_PATH_KIND_PROCFS); + fn = g_build_filename (procfs, "swaps", NULL); + data->file = g_file_new_for_path (fn); + data->monitor = g_file_monitor (data->file, G_FILE_MONITOR_NONE, NULL, error); + if (data->monitor == NULL) + return FALSE; + g_signal_connect (data->monitor, "changed", + G_CALLBACK (fu_plugin_linux_swap_changed_cb), plugin); + return TRUE; +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + gsize bufsz = 0; + g_autofree gchar *buf = NULL; + g_autoptr(FuLinuxSwap) swap = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GError) error_local = NULL; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_KERNEL_SWAP); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); + fu_security_attrs_append (attrs, attr); + + /* load list of swaps */ + if (!g_file_load_contents (data->file, NULL, &buf, &bufsz, NULL, &error_local)) { + g_autofree gchar *fn = g_file_get_path (data->file); + g_warning ("could not open %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); + return; + } + swap = fu_linux_swap_new (buf, bufsz, &error_local); + if (swap == NULL) { + g_autofree gchar *fn = g_file_get_path (data->file); + g_warning ("could not parse %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); + return; + } + + /* none configured */ + if (!fu_linux_swap_get_enabled (swap)) { + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); + return; + } + + /* add security attribute */ + if (!fu_linux_swap_get_encrypted (swap)) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENCRYPTED); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENCRYPTED); +} diff -Nru fwupd-1.4.5/plugins/linux-swap/fu-self-test.c fwupd-1.5.8/plugins/linux-swap/fu-self-test.c --- fwupd-1.4.5/plugins/linux-swap/fu-self-test.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/linux-swap/fu-self-test.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-linux-swap.h" + +#include "fwupd-error.h" + +static void +fu_linux_swap_none_func (void) +{ + g_autoptr(FuLinuxSwap) swap = NULL; + g_autoptr(GError) error = NULL; + + swap = fu_linux_swap_new ("Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n", 0, &error); + g_assert_no_error (error); + g_assert_nonnull (swap); + g_assert_false (fu_linux_swap_get_enabled (swap)); + g_assert_false (fu_linux_swap_get_encrypted (swap)); +} + +static void +fu_linux_swap_plain_func (void) +{ + g_autoptr(FuLinuxSwap) swap = NULL; + g_autoptr(GError) error = NULL; + + swap = fu_linux_swap_new ("Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n" + "/dev/nvme0n1p4 partition\t5962748\t0\t-2\n", + 0, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) { + g_test_skip (error->message); + return; + } + if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN)) { + g_test_skip (error->message); + return; + } + g_assert_no_error (error); + g_assert_nonnull (swap); +} + +static void +fu_linux_swap_encrypted_func (void) +{ + g_autoptr(FuLinuxSwap) swap = NULL; + g_autoptr(GError) error = NULL; + + swap = fu_linux_swap_new ("Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n" + "/dev/dm-1 partition\t5962748\t0\t-2\n", + 0, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) || + g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN)) { + g_test_skip (error->message); + return; + } + g_assert_no_error (error); + g_assert_nonnull (swap); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + /* only critical and error are fatal */ + g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); + g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); + + /* tests go here */ + g_test_add_func ("/linux-swap/none", fu_linux_swap_none_func); + g_test_add_func ("/linux-swap/plain", fu_linux_swap_plain_func); + g_test_add_func ("/linux-swap/encrypted", fu_linux_swap_encrypted_func); + return g_test_run (); +} diff -Nru fwupd-1.4.5/plugins/linux-swap/meson.build fwupd-1.5.8/plugins/linux-swap/meson.build --- fwupd-1.4.5/plugins/linux-swap/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/linux-swap/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,52 @@ +if host_machine.system() == 'linux' +cargs = ['-DG_LOG_DOMAIN="FuPluginLinuxSwap"'] + +shared_module('fu_plugin_linux_swap', + fu_hash, + sources : [ + 'fu-plugin-linux-swap.c', + 'fu-linux-swap.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) +endif + +if get_option('tests') + e = executable( + 'linux-swap-self-test', + fu_hash, + sources : [ + 'fu-self-test.c', + 'fu-linux-swap.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + dependencies : [ + plugin_deps, + ], + link_with : [ + fwupd, + fwupdplugin, + ], + install : true, + install_dir : installed_test_bindir, + ) + test('linux-swap-self-test', e) # added to installed-tests +endif diff -Nru fwupd-1.4.5/plugins/linux-swap/README.md fwupd-1.5.8/plugins/linux-swap/README.md --- fwupd-1.4.5/plugins/linux-swap/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/linux-swap/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,12 @@ +Linux Swap Support +================== + +Introduction +------------ + +This plugin checks if the currently available swap partitions and files are +all encrypted. The result will be stored in an security attribute for HSI. + +External interface access +------------------------- +This plugin requires read access to `/proc` diff -Nru fwupd-1.4.5/plugins/linux-tainted/fu-plugin-linux-tainted.c fwupd-1.5.8/plugins/linux-tainted/fu-plugin-linux-tainted.c --- fwupd-1.4.5/plugins/linux-tainted/fu-plugin-linux-tainted.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/linux-tainted/fu-plugin-linux-tainted.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" + +struct FuPluginData { + GFile *file; + GFileMonitor *monitor; +}; + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + +void +fu_plugin_destroy (FuPlugin *plugin) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + if (data->file != NULL) + g_object_unref (data->file); + if (data->monitor != NULL) { + g_file_monitor_cancel (data->monitor); + g_object_unref (data->monitor); + } +} + +static void +fu_plugin_linux_tainted_changed_cb (GFileMonitor *monitor, + GFile *file, + GFile *other_file, + GFileMonitorEvent event_type, + gpointer user_data) +{ + FuPlugin *plugin = FU_PLUGIN (user_data); + fu_plugin_security_changed (plugin); +} + +gboolean +fu_plugin_startup (FuPlugin *plugin, GError **error) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + g_autofree gchar *fn = NULL; + g_autofree gchar *procfs = NULL; + + procfs = fu_common_get_path (FU_PATH_KIND_PROCFS); + fn = g_build_filename (procfs, "sys", "kernel", "tainted", NULL); + data->file = g_file_new_for_path (fn); + data->monitor = g_file_monitor (data->file, G_FILE_MONITOR_NONE, NULL, error); + if (data->monitor == NULL) + return FALSE; + g_signal_connect (data->monitor, "changed", + G_CALLBACK (fu_plugin_linux_tainted_changed_cb), plugin); + return TRUE; +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + gsize bufsz = 0; + g_autofree gchar *buf = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GError) error_local = NULL; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_KERNEL_TAINTED); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); + fu_security_attrs_append (attrs, attr); + + /* load file */ + if (!g_file_load_contents (data->file, NULL, &buf, &bufsz, NULL, &error_local)) { + g_autofree gchar *fn = g_file_get_path (data->file); + g_warning ("could not open %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); + return; + } + if (g_strcmp0 (buf, "0\n") != 0) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_TAINTED); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_TAINTED); +} diff -Nru fwupd-1.4.5/plugins/linux-tainted/meson.build fwupd-1.5.8/plugins/linux-tainted/meson.build --- fwupd-1.4.5/plugins/linux-tainted/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/linux-tainted/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,25 @@ +if host_machine.system() == 'linux' +cargs = ['-DG_LOG_DOMAIN="FuPluginLinuxTainted"'] + +shared_module('fu_plugin_linux_tainted', + fu_hash, + sources : [ + 'fu-plugin-linux-tainted.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) +endif diff -Nru fwupd-1.4.5/plugins/linux-tainted/README.md fwupd-1.5.8/plugins/linux-tainted/README.md --- fwupd-1.4.5/plugins/linux-tainted/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/linux-tainted/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,12 @@ +Linux Kernel Tainted +==================== + +Introduction +------------ + +This plugin checks if the currently running kernel is tainted. The result will +be stored in an security attribute for HSI. + +External interface access +------------------------- +This plugin requires read access to `/sys/kernel/tainted`. diff -Nru fwupd-1.4.5/plugins/logind/fu-plugin-logind.c fwupd-1.5.8/plugins/logind/fu-plugin-logind.c --- fwupd-1.4.5/plugins/logind/fu-plugin-logind.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/logind/fu-plugin-logind.c 2021-03-31 20:08:32.000000000 +0000 @@ -10,7 +10,6 @@ #include #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" struct FuPluginData { GDBusProxy *logind_proxy; diff -Nru fwupd-1.4.5/plugins/logind/meson.build fwupd-1.5.8/plugins/logind/meson.build --- fwupd-1.4.5/plugins/logind/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/logind/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,7 @@ +if get_option('systemd') +if host_machine.system() != 'linux' + error('linux is required for systemd') +endif cargs = ['-DG_LOG_DOMAIN="FuPluginLogind"'] shared_module('fu_plugin_logind', @@ -21,3 +25,4 @@ plugin_deps, ], ) +endif diff -Nru fwupd-1.4.5/plugins/logind/README.md fwupd-1.5.8/plugins/logind/README.md --- fwupd-1.4.5/plugins/logind/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/logind/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -11,3 +11,7 @@ ------------------ This protocol does not create a device and thus requires no vendor ID set. + +External interface access +------------------------- +This plugin requires access to the dbus interface `org.freedesktop.login1`. diff -Nru fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-bootloader.c fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-bootloader.c --- fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-bootloader.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-bootloader.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2018 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -61,10 +61,11 @@ guint8 rec_type = 0x00; guint16 offset = 0x0000; gboolean exit = FALSE; + gsize linesz = strlen (lines[i]); /* skip empty lines */ tmp = lines[i]; - if (strlen (tmp) < 5) + if (linesz < 5) continue; payload = fu_logitech_hidpp_bootloader_request_new (); @@ -77,7 +78,9 @@ payload->len); return NULL; } - payload->addr = fu_firmware_strparse_uint16 (tmp + 0x03); + if (!fu_firmware_strparse_uint16_safe (tmp, linesz, 0x03, + &payload->addr, error)) + return NULL; payload->cmd = FU_UNIFYING_BOOTLOADER_CMD_WRITE_RAM_BUFFER; rec_type = fu_logitech_hidpp_buffer_read_uint8 (tmp + 0x07); @@ -94,7 +97,10 @@ safely ignore it */ continue; case 0x04: /* extended linear address */ - offset = fu_firmware_strparse_uint16 (tmp + 0x09); + if (!fu_firmware_strparse_uint16_safe (tmp, linesz, + 0x09, &offset, + error)) + return NULL; if (offset != 0x0000) { g_set_error (error, G_IO_ERROR, @@ -245,18 +251,22 @@ if ((major == 0x01 && minor >= 0x04) || (major == 0x03 && minor >= 0x02)) - fu_device_set_protocol (FU_DEVICE (self), "com.logitech.unifyingsigned"); + fu_device_add_protocol (FU_DEVICE (self), "com.logitech.unifyingsigned"); else - fu_device_set_protocol (FU_DEVICE (self), "com.logitech.unifying"); + fu_device_add_protocol (FU_DEVICE (self), "com.logitech.unifying"); return TRUE; } static gboolean -fu_logitech_hidpp_bootloader_open (FuUsbDevice *device, GError **error) +fu_logitech_hidpp_bootloader_open (FuDevice *device, GError **error) { - GUsbDevice *usb_device = fu_usb_device_get_dev (device); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); const guint idx = 0x00; + /* FuUsbDevice->open */ + if (!FU_DEVICE_CLASS (fu_logitech_hidpp_bootloader_parent_class)->open (device, error)) + return FALSE; + /* claim the only interface */ if (!g_usb_device_claim_interface (usb_device, idx, G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, @@ -310,9 +320,9 @@ } static gboolean -fu_logitech_hidpp_bootloader_close (FuUsbDevice *device, GError **error) +fu_logitech_hidpp_bootloader_close (FuDevice *device, GError **error) { - GUsbDevice *usb_device = fu_usb_device_get_dev (device); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); if (usb_device != NULL) { if (!g_usb_device_release_interface (usb_device, 0x00, G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, @@ -320,7 +330,9 @@ return FALSE; } } - return TRUE; + + /* FuUsbDevice->close */ + return FU_DEVICE_CLASS (fu_logitech_hidpp_bootloader_parent_class)->close (device, error); } gboolean @@ -445,6 +457,7 @@ { fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + fu_device_add_internal_flag (FU_DEVICE (self), FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID); fu_device_add_icon (FU_DEVICE (self), "preferences-desktop-keyboard"); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_PLAIN); fu_device_set_name (FU_DEVICE (self), "Unifying Receiver"); @@ -456,10 +469,9 @@ fu_logitech_hidpp_bootloader_class_init (FuLogitechHidPpBootloaderClass *klass) { FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); klass_device->to_string = fu_logitech_hidpp_bootloader_to_string; klass_device->attach = fu_logitech_hidpp_bootloader_attach; klass_device->setup = fu_logitech_hidpp_bootloader_setup; - klass_usb_device->open = fu_logitech_hidpp_bootloader_open; - klass_usb_device->close = fu_logitech_hidpp_bootloader_close; + klass_device->open = fu_logitech_hidpp_bootloader_open; + klass_device->close = fu_logitech_hidpp_bootloader_close; } diff -Nru fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-bootloader.h fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-bootloader.h --- fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-bootloader.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-bootloader.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2018 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-bootloader-nordic.c fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-bootloader-nordic.c --- fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-bootloader-nordic.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-bootloader-nordic.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2018 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-bootloader-nordic.h fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-bootloader-nordic.h --- fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-bootloader-nordic.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-bootloader-nordic.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2018 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-bootloader-texas.c fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-bootloader-texas.c --- fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-bootloader-texas.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-bootloader-texas.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2018 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-bootloader-texas.h fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-bootloader-texas.h --- fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-bootloader-texas.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-bootloader-texas.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2018 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-common.c fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-common.c --- fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-common.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-common.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2018 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-common.h fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-common.h --- fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-common.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-common.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2018 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-hidpp.c fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-hidpp.c --- fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-hidpp.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-hidpp.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2018 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-hidpp.h fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-hidpp.h --- fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-hidpp.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-hidpp.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2018 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-hidpp-msg.c fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-hidpp-msg.c --- fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-hidpp-msg.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-hidpp-msg.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-hidpp-msg.h fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-hidpp-msg.h --- fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-hidpp-msg.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-hidpp-msg.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-peripheral.c fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-peripheral.c --- fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-peripheral.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-peripheral.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -15,7 +15,6 @@ struct _FuLogitechHidPpPeripheral { FuUdevDevice parent_instance; - guint8 battery_level; guint8 cached_fw_entity; guint8 hidpp_id; guint8 hidpp_version; @@ -261,9 +260,12 @@ fu_logitech_hidpp_peripheral_to_string (FuDevice *device, guint idt, GString *str) { FuLogitechHidPpPeripheral *self = FU_UNIFYING_PERIPHERAL (device); + + /* FuUdevDevice->to_string */ + FU_DEVICE_CLASS (fu_logitech_hidpp_peripheral_parent_class)->to_string (device, idt, str); + fu_common_string_append_ku (str, idt, "HidppVersion", self->hidpp_version); fu_common_string_append_kx (str, idt, "HidppId", self->hidpp_id); - fu_common_string_append_ku (str, idt, "BatteryLevel", self->battery_level); fu_common_string_append_kb (str, idt, "IsUpdatable", self->is_updatable); fu_common_string_append_kb (str, idt, "IsActive", self->is_active); for (guint i = 0; i < self->feature_index->len; i++) { @@ -376,7 +378,7 @@ return FALSE; } if (msg->data[0] != 0x00) - self->battery_level = msg->data[0]; + fu_device_set_battery_level (FU_DEVICE (self), msg->data[0]); return TRUE; } } @@ -391,7 +393,7 @@ msg->hidpp_version = self->hidpp_version; if (fu_logitech_hidpp_transfer (self->io_channel, msg, NULL)) { if (msg->data[0] != 0x00) - self->battery_level = msg->data[0]; + fu_device_set_battery_level (FU_DEVICE (self), msg->data[0]); return TRUE; } @@ -400,16 +402,16 @@ if (fu_logitech_hidpp_transfer (self->io_channel, msg, NULL)) { switch (msg->data[0]) { case 1: /* 0 - 10 */ - self->battery_level = 5; + fu_device_set_battery_level (FU_DEVICE (self), 5); break; case 3: /* 11 - 30 */ - self->battery_level = 20; + fu_device_set_battery_level (FU_DEVICE (self), 20); break; case 5: /* 31 - 80 */ - self->battery_level = 55; + fu_device_set_battery_level (FU_DEVICE (self), 55); break; case 7: /* 81 - 100 */ - self->battery_level = 90; + fu_device_set_battery_level (FU_DEVICE (self), 90); break; default: g_warning ("unknown battery percentage: 0x%02x", @@ -468,22 +470,26 @@ } static gboolean -fu_logitech_hidpp_peripheral_probe (FuUdevDevice *device, GError **error) +fu_logitech_hidpp_peripheral_probe (FuDevice *device, GError **error) { g_autofree gchar *devid = NULL; + /* FuUdevDevice->probe */ + if (!FU_DEVICE_CLASS (fu_logitech_hidpp_peripheral_parent_class)->probe (device, error)) + return FALSE; + /* set the physical ID */ - if (!fu_udev_device_set_physical_id (device, "hid", error)) + if (!fu_udev_device_set_physical_id (FU_UDEV_DEVICE (device), "hid", error)) return FALSE; /* nearly... */ - fu_device_set_vendor_id (FU_DEVICE (device), "USB:0x046D"); + fu_device_add_vendor_id (device, "USB:0x046D"); /* this is a non-standard extension */ devid = g_strdup_printf ("UFY\\VID_%04X&PID_%04X", - fu_udev_device_get_vendor (device), - fu_udev_device_get_model (device)); - fu_device_add_instance_id (FU_DEVICE (device), devid); + fu_udev_device_get_vendor (FU_UDEV_DEVICE (device)), + fu_udev_device_get_model (FU_UDEV_DEVICE (device))); + fu_device_add_instance_id (device, devid); return TRUE; } @@ -577,6 +583,7 @@ if (idx != 0x00) { self->is_updatable = TRUE; fu_device_remove_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + fu_device_add_protocol (FU_DEVICE (self), "com.logitech.unifying"); } idx = fu_logitech_hidpp_peripheral_feature_get_idx (self, HIDPP_FEATURE_DFU_CONTROL_SIGNED); if (idx != 0x00) { @@ -597,7 +604,7 @@ self->is_updatable = TRUE; fu_device_remove_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); } - fu_device_set_protocol (FU_DEVICE (device), "com.logitech.unifyingsigned"); + fu_device_add_protocol (FU_DEVICE (device), "com.logitech.unifyingsigned"); } idx = fu_logitech_hidpp_peripheral_feature_get_idx (self, HIDPP_FEATURE_DFU); if (idx != 0x00) { @@ -607,6 +614,10 @@ g_debug ("repairing device in bootloader mode"); fu_device_set_version (FU_DEVICE (device), "MPK00.00_B0000"); } + /* we do not actually know which protocol when in recovery mode, + * so force the metadata to have the specific regex set up */ + fu_device_add_protocol (FU_DEVICE (self), "com.logitech.unifying"); + fu_device_add_protocol (FU_DEVICE (self), "com.logitech.unifyingsigned"); } /* this device may have changed state */ @@ -680,6 +691,7 @@ g_prefix_error (error, "failed to put device into DFU mode: "); return FALSE; } + g_usleep (200 * 1000); return fu_logitech_hidpp_peripheral_setup (FU_DEVICE (self), error); } @@ -861,7 +873,9 @@ } /* check error */ - packet_cnt = fu_common_read_uint32 (msg->data, G_BIG_ENDIAN); + if (!fu_common_read_uint32_safe (msg->data, sizeof(msg->data), 0x0, + &packet_cnt, G_BIG_ENDIAN, error)) + return FALSE; g_debug ("packet_cnt=0x%04x", packet_cnt); if (fu_logitech_hidpp_peripheral_check_status (msg->data[4], &error_local)) return TRUE; @@ -1018,7 +1032,6 @@ fu_logitech_hidpp_peripheral_class_init (FuLogitechHidPpPeripheralClass *klass) { FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - FuUdevDeviceClass *klass_device_udev = FU_UDEV_DEVICE_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = fu_logitech_hidpp_peripheral_finalize; @@ -1030,7 +1043,7 @@ klass_device->detach = fu_logitech_hidpp_peripheral_detach; klass_device->poll = fu_logitech_hidpp_peripheral_poll; klass_device->to_string = fu_logitech_hidpp_peripheral_to_string; - klass_device_udev->probe = fu_logitech_hidpp_peripheral_probe; + klass_device->probe = fu_logitech_hidpp_peripheral_probe; } static void @@ -1040,10 +1053,10 @@ self->feature_index = g_ptr_array_new_with_free_func (g_free); fu_device_add_parent_guid (FU_DEVICE (self), "HIDRAW\\VEN_046D&DEV_C52B"); fu_device_set_remove_delay (FU_DEVICE (self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); - fu_device_set_protocol (FU_DEVICE (self), "com.logitech.unifying"); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_PLAIN); /* there are a lot of unifying peripherals, but not all respond * well to opening -- so limit to ones with issued updates */ - fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_ONLY_SUPPORTED); + fu_device_add_internal_flag (FU_DEVICE (self), + FU_DEVICE_INTERNAL_FLAG_ONLY_SUPPORTED); } diff -Nru fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-peripheral.h fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-peripheral.h --- fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-peripheral.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-peripheral.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-runtime.c fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-runtime.c --- fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-runtime.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-runtime.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2018 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -26,6 +26,7 @@ fu_logitech_hidpp_runtime_to_string (FuDevice *device, guint idt, GString *str) { FuLogitechHidPpRuntime *self = FU_UNIFYING_RUNTIME (device); + FU_DEVICE_CLASS (fu_logitech_hidpp_runtime_parent_class)->to_string (device, idt, str); fu_common_string_append_kb (str, idt, "SignedFirmware", self->signed_firmware); } @@ -128,15 +129,19 @@ } static gboolean -fu_logitech_hidpp_runtime_probe (FuUdevDevice *device, GError **error) +fu_logitech_hidpp_runtime_probe (FuDevice *device, GError **error) { FuLogitechHidPpRuntime *self = FU_UNIFYING_RUNTIME (device); GUdevDevice *udev_device = fu_udev_device_get_dev (FU_UDEV_DEVICE (device)); guint16 release = 0xffff; g_autoptr(GUdevDevice) udev_parent = NULL; + /* FuUdevDevice->probe */ + if (!FU_DEVICE_CLASS (fu_logitech_hidpp_runtime_parent_class)->probe (device, error)) + return FALSE; + /* set the physical ID */ - if (!fu_udev_device_set_physical_id (device, "usb", error)) + if (!fu_udev_device_set_physical_id (FU_UDEV_DEVICE (device), "usb", error)) return FALSE; /* generate bootloader-specific GUID */ @@ -156,7 +161,7 @@ devid2 = g_strdup_printf ("USB\\VID_%04X&PID_%04X", (guint) FU_UNIFYING_DEVICE_VID, (guint) FU_UNIFYING_DEVICE_PID_BOOTLOADER_NORDIC); - fu_device_add_counterpart_guid (FU_DEVICE (device), devid2); + fu_device_add_counterpart_guid (device, devid2); self->version_bl_major = 0x01; break; case 0x2400: @@ -164,7 +169,7 @@ devid2 = g_strdup_printf ("USB\\VID_%04X&PID_%04X", (guint) FU_UNIFYING_DEVICE_VID, (guint) FU_UNIFYING_DEVICE_PID_BOOTLOADER_TEXAS); - fu_device_add_counterpart_guid (FU_DEVICE (device), devid2); + fu_device_add_counterpart_guid (device, devid2); self->version_bl_major = 0x03; break; default: @@ -229,11 +234,11 @@ if ((self->version_bl_major == 0x01 && config[8] >= 0x04) || (self->version_bl_major == 0x03 && config[8] >= 0x02)) { self->signed_firmware = TRUE; - fu_device_set_protocol (device, "com.logitech.unifyingsigned"); + fu_device_add_protocol (device, "com.logitech.unifyingsigned"); } } if (!self->signed_firmware) - fu_device_set_protocol (device, "com.logitech.unifying"); + fu_device_add_protocol (device, "com.logitech.unifying"); /* enable HID++ notifications */ if (!fu_logitech_hidpp_runtime_enable_notifications (self, error)) { @@ -306,12 +311,11 @@ fu_logitech_hidpp_runtime_class_init (FuLogitechHidPpRuntimeClass *klass) { FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - FuUdevDeviceClass *klass_device_udev = FU_UDEV_DEVICE_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = fu_logitech_hidpp_runtime_finalize; klass_device->open = fu_logitech_hidpp_runtime_open; - klass_device_udev->probe = fu_logitech_hidpp_runtime_probe; + klass_device->probe = fu_logitech_hidpp_runtime_probe; klass_device->setup = fu_logitech_hidpp_runtime_setup; klass_device->close = fu_logitech_hidpp_runtime_close; klass_device->detach = fu_logitech_hidpp_runtime_detach; @@ -323,6 +327,7 @@ fu_logitech_hidpp_runtime_init (FuLogitechHidPpRuntime *self) { fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_internal_flag (FU_DEVICE (self), FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_PLAIN); fu_device_add_icon (FU_DEVICE (self), "preferences-desktop-keyboard"); fu_device_set_name (FU_DEVICE (self), "Unifying Receiver"); diff -Nru fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-runtime.h fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-runtime.h --- fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-runtime.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-runtime.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2018 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-self-test.c fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-self-test.c --- fwupd-1.4.5/plugins/logitech-hidpp/fu-logitech-hidpp-self-test.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/logitech-hidpp/fu-logitech-hidpp-self-test.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/logitech-hidpp/fu-plugin-logitech-hidpp.c fwupd-1.5.8/plugins/logitech-hidpp/fu-plugin-logitech-hidpp.c --- fwupd-1.4.5/plugins/logitech-hidpp/fu-plugin-logitech-hidpp.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/logitech-hidpp/fu-plugin-logitech-hidpp.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2018 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -9,7 +9,6 @@ #include #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #include "fu-logitech-hidpp-bootloader-nordic.h" #include "fu-logitech-hidpp-bootloader-texas.h" diff -Nru fwupd-1.4.5/plugins/logitech-hidpp/logitech-hidpp.quirk fwupd-1.5.8/plugins/logitech-hidpp/logitech-hidpp.quirk --- fwupd-1.4.5/plugins/logitech-hidpp/logitech-hidpp.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/logitech-hidpp/logitech-hidpp.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,12 +1,12 @@ # Unifying Receiver -[DeviceInstanceId=HIDRAW\VEN_046D&DEV_C52B] +[HIDRAW\VEN_046D&DEV_C52B] Plugin = logitech_hidpp GType = FuLogitechHidPpRuntime VendorId=USB:0x046D InstallDuration = 30 # Nordic -[DeviceInstanceId=USB\VID_046D&PID_AAAA] +[USB\VID_046D&PID_AAAA] Plugin = logitech_hidpp GType = FuLogitechHidPpBootloaderNordic FirmwareSizeMin = 0x4000 @@ -14,7 +14,7 @@ InstallDuration = 30 # Nordic Pico -[DeviceInstanceId=USB\VID_046D&PID_AAAE] +[USB\VID_046D&PID_AAAE] Plugin = logitech_hidpp GType = FuLogitechHidPpBootloaderNordic FirmwareSizeMin = 0x4000 @@ -22,7 +22,7 @@ InstallDuration = 30 # Texas -[DeviceInstanceId=USB\VID_046D&PID_AAAC] +[USB\VID_046D&PID_AAAC] Plugin = logitech_hidpp GType = FuLogitechHidPpBootloaderTexas FirmwareSizeMin = 0x4000 @@ -30,7 +30,7 @@ InstallDuration = 18 # Texas Pico -[DeviceInstanceId=USB\VID_046D&PID_AAAD] +[USB\VID_046D&PID_AAAD] Plugin = logitech_hidpp GType = FuLogitechHidPpBootloaderTexas FirmwareSizeMin = 0x4000 @@ -38,6 +38,6 @@ InstallDuration = 18 # Possible HID++ v2.0 peripheral device -[DeviceInstanceId=HIDRAW\VEN_046D] +[HIDRAW\VEN_046D] Plugin = logitech_hidpp GType = FuLogitechHidPpPeripheral diff -Nru fwupd-1.4.5/plugins/logitech-hidpp/meson.build fwupd-1.5.8/plugins/logitech-hidpp/meson.build --- fwupd-1.4.5/plugins/logitech-hidpp/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/logitech-hidpp/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,4 @@ +if get_option('gudev') and get_option('gusb') cargs = ['-DG_LOG_DOMAIN="FuPluginLogitechHidPp"'] install_data([ @@ -61,3 +62,4 @@ ) test('logitech-hidpp-self-test', e) endif +endif diff -Nru fwupd-1.4.5/plugins/logitech-hidpp/README.md fwupd-1.5.8/plugins/logitech-hidpp/README.md --- fwupd-1.4.5/plugins/logitech-hidpp/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/logitech-hidpp/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -47,6 +47,20 @@ The vendor ID is set from the vendor ID, in this instance set to `USB:0x046D` in bootloader and `HIDRAW:0x046D` in runtime mode. +Update Behavior +--------------- + +The peripheral firmware is deployed when the device is in normal runtime mode, +and the device will reset when the new firmware has been written. + +The reciever device presents in runtime mode, but on detach re-enumerates with a +different USB PID in a bootloader mode. On attach the device again re-enumerates +back to the runtime mode. All unifying devices attached to the reciever will not +work for the duration of the update. + +For this reason the `REPLUG_MATCH_GUID` internal device flag is used so that +the bootloader and runtime modes are treated as the same device. + Design Notes ------------ @@ -58,3 +72,7 @@ [1] https://www.mousejack.com/ [2] https://pwr-Solaar.github.io/Solaar/ + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff -Nru fwupd-1.4.5/plugins/meson.build fwupd-1.5.8/plugins/meson.build --- fwupd-1.4.5/plugins/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,94 +1,66 @@ +subdir('acpi-dmar') +subdir('acpi-facp') +subdir('altos') +subdir('amt') +subdir('ata') +subdir('bcm57xx') +subdir('bios') subdir('ccgx') +subdir('colorhug') subdir('cpu') +subdir('cros-ec') +subdir('dell') +subdir('dell-dock') +subdir('dell-esrt') subdir('dfu') -subdir('colorhug') +subdir('dfu-csr') subdir('ebitdo') +subdir('elantp') +subdir('emmc') subdir('ep963x') subdir('fastboot') +subdir('flashrom') subdir('fresco-pd') +subdir('goodix-moc') +subdir('hailuck') +subdir('iommu') subdir('jabra') -subdir('steelseries') -subdir('dell-dock') +subdir('linux-lockdown') +subdir('linux-sleep') +subdir('linux-swap') +subdir('linux-tainted') +subdir('logind') +subdir('logitech-hidpp') +subdir('modem-manager') +subdir('msr') subdir('nitrokey') +subdir('nvme') +subdir('optionrom') +subdir('pci-bcr') +subdir('pci-mei') +subdir('pixart-rf') +subdir('platform-integrity') +subdir('redfish') subdir('rts54hid') subdir('rts54hub') subdir('solokey') +subdir('steelseries') +subdir('superio') subdir('synaptics-cxaudio') +subdir('synaptics-mst') subdir('synaptics-prometheus') -subdir('test') -subdir('upower') -subdir('wacom-usb') -subdir('vli') - -if get_option('gudev') -subdir('ata') -subdir('logitech-hidpp') -subdir('optionrom') -subdir('superio') subdir('synaptics-rmi') subdir('system76-launch') +subdir('test') subdir('thelio-io') -subdir('wacom-raw') -endif - -if get_option('systemd') -subdir('logind') -endif - -# depends on dfu -subdir('csr') - -if get_option('plugin_tpm') and get_option('gudev') +subdir('thunderbolt') subdir('tpm') subdir('tpm-eventlog') -endif - -if get_option('plugin_emmc') and get_option('gudev') -subdir('emmc') -endif - -if get_option('plugin_nvme') and get_option('gudev') -subdir('nvme') -endif - -if get_option('plugin_modem_manager') -subdir('modem-manager') -endif - -if get_option('plugin_altos') and get_option('gudev') -subdir('altos') -endif - -if get_option('plugin_amt') -subdir('amt') -endif - -if get_option('plugin_thunderbolt') and get_option('gudev') -subdir('thunderbolt') -endif - -if get_option('plugin_redfish') -subdir('redfish') -endif - -if get_option('plugin_dell') -subdir('dell') -subdir('dell-esrt') -endif - -if get_option('plugin_synaptics') and get_option('gudev') -subdir('synaptics-mst') -endif - -if get_option('plugin_uefi') -subdir('uefi') +subdir('uefi-capsule') +subdir('uefi-dbx') +subdir('uefi-pk') subdir('uefi-recovery') -endif - -if get_option('plugin_flashrom') -subdir('flashrom') -endif - -if get_option('plugin_coreboot') -subdir('coreboot') -endif +subdir('upower') +subdir('vli') +subdir('wacom-raw') +subdir('wacom-usb') diff -Nru fwupd-1.4.5/plugins/modem-manager/fu-mm-device.c fwupd-1.5.8/plugins/modem-manager/fu-mm-device.c --- fwupd-1.4.5/plugins/modem-manager/fu-mm-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/modem-manager/fu-mm-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -43,6 +43,7 @@ MMModemFirmwareUpdateMethod update_methods; gchar *detach_fastboot_at; gint port_at_ifnum; + gint port_qmi_ifnum; /* fastboot detach handling */ gchar *port_at; @@ -102,6 +103,35 @@ return device->port_at_ifnum; } +gint +fu_mm_device_get_port_qmi_ifnum (FuMmDevice *device) +{ + g_return_val_if_fail (FU_IS_MM_DEVICE (device), -1); + return device->port_qmi_ifnum; +} + +static gboolean +validate_firmware_update_method (MMModemFirmwareUpdateMethod methods, GError **error) +{ + static const MMModemFirmwareUpdateMethod supported_combinations[] = { + MM_MODEM_FIRMWARE_UPDATE_METHOD_FASTBOOT, + MM_MODEM_FIRMWARE_UPDATE_METHOD_QMI_PDC | MM_MODEM_FIRMWARE_UPDATE_METHOD_FASTBOOT, + }; + g_autofree gchar *methods_str = NULL; + + methods_str = mm_modem_firmware_update_method_build_string_from_mask (methods); + for (guint i = 0; i < G_N_ELEMENTS (supported_combinations); i++) { + if (supported_combinations[i] == methods) { + g_debug ("valid firmware update combination: %s", methods_str); + return TRUE; + } + } + + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, + "invalid firmware update combination: %s", methods_str); + return FALSE; +} + static gboolean fu_mm_device_probe_default (FuDevice *device, GError **error) { @@ -131,6 +161,10 @@ return FALSE; } + /* make sure the combination is supported */ + if (!validate_firmware_update_method (self->update_methods, error)) + return FALSE; + /* various fastboot commands */ if (self->update_methods & MM_MODEM_FIRMWARE_UPDATE_METHOD_FASTBOOT) { const gchar *tmp; @@ -180,7 +214,7 @@ break; } } - fu_device_set_protocol (device, "com.google.fastboot"); + fu_device_add_protocol (device, "com.google.fastboot"); } if (self->update_methods & MM_MODEM_FIRMWARE_UPDATE_METHOD_QMI_PDC) { for (guint i = 0; i < n_ports; i++) { @@ -191,8 +225,8 @@ } } /* only set if fastboot wasn't already set */ - if (fu_device_get_protocol (device) == NULL) - fu_device_set_protocol (device, "com.qualcomm.qmi_pdc"); + if (fu_device_get_protocols (device)->len == 0) + fu_device_add_protocol (device, "com.qualcomm.qmi_pdc"); } mm_modem_port_info_array_free (ports, n_ports); @@ -216,13 +250,20 @@ return FALSE; } - /* if we have the at port reported, get sysfs path and interface number */ if (self->port_at != NULL) { fu_mm_utils_get_port_info (self->port_at, &device_sysfs_path, &self->port_at_ifnum, NULL); - } else if (self->port_qmi != NULL) { - fu_mm_utils_get_port_info (self->port_qmi, &device_sysfs_path, NULL, NULL); - } else { - g_warn_if_reached (); + } + if (self->port_qmi != NULL) { + g_autofree gchar *qmi_device_sysfs_path = NULL; + fu_mm_utils_get_port_info (self->port_qmi, &qmi_device_sysfs_path, &self->port_qmi_ifnum, NULL); + if (device_sysfs_path == NULL && qmi_device_sysfs_path != NULL) { + device_sysfs_path = g_steal_pointer (&qmi_device_sysfs_path); + } else if (g_strcmp0 (device_sysfs_path, qmi_device_sysfs_path) != 0) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "mismatched device sysfs path: %s != %s", + device_sysfs_path, qmi_device_sysfs_path); + return FALSE; + } } /* if no device sysfs file, error out */ @@ -243,7 +284,7 @@ fu_device_set_version (device, version); for (guint i = 0; device_ids[i] != NULL; i++) fu_device_add_instance_id (device, device_ids[i]); - if (fu_device_get_vendor_id (device) == NULL) { + if (fu_device_get_vendor_ids (device) == NULL) { g_autofree gchar *path = g_build_filename (device_sysfs_path, "idVendor", NULL); g_autofree gchar *value = NULL; g_autoptr(GError) error_local = NULL; @@ -252,7 +293,7 @@ g_warning ("failed to set vendor ID: %s", error_local->message); } else { g_autofree gchar *vendor_id = g_strdup_printf ("USB:0x%s", g_strchomp (value)); - fu_device_set_vendor_id (device, vendor_id); + fu_device_add_vendor_id (device, vendor_id); } } @@ -418,13 +459,12 @@ * * If the FuMmModem is created from a MM-exposed modem and... * a) we only support fastboot, we just trigger the fastboot detach. - * b) we only support qmi-pdc, we just exit without any detach. - * c) we support both fastboot and qmi-pdc, we will set the + * b) we support both fastboot and qmi-pdc, we will set the * ANOTHER_WRITE_REQUIRED flag in the device and we'll trigger * the fastboot detach. * * If the FuMmModem is created from udev events... - * d) it means we're in the extra required write that was flagged + * c) it means we're in the extra required write that was flagged * in an earlier detach(), and we need to perform the qmi-pdc * update procedure at this time, so we just exit without any * detach. @@ -470,8 +510,6 @@ FuMmDevice *device; GError *error; GPtrArray *file_infos; - gsize total_written; - gsize total_bytes; } FuMmArchiveIterateCtx; static gboolean @@ -521,7 +559,6 @@ file_info->bytes = g_bytes_ref (bytes); file_info->active = fu_mm_should_be_active (fu_device_get_version (FU_DEVICE (ctx->device)), filename); g_ptr_array_add (ctx->file_infos, file_info); - ctx->total_bytes += g_bytes_get_size (file_info->bytes); return TRUE; } @@ -562,8 +599,6 @@ .device = FU_MM_DEVICE (device), .error = NULL, .file_infos = file_infos, - .total_written = 0, - .total_bytes = 0, }; /* decompress entire archive ahead of time */ @@ -726,6 +761,7 @@ { fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_USE_RUNTIME_VERSION); + fu_device_add_internal_flag (FU_DEVICE (self), FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_PLAIN); fu_device_set_summary (FU_DEVICE (self), "Mobile broadband device"); fu_device_add_icon (FU_DEVICE (self), "network-modem"); @@ -775,6 +811,7 @@ self->manager = g_object_ref (manager); self->omodem = g_object_ref (omodem); self->port_at_ifnum = -1; + self->port_qmi_ifnum = -1; return self; } @@ -792,6 +829,7 @@ info->update_methods = fu_mm_device_get_update_methods (device); info->detach_fastboot_at = g_strdup (fu_mm_device_get_detach_fastboot_at (device)); info->port_at_ifnum = fu_mm_device_get_port_at_ifnum (device); + info->port_qmi_ifnum = fu_mm_device_get_port_qmi_ifnum (device); info->inhibited_uid = g_strdup (fu_mm_device_get_inhibition_uid (device)); return info; @@ -825,6 +863,7 @@ self->update_methods = info->update_methods; self->detach_fastboot_at = g_strdup (info->detach_fastboot_at); self->port_at_ifnum = info->port_at_ifnum; + self->port_qmi_ifnum = info->port_qmi_ifnum; for (guint i = 0; i < info->guids->len; i++) fu_device_add_guid (FU_DEVICE (self), g_ptr_array_index (info->guids, i)); @@ -840,17 +879,19 @@ { g_return_if_fail (FU_IS_MM_DEVICE (self)); - /* cdc-wdm ports always added unless one already set */ if (g_str_equal (subsystem, "usbmisc") && - (self->port_qmi == NULL)) { + self->port_qmi == NULL && + ifnum >= 0 && + ifnum == self->port_qmi_ifnum) { g_debug ("added QMI port %s (%s)", path, subsystem); self->port_qmi = g_strdup (path); return; } if (g_str_equal (subsystem, "tty") && - (self->port_at == NULL) && - (ifnum >= 0) && (ifnum == self->port_at_ifnum)) { + self->port_at == NULL && + ifnum >= 0 && + ifnum == self->port_at_ifnum) { g_debug ("added AT port %s (%s)", path, subsystem); self->port_at = g_strdup (path); return; diff -Nru fwupd-1.4.5/plugins/modem-manager/fu-mm-device.h fwupd-1.5.8/plugins/modem-manager/fu-mm-device.h --- fwupd-1.4.5/plugins/modem-manager/fu-mm-device.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/modem-manager/fu-mm-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2019 Richard Hughes + * Copyright (C) 2018 Richard Hughes * Copyright (C) 2019 Aleksander Morgado * * SPDX-License-Identifier: LGPL-2.1+ @@ -20,6 +20,7 @@ const gchar *fu_mm_device_get_inhibition_uid (FuMmDevice *device); const gchar *fu_mm_device_get_detach_fastboot_at (FuMmDevice *device); gint fu_mm_device_get_port_at_ifnum (FuMmDevice *device); +gint fu_mm_device_get_port_qmi_ifnum (FuMmDevice *device); MMModemFirmwareUpdateMethod fu_mm_device_get_update_methods (FuMmDevice *device); /* support for udev-based devices */ @@ -35,6 +36,7 @@ MMModemFirmwareUpdateMethod update_methods; gchar *detach_fastboot_at; gint port_at_ifnum; + gint port_qmi_ifnum; }; FuPluginMmInhibitedDeviceInfo *fu_plugin_mm_inhibited_device_info_new (FuMmDevice *device); void fu_plugin_mm_inhibited_device_info_free (FuPluginMmInhibitedDeviceInfo *info); diff -Nru fwupd-1.4.5/plugins/modem-manager/fu-plugin-modem-manager.c fwupd-1.5.8/plugins/modem-manager/fu-plugin-modem-manager.c --- fwupd-1.4.5/plugins/modem-manager/fu-plugin-modem-manager.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/modem-manager/fu-plugin-modem-manager.c 2021-03-31 20:08:32.000000000 +0000 @@ -10,7 +10,6 @@ #include #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #include "fu-mm-device.h" #include "fu-mm-utils.h" @@ -62,6 +61,8 @@ FuPluginData *priv = fu_plugin_get_data (plugin); g_autoptr(FuPluginMmInhibitedDeviceInfo) info = NULL; + g_clear_object (&priv->udev_client); + /* get the device removed from the plugin cache before uninhibiting */ fu_plugin_mm_udev_device_removed (plugin); @@ -196,11 +197,13 @@ /* setup inhibited device info */ priv->inhibited = g_steal_pointer (&info); - /* as soon as inhibition is place, we need to do modem device monitoring based - * on the udev client, as MM no longer reports devices */ - priv->udev_client = g_udev_client_new (subsystems); - g_signal_connect (priv->udev_client, "uevent", - G_CALLBACK (fu_plugin_mm_udev_uevent_cb), plugin); + /* only do modem port monitoring using udev if the module is expected + * to reset itself into a fully different layout, e.g. a fastboot device */ + if (fu_mm_device_get_update_methods (FU_MM_DEVICE (device)) & MM_MODEM_FIRMWARE_UPDATE_METHOD_FASTBOOT) { + priv->udev_client = g_udev_client_new (subsystems); + g_signal_connect (priv->udev_client, "uevent", + G_CALLBACK (fu_plugin_mm_udev_uevent_cb), plugin); + } return TRUE; } diff -Nru fwupd-1.4.5/plugins/modem-manager/meson.build fwupd-1.5.8/plugins/modem-manager/meson.build --- fwupd-1.4.5/plugins/modem-manager/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/modem-manager/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,4 @@ +if get_option('plugin_modem_manager') cargs = ['-DG_LOG_DOMAIN="FuPluginMm"'] install_data(['modem-manager.quirk'], @@ -32,3 +33,4 @@ libqmi_glib, ], ) +endif diff -Nru fwupd-1.4.5/plugins/modem-manager/modem-manager.quirk fwupd-1.5.8/plugins/modem-manager/modem-manager.quirk --- fwupd-1.4.5/plugins/modem-manager/modem-manager.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/modem-manager/modem-manager.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,40 +1,40 @@ # DW5821e -[DeviceInstanceId=USB\VID_413C&PID_81D7] +[USB\VID_413C&PID_81D7] Summary = Dell DW5821e LTE modem CounterpartGuid = USB\VID_413C&PID_81D6 # DW5821e in fastboot mode -[DeviceInstanceId=USB\VID_413C&PID_81D6] +[USB\VID_413C&PID_81D6] Summary = Dell DW5821e LTE modem (fastboot) CounterpartGuid = USB\VID_413C&PID_81D7 # DW5821e/eSIM -[DeviceInstanceId=USB\VID_413C&PID_81E0] +[USB\VID_413C&PID_81E0] Summary = Dell DW5821e/eSIM LTE modem CounterpartGuid = USB\VID_413C&PID_81E1 # DW5821e/eSIM in fastboot mode -[DeviceInstanceId=USB\VID_413C&PID_81E1] +[USB\VID_413C&PID_81E1] Summary = Dell DW5821e/eSIM LTE modem (fastboot) CounterpartGuid = USB\VID_413C&PID_81E0 # T77W968 -[DeviceInstanceId=USB\VID_0489&PID_E0B4] +[USB\VID_0489&PID_E0B4] Summary = Foxconn T77w968 LTE modem CounterpartGuid = USB\VID_0489&PID_E0B7 # T77W968 in fastboot mode -[DeviceInstanceId=USB\VID_0489&PID_E0B7] +[USB\VID_0489&PID_E0B7] Summary = Foxconn T77w968 LTE modem (fastboot) CounterpartGuid = USB\VID_0489&PID_E0B4 # T77W968/eSIM -[DeviceInstanceId=USB\VID_0489&PID_E0B5] +[USB\VID_0489&PID_E0B5] Summary = Foxconn T77w968/eSIM LTE modem CounterpartGuid = USB\VID_0489&PID_E0B8 # T77W968/eSIM in fastboot mode -[DeviceInstanceId=USB\VID_0489&PID_E0B8] +[USB\VID_0489&PID_E0B8] Summary = Foxconn T77w968/eSIM LTE modem (fastboot) CounterpartGuid = USB\VID_0489&PID_E0B5 diff -Nru fwupd-1.4.5/plugins/modem-manager/README.md fwupd-1.5.8/plugins/modem-manager/README.md --- fwupd-1.4.5/plugins/modem-manager/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/modem-manager/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -34,6 +34,9 @@ Update Protocol: com.google.fastboot +For this reason the `REPLUG_MATCH_GUID` internal device flag is used so that +the fastboot and runtime modes are treated as the same device. + Update method: qmi-pdc ---------------------- @@ -48,3 +51,10 @@ the new ones. Update protocol: com.qualcomm.qmi_pdc + +For this reason the `REPLUG_MATCH_GUID` internal device flag is used so that +the fastboot and runtime modes are treated as the same device. + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff -Nru fwupd-1.4.5/plugins/msr/fu-plugin-msr.c fwupd-1.5.8/plugins/msr/fu-plugin-msr.c --- fwupd-1.4.5/plugins/msr/fu-plugin-msr.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/msr/fu-plugin-msr.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-plugin-vfuncs.h" + +typedef union { + guint32 data; + struct { + guint32 enabled : 1; + guint32 rsrvd : 29; + guint32 locked : 1; + guint32 debug_occurred : 1; + } __attribute__((packed)) fields; +} FuMsrIa32Debug; + +typedef union { + guint32 data; + struct { + guint32 unknown0 : 23; /* 0 -> 22 inc */ + guint32 sev_is_enabled : 1; + guint32 unknown1 : 8; + } __attribute__((packed)) fields; +} FuMsrK8Syscfg; + +struct FuPluginData { + gboolean ia32_debug_supported; + FuMsrIa32Debug ia32_debug; + gboolean k8_syscfg_supported; + FuMsrK8Syscfg k8_syscfg; +}; + +#define PCI_MSR_IA32_DEBUG_INTERFACE 0xc80 +#define PCI_MSR_IA32_BIOS_SIGN_ID 0x8b +#define PCI_MSR_K8_SYSCFG 0xC0010010 + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_udev_subsystem (plugin, "msr"); +} + +gboolean +fu_plugin_startup (FuPlugin *plugin, GError **error) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + guint eax = 0; + guint ecx = 0; + + /* sdbg is supported: https://en.wikipedia.org/wiki/CPUID */ + if (fu_common_get_cpu_vendor () == FU_CPU_VENDOR_INTEL) { + if (!fu_common_cpuid (0x01, NULL, NULL, &ecx, NULL, error)) + return FALSE; + priv->ia32_debug_supported = ((ecx >> 11) & 0x1) > 0; + } + + /* indicates support for SEV */ + if (fu_common_get_cpu_vendor () == FU_CPU_VENDOR_AMD) { + if (!fu_common_cpuid (0x8000001f, &eax, NULL, NULL, NULL, error)) + return FALSE; + priv->k8_syscfg_supported = ((eax >> 0) & 0x1) > 0; + } + + return TRUE; +} + +gboolean +fu_plugin_backend_device_added (FuPlugin *plugin, FuDevice *device, GError **error) +{ + FuDevice *device_cpu = fu_plugin_cache_lookup (plugin, "cpu"); + FuPluginData *priv = fu_plugin_get_data (plugin); + guint8 buf[8] = { 0x0 }; + g_autoptr(FuDeviceLocker) locker = NULL; + g_autofree gchar *basename = NULL; + + /* interesting device? */ + if (!FU_IS_UDEV_DEVICE (device)) + return TRUE; + if (g_strcmp0 (fu_udev_device_get_subsystem (FU_UDEV_DEVICE (device)), "msr") != 0) + return TRUE; + + /* we only care about the first processor */ + basename = g_path_get_basename (fu_udev_device_get_sysfs_path (FU_UDEV_DEVICE (device))); + if (g_strcmp0 (basename, "msr0") != 0) + return TRUE; + + /* open the config */ + fu_device_set_physical_id (FU_DEVICE (device), "msr"); + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + + /* grab MSR */ + if (priv->ia32_debug_supported) { + if (!fu_udev_device_pread_full (FU_UDEV_DEVICE (device), PCI_MSR_IA32_DEBUG_INTERFACE, + buf, sizeof(buf), error)) { + g_prefix_error (error, "could not read IA32_DEBUG_INTERFACE: "); + return FALSE; + } + if (!fu_common_read_uint32_safe (buf, sizeof(buf), 0x0, + &priv->ia32_debug.data, G_LITTLE_ENDIAN, + error)) + return FALSE; + g_debug ("IA32_DEBUG_INTERFACE: enabled=%i, locked=%i, debug_occurred=%i", + priv->ia32_debug.fields.enabled, + priv->ia32_debug.fields.locked, + priv->ia32_debug.fields.debug_occurred); + } + + /* grab MSR */ + if (priv->k8_syscfg_supported) { + if (!fu_udev_device_pread_full (FU_UDEV_DEVICE (device), PCI_MSR_K8_SYSCFG, + buf, sizeof(buf), error)) { + g_prefix_error (error, "could not read MSR_K8_SYSCFG: "); + return FALSE; + } + if (!fu_common_read_uint32_safe (buf, sizeof(buf), 0x0, + &priv->k8_syscfg.data, G_LITTLE_ENDIAN, + error)) + return FALSE; + g_debug ("MSR_K8_SYSCFG: sev_is_enabled=%i", + priv->k8_syscfg.fields.sev_is_enabled); + } + + /* get microcode version */ + if (device_cpu != NULL) { + guint32 ver_raw; + if (!fu_udev_device_pread_full (FU_UDEV_DEVICE (device), PCI_MSR_IA32_BIOS_SIGN_ID, + buf, sizeof(buf), error)) { + g_prefix_error (error, "could not read IA32_BIOS_SIGN_ID: "); + return FALSE; + } + fu_common_dump_raw (G_LOG_DOMAIN, "IA32_BIOS_SIGN_ID", buf, sizeof(buf)); + if (!fu_common_read_uint32_safe (buf, sizeof(buf), 0x4, + &ver_raw, G_LITTLE_ENDIAN, + error)) + return FALSE; + if (ver_raw != 0) { + FwupdVersionFormat verfmt = fu_device_get_version_format (device_cpu); + g_autofree gchar *ver_str = NULL; + ver_str = fu_common_version_from_uint32 (ver_raw, verfmt); + g_debug ("setting microcode version to %s", ver_str); + fu_device_set_version (device_cpu, ver_str); + fu_device_set_version_raw (device_cpu, ver_raw); + } + } + + /* success */ + return TRUE; +} + +void +fu_plugin_device_registered (FuPlugin *plugin, FuDevice *dev) +{ + if (g_strcmp0 (fu_device_get_plugin (dev), "cpu") == 0) { + fu_plugin_cache_add (plugin, "cpu", dev); + return; + } +} + +static void +fu_plugin_add_security_attr_dci_enabled (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* this MSR is only valid for a subset of Intel CPUs */ + if (fu_common_get_cpu_vendor () != FU_CPU_VENDOR_INTEL) + return; + if (!priv->ia32_debug_supported) + return; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_INTEL_DCI_ENABLED); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fu_security_attrs_append (attrs, attr); + + /* check fields */ + if (priv->ia32_debug.fields.enabled) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); +} + +static void +fu_plugin_add_security_attr_dci_locked (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* this MSR is only valid for a subset of Intel CPUs */ + if (fu_common_get_cpu_vendor () != FU_CPU_VENDOR_INTEL) + return; + if (!priv->ia32_debug_supported) + return; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_INTEL_DCI_LOCKED); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT); + fu_security_attrs_append (attrs, attr); + + /* check fields */ + if (!priv->ia32_debug.fields.locked) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_LOCKED); +} + +static void +fu_plugin_add_security_attr_amd_tsme_enabled (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* this MSR is only valid for a subset of AMD CPUs */ + if (fu_common_get_cpu_vendor () != FU_CPU_VENDOR_AMD) + return; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_ENCRYPTED_RAM); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_PROTECTION); + fu_security_attrs_append (attrs, attr); + + /* check fields */ + if (!priv->k8_syscfg_supported) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED); + return; + } + if (!priv->k8_syscfg.fields.sev_is_enabled) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + fu_plugin_add_security_attr_dci_enabled (plugin, attrs); + fu_plugin_add_security_attr_dci_locked (plugin, attrs); + fu_plugin_add_security_attr_amd_tsme_enabled (plugin, attrs); +} diff -Nru fwupd-1.4.5/plugins/msr/fwupd-msr.conf fwupd-1.5.8/plugins/msr/fwupd-msr.conf --- fwupd-1.4.5/plugins/msr/fwupd-msr.conf 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/msr/fwupd-msr.conf 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +msr diff -Nru fwupd-1.4.5/plugins/msr/meson.build fwupd-1.5.8/plugins/msr/meson.build --- fwupd-1.4.5/plugins/msr/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/msr/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,35 @@ +if get_option('plugin_msr') +cargs = ['-DG_LOG_DOMAIN="FuPluginMsr"'] + +install_data(['msr.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +if get_option('systemd') +install_data(['fwupd-msr.conf'], + install_dir: systemd_modules_load_dir, +) +endif + +shared_module('fu_plugin_msr', + fu_hash, + sources : [ + 'fu-plugin-msr.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) +endif diff -Nru fwupd-1.4.5/plugins/msr/msr.quirk fwupd-1.5.8/plugins/msr/msr.quirk --- fwupd-1.4.5/plugins/msr/msr.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/msr/msr.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,3 @@ +# match all devices with this udev subsystem +[MSR] +Plugin = msr diff -Nru fwupd-1.4.5/plugins/msr/README.md fwupd-1.5.8/plugins/msr/README.md --- fwupd-1.4.5/plugins/msr/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/msr/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,18 @@ +MSR +=== + +Introduction +------------ + +This plugin checks if the Model-specific registers (MSRs) indicate the +Direct Connect Interface (DCI) is enabled. + +DCI allows debugging of Intel processors using the USB3 port. DCI should +always be disabled and locked on production hardware as it allows the +attacker to disable other firmware protection methods. + +The result will be stored in a security attribute for HSI. + +External interface access +------------------------- +This plugin requires read access to `/sys/class/msr`. diff -Nru fwupd-1.4.5/plugins/nitrokey/fu-nitrokey-device.c fwupd-1.5.8/plugins/nitrokey/fu-nitrokey-device.c --- fwupd-1.4.5/plugins/nitrokey/fu-nitrokey-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/nitrokey/fu-nitrokey-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2017 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -130,14 +130,15 @@ } static void -fu_nitrokey_device_init (FuNitrokeyDevice *device) +fu_nitrokey_device_init (FuNitrokeyDevice *self) { - fu_device_set_remove_delay (FU_DEVICE (device), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); - fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_UPDATABLE); - fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_ADD_COUNTERPART_GUIDS); - fu_device_set_version_format (FU_DEVICE (device), FWUPD_VERSION_FORMAT_PAIR); - fu_device_set_protocol (FU_DEVICE (device), "org.usb.dfu"); - fu_device_retry_set_delay (FU_DEVICE (device), 100); + fu_device_set_remove_delay (FU_DEVICE (self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_ADD_COUNTERPART_GUIDS); + fu_device_add_internal_flag (FU_DEVICE (self), FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID); + fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_PAIR); + fu_device_add_protocol (FU_DEVICE (self), "org.usb.dfu"); + fu_device_retry_set_delay (FU_DEVICE (self), 100); } static void diff -Nru fwupd-1.4.5/plugins/nitrokey/fu-plugin-nitrokey.c fwupd-1.5.8/plugins/nitrokey/fu-plugin-nitrokey.c --- fwupd-1.4.5/plugins/nitrokey/fu-plugin-nitrokey.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/nitrokey/fu-plugin-nitrokey.c 2021-03-31 20:08:32.000000000 +0000 @@ -7,7 +7,6 @@ #include "config.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #include "fu-nitrokey-device.h" #include "fu-nitrokey-common.h" diff -Nru fwupd-1.4.5/plugins/nitrokey/fu-self-test.c fwupd-1.5.8/plugins/nitrokey/fu-self-test.c --- fwupd-1.4.5/plugins/nitrokey/fu-self-test.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/nitrokey/fu-self-test.c 2021-03-31 20:08:32.000000000 +0000 @@ -7,6 +7,7 @@ #include "config.h" #include +#include #include "fu-nitrokey-common.h" diff -Nru fwupd-1.4.5/plugins/nitrokey/meson.build fwupd-1.5.8/plugins/nitrokey/meson.build --- fwupd-1.4.5/plugins/nitrokey/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/nitrokey/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -19,6 +19,7 @@ install : true, install_dir: plugin_dir, link_with : [ + fwupd, fwupdplugin, ], c_args : cargs, @@ -47,6 +48,8 @@ link_with : [ fwupdplugin, ], + install : true, + install_dir : installed_test_bindir, ) - test('nitrokey-self-test', e) + test('nitrokey-self-test', e) # added to installed-tests endif diff -Nru fwupd-1.4.5/plugins/nitrokey/nitrokey.quirk fwupd-1.5.8/plugins/nitrokey/nitrokey.quirk --- fwupd-1.4.5/plugins/nitrokey/nitrokey.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/nitrokey/nitrokey.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ # Nitrokey Storage -[DeviceInstanceId=USB\VID_20A0&PID_4109] +[USB\VID_20A0&PID_4109] Plugin = nitrokey Flags = needs-bootloader,use-runtime-version CounterpartGuid = USB\VID_03EB&PID_2FF1 diff -Nru fwupd-1.4.5/plugins/nitrokey/README.md fwupd-1.5.8/plugins/nitrokey/README.md --- fwupd-1.4.5/plugins/nitrokey/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/nitrokey/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -20,8 +20,24 @@ * `USB\VID_20A0&PID_4109` * `USB\VID_20A0` +Update Behavior +--------------- + +The device usually presents in runtime mode, but on detach re-enumerates with a +different USB VID and PID in DFU mode. The device is then handled by the `dfu` +plugin. + +On DFU attach the device again re-enumerates back to the runtime mode. + +For this reason the `REPLUG_MATCH_GUID` internal device flag is used so that +the bootloader and runtime modes are treated as the same device. + Vendor ID Security ------------------ The vendor ID is set from the USB vendor, in this instance set to `USB:0x20A0` in runtime mode and `USB:0x03EB` in bootloader mode. + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff -Nru fwupd-1.4.5/plugins/nvme/fu-nvme-device.c fwupd-1.5.8/plugins/nvme/fu-nvme-device.c --- fwupd-1.4.5/plugins/nvme/fu-nvme-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/nvme/fu-nvme-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -27,6 +27,7 @@ fu_nvme_device_to_string (FuDevice *device, guint idt, GString *str) { FuNvmeDevice *self = FU_NVME_DEVICE (device); + FU_DEVICE_CLASS (fu_nvme_device_parent_class)->to_string (device, idt, str); fu_common_string_append_ku (str, idt, "PciDepth", self->pci_depth); } @@ -169,7 +170,8 @@ /* do not add the FuUdevDevice instance IDs as generic firmware * should not be used on these OEM-specific devices */ - fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NO_AUTO_INSTANCE_IDS); + fu_device_add_internal_flag (FU_DEVICE (self), + FU_DEVICE_INTERNAL_FLAG_NO_AUTO_INSTANCE_IDS); /* add instance ID *and* GUID as using no-auto-instance-ids */ devid = g_strdup_printf ("STORAGE-DELL-%s", component_id); @@ -261,25 +263,29 @@ } static gboolean -fu_nvme_device_probe (FuUdevDevice *device, GError **error) +fu_nvme_device_probe (FuDevice *device, GError **error) { FuNvmeDevice *self = FU_NVME_DEVICE (device); + /* FuUdevDevice->probe */ + if (!FU_DEVICE_CLASS (fu_nvme_device_parent_class)->probe (device, error)) + return FALSE; + /* set the physical ID */ - if (!fu_udev_device_set_physical_id (device, "pci", error)) + if (!fu_udev_device_set_physical_id (FU_UDEV_DEVICE (device), "pci", error)) return FALSE; /* look at the PCI depth to work out if in an external enclosure */ - self->pci_depth = fu_udev_device_get_slot_depth (device, "pci"); + self->pci_depth = fu_udev_device_get_slot_depth (FU_UDEV_DEVICE (device), "pci"); if (self->pci_depth <= 2) { - fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL); - fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_INTERNAL); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE); } /* all devices need at least a warm reset, but some quirked drives * need a full "cold" shutdown and startup */ - if (!fu_device_has_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) - fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NEEDS_REBOOT); + if (!fu_device_has_flag (self, FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT); return TRUE; } @@ -341,9 +347,9 @@ for (guint i = 0; i < chunks->len; i++) { FuChunk *chk = g_ptr_array_index (chunks, i); if (!fu_nvme_device_fw_download (self, - chk->address, - chk->data, - chk->data_sz, + fu_chunk_get_address (chk), + fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk), error)) { g_prefix_error (error, "failed to write chunk %u: ", i); return FALSE; @@ -393,7 +399,7 @@ fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_PLAIN); fu_device_set_summary (FU_DEVICE (self), "NVM Express Solid State Drive"); fu_device_add_icon (FU_DEVICE (self), "drive-harddisk"); - fu_device_set_protocol (FU_DEVICE (self), "org.nvmexpress"); + fu_device_add_protocol (FU_DEVICE (self), "org.nvmexpress"); fu_udev_device_set_flags (FU_UDEV_DEVICE (self), FU_UDEV_DEVICE_FLAG_OPEN_READ | FU_UDEV_DEVICE_FLAG_VENDOR_FROM_PARENT); @@ -410,13 +416,12 @@ { GObjectClass *object_class = G_OBJECT_CLASS (klass); FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - FuUdevDeviceClass *klass_udev_device = FU_UDEV_DEVICE_CLASS (klass); object_class->finalize = fu_nvme_device_finalize; klass_device->to_string = fu_nvme_device_to_string; klass_device->set_quirk_kv = fu_nvme_device_set_quirk_kv; klass_device->setup = fu_nvme_device_setup; klass_device->write_firmware = fu_nvme_device_write_firmware; - klass_udev_device->probe = fu_nvme_device_probe; + klass_device->probe = fu_nvme_device_probe; } FuNvmeDevice * diff -Nru fwupd-1.4.5/plugins/nvme/fu-plugin-nvme.c fwupd-1.5.8/plugins/nvme/fu-plugin-nvme.c --- fwupd-1.4.5/plugins/nvme/fu-plugin-nvme.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/nvme/fu-plugin-nvme.c 2021-03-31 20:08:32.000000000 +0000 @@ -7,7 +7,6 @@ #include "config.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #include "fu-nvme-device.h" diff -Nru fwupd-1.4.5/plugins/nvme/fu-self-test.c fwupd-1.5.8/plugins/nvme/fu-self-test.c --- fwupd-1.4.5/plugins/nvme/fu-self-test.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/nvme/fu-self-test.c 2021-03-31 20:08:32.000000000 +0000 @@ -16,12 +16,18 @@ { gboolean ret; gsize sz; + const gchar *ci = g_getenv ("CI_NETWORK"); g_autofree gchar *data = NULL; g_autofree gchar *path = NULL; g_autoptr(FuNvmeDevice) dev = NULL; g_autoptr(GError) error = NULL; - path = g_build_filename (TESTDATADIR, "TOSHIBA_THNSN5512GPU7.bin", NULL); + path = g_test_build_filename (G_TEST_DIST, "tests", "TOSHIBA_THNSN5512GPU7.bin", NULL); + + if (!g_file_test (path, G_FILE_TEST_EXISTS) && ci == NULL) { + g_test_skip ("Missing TOSHIBA_THNSN5512GPU7.bin"); + return; + } ret = g_file_get_contents (path, &data, &sz, &error); g_assert_no_error (error); g_assert (ret); @@ -43,7 +49,7 @@ g_autoptr(GDir) dir = NULL; /* may or may not exist */ - path = g_build_filename (TESTDATADIR, "blobs", NULL); + path = g_test_build_filename (G_TEST_DIST, "tests", "blobs", NULL); if (!g_file_test (path, G_FILE_TEST_EXISTS)) return; dir = g_dir_open (path, 0, NULL); diff -Nru fwupd-1.4.5/plugins/nvme/meson.build fwupd-1.5.8/plugins/nvme/meson.build --- fwupd-1.4.5/plugins/nvme/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/nvme/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,7 @@ +if get_option('plugin_nvme') +if not get_option('gudev') + error('gudev is required for plugin_nvme') +endif cargs = ['-DG_LOG_DOMAIN="FuPluginNvme"'] install_data([ @@ -34,8 +38,9 @@ ) if get_option('tests') - testdatadir = join_paths(meson.current_source_dir(), 'tests') - cargs += '-DTESTDATADIR="' + testdatadir + '"' + testdatadirs = environment() + testdatadirs.set('G_TEST_SRCDIR', meson.current_source_dir()) + testdatadirs.set('G_TEST_BUILDDIR', meson.current_build_dir()) e = executable( 'nvme-self-test', fu_hash, @@ -56,7 +61,9 @@ fwupd, fwupdplugin, ], - c_args : cargs + install : true, + install_dir : installed_test_bindir, ) - test('nvme-self-test', e) + test('nvme-self-test', e, env : testdatadirs) # added to installed-tests +endif endif diff -Nru fwupd-1.4.5/plugins/nvme/nvme.quirk fwupd-1.5.8/plugins/nvme/nvme.quirk --- fwupd-1.4.5/plugins/nvme/nvme.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/nvme/nvme.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,7 +1,7 @@ # match all devices with this udev subsystem -[DeviceInstanceId=NVME] +[NVME] Plugin = nvme # Phison -[DeviceInstanceId=NVME\VEN_1987] +[NVME\VEN_1987] Flags = force-align,needs-shutdown diff -Nru fwupd-1.4.5/plugins/nvme/README.md fwupd-1.5.8/plugins/nvme/README.md --- fwupd-1.4.5/plugins/nvme/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/nvme/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -41,6 +41,12 @@ and any optional GUID saved in the vendor extension block. +Update Behavior +--------------- + +The firmware is deployed when the device is in normal runtime mode, but it is +only activated when the system is either restarted or in some cases shutdown. + Quirk use --------- This plugin uses the following plugin-specific quirks: @@ -54,3 +60,7 @@ ------------------ The vendor ID is set from the udev vendor, for example set to `NVME:0x1179` + +External interface access +------------------------- +This plugin requires ioctl `NVME_IOCTL_ADMIN_CMD` access. diff -Nru fwupd-1.4.5/plugins/nvme/tests/.gitignore fwupd-1.5.8/plugins/nvme/tests/.gitignore --- fwupd-1.4.5/plugins/nvme/tests/.gitignore 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/nvme/tests/.gitignore 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -blobs Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/nvme/tests/TOSHIBA_THNSN5512GPU7.bin and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/nvme/tests/TOSHIBA_THNSN5512GPU7.bin differ diff -Nru fwupd-1.4.5/plugins/optionrom/fu-optionrom-device.c fwupd-1.5.8/plugins/optionrom/fu-optionrom-device.c --- fwupd-1.4.5/plugins/optionrom/fu-optionrom-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/optionrom/fu-optionrom-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,12 +1,11 @@ /* - * Copyright (C) 2015-2019 Richard Hughes + * Copyright (C) 2015 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" -#include "fu-rom.h" #include "fu-optionrom-device.h" struct _FuOptionromDevice { @@ -16,36 +15,39 @@ G_DEFINE_TYPE (FuOptionromDevice, fu_optionrom_device, FU_TYPE_UDEV_DEVICE) static gboolean -fu_optionrom_device_probe (FuUdevDevice *device, GError **error) +fu_optionrom_device_probe (FuDevice *device, GError **error) { - GUdevDevice *udev_device = fu_udev_device_get_dev (device); - const gchar *guid = NULL; + g_autofree gchar *fn = NULL; - guid = g_udev_device_get_property (udev_device, "FWUPD_GUID"); - if (guid == NULL) { + /* FuUdevDevice->probe */ + if (!FU_DEVICE_CLASS (fu_optionrom_device_parent_class)->probe (device, error)) + return FALSE; + + /* does the device even have ROM? */ + fn = g_build_filename (fu_udev_device_get_sysfs_path (FU_UDEV_DEVICE (device)), "rom", NULL); + if (!g_file_test (fn, G_FILE_TEST_EXISTS)) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, - "no FWUPD_GUID property"); + "Unable to read firmware from device"); return FALSE; } /* set the physical ID */ - if (!fu_udev_device_set_physical_id (device, "pci", error)) - return FALSE; - - return TRUE; + return fu_udev_device_set_physical_id (FU_UDEV_DEVICE (device), "pci", error); } -static FuFirmware * -fu_optionrom_device_read_firmware (FuDevice *device, GError **error) +static GBytes * +fu_optionrom_device_dump_firmware (FuDevice *device, GError **error) { FuUdevDevice *udev_device = FU_UDEV_DEVICE (device); - g_autofree gchar *guid = NULL; + guint number_reads = 0; + g_autofree gchar *fn = NULL; g_autofree gchar *rom_fn = NULL; - g_autoptr(FuRom) rom = NULL; - g_autoptr(GBytes) fw = NULL; + g_autoptr(GByteArray) buf = g_byte_array_new (); + g_autoptr(GError) error_local = NULL; g_autoptr(GFile) file = NULL; + g_autoptr(GInputStream) stream = NULL; /* open the file */ rom_fn = g_build_filename (fu_udev_device_get_sysfs_path (udev_device), "rom", NULL); @@ -56,33 +58,60 @@ "Unable to read firmware from device"); return NULL; } + + /* open file */ file = g_file_new_for_path (rom_fn); - rom = fu_rom_new (); - if (!fu_rom_load_file (rom, file, FU_ROM_LOAD_FLAG_BLANK_PPID, NULL, error)) + stream = G_INPUT_STREAM (g_file_read (file, NULL, &error_local)); + if (stream == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_AUTH_FAILED, + error_local->message); return NULL; + } + + /* we have to enable the read for devices */ + fn = g_file_get_path (file); + if (g_str_has_prefix (fn, "/sys")) { + g_autoptr(GFileOutputStream) output_stream = NULL; + output_stream = g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, + NULL, error); + if (output_stream == NULL) + return NULL; + if (g_output_stream_write (G_OUTPUT_STREAM (output_stream), "1", 1, + NULL, error) < 0) + return NULL; + } - /* update version */ - if (g_strcmp0 (fu_device_get_version (device), - fu_rom_get_version (rom)) != 0) { - g_debug ("changing version of %s from %s to %s", - fu_device_get_id (device), - fu_device_get_version (device), - fu_rom_get_version (rom)); - fu_device_set_version (device, fu_rom_get_version (rom)); - } - - /* Also add the GUID from the firmware as the firmware may be more - * generic, which also allows us to match the GUID when doing 'verify' - * on a device with a different PID to the firmware */ - /* update guid */ - guid = g_strdup_printf ("PCI\\VEN_%04X&DEV_%04X", - fu_rom_get_vendor (rom), - fu_rom_get_model (rom)); - fu_device_add_guid (device, guid); - - /* get new data */ - fw = fu_rom_get_data (rom); - return fu_firmware_new_from_bytes (fw); + /* ensure we got enough data to fill the buffer */ + while (TRUE) { + gssize sz; + guint8 tmp[32 * 1024] = { 0x0 }; + sz = g_input_stream_read (stream, tmp, sizeof(tmp), NULL, error); + if (sz == 0) + break; + g_debug ("ROM returned 0x%04x bytes", (guint) sz); + if (sz < 0) + return NULL; + g_byte_array_append (buf, tmp, sz); + + /* check the firmware isn't serving us small chunks */ + if (number_reads++ > 1024) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "firmware not fulfilling requests"); + return NULL; + } + } + if (buf->len < 512) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "firmware too small: %u bytes", buf->len); + return NULL; + } + return g_byte_array_free_to_bytes (g_steal_pointer (&buf)); } static void @@ -91,6 +120,7 @@ fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL); fu_device_add_icon (FU_DEVICE (self), "audio-card"); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE); + fu_device_set_logical_id (FU_DEVICE (self), "rom"); fu_udev_device_set_flags (FU_UDEV_DEVICE (self), FU_UDEV_DEVICE_FLAG_OPEN_READ | FU_UDEV_DEVICE_FLAG_VENDOR_FROM_PARENT); @@ -107,8 +137,7 @@ { GObjectClass *object_class = G_OBJECT_CLASS (klass); FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - FuUdevDeviceClass *klass_udev_device = FU_UDEV_DEVICE_CLASS (klass); object_class->finalize = fu_optionrom_device_finalize; - klass_device->read_firmware = fu_optionrom_device_read_firmware; - klass_udev_device->probe = fu_optionrom_device_probe; + klass_device->dump_firmware = fu_optionrom_device_dump_firmware; + klass_device->probe = fu_optionrom_device_probe; } diff -Nru fwupd-1.4.5/plugins/optionrom/fu-plugin-optionrom.c fwupd-1.5.8/plugins/optionrom/fu-plugin-optionrom.c --- fwupd-1.4.5/plugins/optionrom/fu-plugin-optionrom.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/optionrom/fu-plugin-optionrom.c 2021-03-31 20:08:32.000000000 +0000 @@ -7,7 +7,6 @@ #include "config.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #include "fu-optionrom-device.h" diff -Nru fwupd-1.4.5/plugins/optionrom/fu-rom.c fwupd-1.5.8/plugins/optionrom/fu-rom.c --- fwupd-1.4.5/plugins/optionrom/fu-rom.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/optionrom/fu-rom.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,835 +0,0 @@ -/* - * Copyright (C) 2015 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include -#include -#include - -#include "fu-rom.h" - -static void fu_rom_finalize (GObject *object); - -/* data from http://resources.infosecinstitute.com/pci-expansion-rom/ */ -typedef struct { - guint8 *rom_data; - guint32 rom_len; - guint32 rom_offset; - guint32 entry_point; - guint8 reserved[18]; - guint16 cpi_ptr; - guint16 vendor_id; - guint16 device_id; - guint16 device_list_ptr; - guint16 data_len; - guint8 data_rev; - guint32 class_code; - guint32 image_len; - guint16 revision_level; - guint8 code_type; - guint8 last_image; - guint32 max_runtime_len; - guint16 config_header_ptr; - guint16 dmtf_clp_ptr; -} FuRomPciHeader; - -struct _FuRom { - GObject parent_instance; - FuRomKind kind; - gchar *version; - guint16 vendor_id; - guint16 device_id; - GPtrArray *hdrs; /* of FuRomPciHeader */ -}; - -G_DEFINE_TYPE (FuRom, fu_rom, G_TYPE_OBJECT) - -static void -fu_rom_pci_header_free (FuRomPciHeader *hdr) -{ - g_free (hdr->rom_data); - g_free (hdr); -} - -const gchar * -fu_rom_kind_to_string (FuRomKind kind) -{ - if (kind == FU_ROM_KIND_UNKNOWN) - return "unknown"; - if (kind == FU_ROM_KIND_ATI) - return "ati"; - if (kind == FU_ROM_KIND_NVIDIA) - return "nvidia"; - if (kind == FU_ROM_KIND_INTEL) - return "intel"; - if (kind == FU_ROM_KIND_PCI) - return "pci"; - return NULL; -} - -static guint8 * -fu_rom_pci_strstr (FuRomPciHeader *hdr, const gchar *needle) -{ - gsize needle_len; - guint8 *haystack; - gsize haystack_len; - - if (needle == NULL || needle[0] == '\0') - return NULL; - if (hdr->rom_data == NULL) - return NULL; - if (hdr->data_len > hdr->rom_len) - return NULL; - haystack = &hdr->rom_data[hdr->data_len]; - haystack_len = hdr->rom_len - hdr->data_len; - needle_len = strlen (needle); - if (needle_len > haystack_len) - return NULL; - for (guint i = 0; i < haystack_len - needle_len; i++) { - if (memcmp (haystack + i, needle, needle_len) == 0) - return &haystack[i]; - } - return NULL; -} - -static guint -fu_rom_blank_serial_numbers (guint8 *buffer, guint buffer_sz) -{ - guint i; - for (i = 0; i < buffer_sz; i++) { - if (buffer[i] == 0xff || - buffer[i] == '\0' || - buffer[i] == '\n' || - buffer[i] == '\r') - break; - buffer[i] = '\0'; - } - return i; -} - -static gchar * -fu_rom_get_hex_dump (guint8 *buffer, guint32 sz) -{ - GString *str = g_string_new (""); - for (guint32 i = 0; i < sz; i++) - g_string_append_printf (str, "%02x ", buffer[i]); - g_string_append (str, " "); - for (guint32 i = 0; i < sz; i++) { - gchar tmp = '?'; - if (g_ascii_isprint (buffer[i])) - tmp = (gchar) buffer[i]; - g_string_append_printf (str, "%c", tmp); - } - return g_string_free (str, FALSE); -} - -typedef struct { - guint8 segment_kind; - guint8 *data; - guint16 data_len; - guint16 next_offset; -} FooRomPciCertificateHdr; - -static void -fu_rom_pci_print_certificate_data (guint8 *buffer, gssize sz) -{ - guint16 off = 0; - g_autofree gchar *hdr_str = NULL; - - /* 27 byte header, unknown purpose */ - hdr_str = fu_rom_get_hex_dump (buffer+off, 27); - g_debug (" ISBN header: %s", hdr_str); - buffer += 27; - - while (TRUE) { - /* 29 byte header to the segment, then data: - * 0x01 = type. 0x1 = certificate, 0x2 = hashes? - * 0x13,0x14 = offset to next segment */ - FooRomPciCertificateHdr h; - g_autofree gchar *segment_str = NULL; - segment_str = fu_rom_get_hex_dump (buffer+off, 29); - g_debug (" ISBN segment @%02x: %s", off, segment_str); - h.segment_kind = buffer[off+1]; - h.next_offset = (guint16) (((guint16) buffer[off+14] << 8) + buffer[off+13]); - h.data = &buffer[off+29]; - - /* calculate last block length automatically */ - if (h.next_offset == 0) - h.data_len = (guint16) (sz - off - 29 - 27); - else - h.data_len = (guint16) (h.next_offset - off - 29); - - /* print the certificate */ - if (h.segment_kind == 0x01) { - g_autofree gchar *tmp = NULL; - tmp = fu_rom_get_hex_dump (h.data, h.data_len); - g_debug ("%s(%i)", tmp, h.data_len); - } else if (h.segment_kind == 0x02) { - g_autofree gchar *tmp = NULL; - tmp = fu_rom_get_hex_dump (h.data, - h.data_len < 32 ? h.data_len : 32); - g_debug ("%s(%i)", tmp, h.data_len); - } else { - g_warning ("unknown segment kind %i", h.segment_kind); - } - - /* last block */ - if (h.next_offset == 0x0000) - break; - off = h.next_offset; - } -} - -static const gchar * -fu_rom_pci_code_type_to_string (guint8 code_type) -{ - if (code_type == 0) - return "Intel86"; - if (code_type == 1) - return "OpenFirmware"; - if (code_type == 2) - return "PA-RISC"; - if (code_type == 3) - return "EFI"; - return "reserved"; -} - -static guint8 -fu_rom_pci_header_get_checksum (FuRomPciHeader *hdr) -{ - guint8 chksum_check = 0x00; - for (guint i = 0; i < hdr->rom_len; i++) - chksum_check += hdr->rom_data[i]; - return chksum_check; -} - -static void -fu_rom_pci_print_header (FuRomPciHeader *hdr) -{ - guint8 chksum_check; - guint8 *buffer; - g_autofree gchar *data_str = NULL; - g_autofree gchar *reserved_str = NULL; - - g_debug ("PCI Header"); - g_debug (" RomOffset: 0x%04x", hdr->rom_offset); - g_debug (" RomSize: 0x%04x", hdr->rom_len); - g_debug (" EntryPnt: 0x%06x", hdr->entry_point); - reserved_str = fu_rom_get_hex_dump (hdr->reserved, 18); - g_debug (" Reserved: %s", reserved_str); - g_debug (" CpiPtr: 0x%04x", hdr->cpi_ptr); - - /* sanity check */ - if (hdr->cpi_ptr > hdr->rom_len) { - g_debug (" PCI DATA: Invalid as cpi_ptr > rom_len"); - return; - } - if (hdr->data_len > hdr->rom_len) { - g_debug (" PCI DATA: Invalid as data_len > rom_len"); - return; - } - - /* print the data */ - buffer = &hdr->rom_data[hdr->cpi_ptr]; - g_debug (" PCI Data"); - g_debug (" VendorID: 0x%04x", hdr->vendor_id); - g_debug (" DeviceID: 0x%04x", hdr->device_id); - g_debug (" DevList: 0x%04x", hdr->device_list_ptr); - g_debug (" DataLen: 0x%04x", hdr->data_len); - g_debug (" DataRev: 0x%04x", hdr->data_rev); - if (hdr->image_len < 0x0f) { - data_str = fu_rom_get_hex_dump (&buffer[hdr->data_len], hdr->image_len); - g_debug (" ImageLen: 0x%04x [%s]", hdr->image_len, data_str); - } else if (hdr->image_len >= 0x0f) { - data_str = fu_rom_get_hex_dump (&buffer[hdr->data_len], 0x0f); - g_debug (" ImageLen: 0x%04x [%s...]", hdr->image_len, data_str); - } else { - g_debug (" ImageLen: 0x%04x", hdr->image_len); - } - g_debug (" RevLevel: 0x%04x", hdr->revision_level); - g_debug (" CodeType: 0x%02x [%s]", hdr->code_type, - fu_rom_pci_code_type_to_string (hdr->code_type)); - g_debug (" LastImg: 0x%02x [%s]", hdr->last_image, - hdr->last_image == 0x80 ? "yes" : "no"); - g_debug (" MaxRunLen: 0x%04x", hdr->max_runtime_len); - g_debug (" ConfigHdr: 0x%04x", hdr->config_header_ptr); - g_debug (" ClpPtr: 0x%04x", hdr->dmtf_clp_ptr); - - /* dump the ISBN */ - if (hdr->code_type == 0x70 && - memcmp (&buffer[hdr->data_len], "ISBN", 4) == 0) { - fu_rom_pci_print_certificate_data (&buffer[hdr->data_len], - hdr->image_len); - } - - /* verify the checksum byte */ - if (hdr->image_len <= hdr->rom_len && hdr->image_len > 0) { - buffer = hdr->rom_data; - chksum_check = fu_rom_pci_header_get_checksum (hdr); - if (chksum_check == 0x00) { - g_debug (" ChkSum: 0x%02x [valid]", - buffer[hdr->image_len-1]); - } else { - g_debug (" ChkSum: 0x%02x [failed, got 0x%02x]", - buffer[hdr->image_len-1], - chksum_check); - } - } else { - g_debug (" ChkSum: 0x?? [unknown]"); - } -} - -gboolean -fu_rom_extract_all (FuRom *self, const gchar *path, GError **error) -{ - FuRomPciHeader *hdr; - - for (guint i = 0; i < self->hdrs->len; i++) { - g_autofree gchar *fn = NULL; - hdr = g_ptr_array_index (self->hdrs, i); - fn = g_strdup_printf ("%s/%02u.bin", path, i); - g_debug ("dumping ROM #%u at 0x%04x [0x%02x] to %s", - i, hdr->rom_offset, hdr->rom_len, fn); - if (hdr->rom_len == 0) - continue; - if (!g_file_set_contents (fn, - (const gchar *) hdr->rom_data, - (gssize) hdr->rom_len, error)) - return FALSE; - } - return TRUE; -} - -static void -fu_rom_find_and_blank_serial_numbers (FuRom *self) -{ - FuRomPciHeader *hdr; - guint8 *tmp; - - /* bail if not likely */ - if (self->kind == FU_ROM_KIND_PCI || - self->kind == FU_ROM_KIND_INTEL) { - g_debug ("no serial numbers likely"); - return; - } - - for (guint i = 0; i < self->hdrs->len; i++) { - hdr = g_ptr_array_index (self->hdrs, i); - g_debug ("looking for PPID at 0x%04x", hdr->rom_offset); - tmp = fu_rom_pci_strstr (hdr, "PPID"); - if (tmp != NULL) { - guint len; - guint8 chk; - len = fu_rom_blank_serial_numbers (tmp, hdr->rom_len - hdr->data_len); - g_debug ("cleared %u chars @ 0x%04lx", - len, (gulong) (tmp - &hdr->rom_data[hdr->data_len])); - - /* we have to fix the checksum */ - chk = fu_rom_pci_header_get_checksum (hdr); - hdr->rom_data[hdr->rom_len - 1] -= chk; - fu_rom_pci_print_header (hdr); - } - } -} - -static gboolean -fu_rom_pci_parse_data (FuRomPciHeader *hdr) -{ - guint8 *buffer; - - /* check valid */ - if (hdr->cpi_ptr == 0x0000) { - g_debug ("No PCI DATA @ 0x%04x", hdr->rom_offset); - return FALSE; - } - if (hdr->rom_len > 0 && hdr->cpi_ptr > hdr->rom_len) { - g_debug ("Invalid PCI DATA @ 0x%04x", hdr->rom_offset); - return FALSE; - } - - /* gahh, CPI is out of the first chunk */ - if (hdr->cpi_ptr > hdr->rom_len) { - g_debug ("No available PCI DATA @ 0x%04x : 0x%04x > 0x%04x", - hdr->rom_offset, hdr->cpi_ptr, hdr->rom_len); - return FALSE; - } - - /* check signature */ - buffer = &hdr->rom_data[hdr->cpi_ptr]; - if (memcmp (buffer, "PCIR", 4) != 0) { - if (memcmp (buffer, "RGIS", 4) == 0 || - memcmp (buffer, "NPDS", 4) == 0 || - memcmp (buffer, "NPDE", 4) == 0) { - g_debug ("-- using NVIDIA DATA quirk"); - } else { - g_debug ("Not PCI DATA: %02x%02x%02x%02x [%c%c%c%c]", - buffer[0], buffer[1], - buffer[2], buffer[3], - buffer[0], buffer[1], - buffer[2], buffer[3]); - return FALSE; - } - } - - /* parse */ - hdr->vendor_id = ((guint16) buffer[0x05] << 8) + buffer[0x04]; - hdr->device_id = ((guint16) buffer[0x07] << 8) + buffer[0x06]; - hdr->device_list_ptr = ((guint16) buffer[0x09] << 8) + buffer[0x08]; - hdr->data_len = ((guint16) buffer[0x0b] << 8) + buffer[0x0a]; - hdr->data_rev = buffer[0x0c]; - hdr->class_code = ((guint16) buffer[0x0f] << 16) + - ((guint16) buffer[0x0e] << 8) + - buffer[0x0d]; - hdr->image_len = (((guint16) buffer[0x11] << 8) + buffer[0x10]) * 512; - hdr->revision_level = ((guint16) buffer[0x13] << 8) + buffer[0x12]; - hdr->code_type = buffer[0x14]; - hdr->last_image = buffer[0x15]; - hdr->max_runtime_len = (((guint16) buffer[0x17] << 8) + - buffer[0x16]) * 512; - hdr->config_header_ptr = ((guint16) buffer[0x19] << 8) + buffer[0x18]; - hdr->dmtf_clp_ptr = ((guint16) buffer[0x1b] << 8) + buffer[0x1a]; - return TRUE; -} - -static FuRomPciHeader * -fu_rom_pci_get_header (guint8 *buffer, guint32 sz) -{ - FuRomPciHeader *hdr; - - /* check signature */ - if (memcmp (buffer, "\x55\xaa", 2) != 0) { - if (memcmp (buffer, "\x56\x4e", 2) == 0) { - g_debug ("-- using NVIDIA ROM quirk"); - } else { - g_autofree gchar *sig_str = NULL; - sig_str = fu_rom_get_hex_dump (buffer, MIN (16, sz)); - g_debug ("Not PCI ROM %s", sig_str); - return NULL; - } - } - - /* decode structure */ - hdr = g_new0 (FuRomPciHeader, 1); - hdr->rom_len = buffer[0x02] * 512; - - /* fix up misreporting */ - if (hdr->rom_len == 0) { - g_debug ("fixing up last image size"); - hdr->rom_len = sz; - } - - /* copy this locally to the header */ - hdr->rom_data = g_memdup (buffer, hdr->rom_len); - - /* parse out CPI */ - hdr->entry_point = ((guint32) buffer[0x05] << 16) + - ((guint16) buffer[0x04] << 8) + - buffer[0x03]; - memcpy (&hdr->reserved, &buffer[6], 18); - hdr->cpi_ptr = ((guint16) buffer[0x19] << 8) + buffer[0x18]; - - /* parse the header data */ - g_debug ("looking for PCI DATA @ 0x%04x", hdr->cpi_ptr); - fu_rom_pci_parse_data (hdr); - return hdr; -} - -static gchar * -fu_rom_find_version_pci (FuRomPciHeader *hdr) -{ - gchar *str; - - /* ARC storage */ - if (memcmp (hdr->reserved, "\0\0ARC", 5) == 0) { - str = (gchar *) fu_rom_pci_strstr (hdr, "BIOS: "); - if (str != NULL) - return g_strdup (str + 6); - } - return NULL; -} - -static gchar * -fu_rom_find_version_nvidia (FuRomPciHeader *hdr) -{ - gchar *str; - - /* static location for some firmware */ - if (memcmp (hdr->rom_data + 0x013d, "Version ", 8) == 0) - return g_strdup ((gchar *) &hdr->rom_data[0x013d + 8]); - - /* usual search string */ - str = (gchar *) fu_rom_pci_strstr (hdr, "Version "); - if (str != NULL) - return g_strdup (str + 8); - - /* broken */ - str = (gchar *) fu_rom_pci_strstr (hdr, "Vension:"); - if (str != NULL) - return g_strdup (str + 8); - str = (gchar *) fu_rom_pci_strstr (hdr, "Version"); - if (str != NULL) - return g_strdup (str + 7); - - /* fallback to VBIOS */ - if (memcmp (hdr->rom_data + 0xfa, "VBIOS Ver", 9) == 0) - return g_strdup ((gchar *) &hdr->rom_data[0xfa + 9]); - return NULL; -} - -static gchar * -fu_rom_find_version_intel (FuRomPciHeader *hdr) -{ - gchar *str; - - /* 2175_RYan PC 14.34 06/06/2013 21:27:53 */ - str = (gchar *) fu_rom_pci_strstr (hdr, "Build Number:"); - if (str != NULL) { - g_auto(GStrv) split = NULL; - split = g_strsplit (str + 14, " ", -1); - for (guint i = 0; split[i] != NULL; i++) { - if (g_strstr_len (split[i], -1, ".") == NULL) - continue; - return g_strdup (split[i]); - } - } - - /* fallback to VBIOS */ - str = (gchar *) fu_rom_pci_strstr (hdr, "VBIOS "); - if (str != NULL) - return g_strdup (str + 6); - return NULL; -} - -static gchar * -fu_rom_find_version_ati (FuRomPciHeader *hdr) -{ - gchar *str; - - str = (gchar *) fu_rom_pci_strstr (hdr, " VER0"); - if (str != NULL) - return g_strdup (str + 4); - - /* broken */ - str = (gchar *) fu_rom_pci_strstr (hdr, " VR"); - if (str != NULL) - return g_strdup (str + 4); - return NULL; -} - -static gchar * -fu_rom_find_version (FuRomKind kind, FuRomPciHeader *hdr) -{ - if (kind == FU_ROM_KIND_PCI) - return fu_rom_find_version_pci (hdr); - if (kind == FU_ROM_KIND_NVIDIA) - return fu_rom_find_version_nvidia (hdr); - if (kind == FU_ROM_KIND_INTEL) - return fu_rom_find_version_intel (hdr); - if (kind == FU_ROM_KIND_ATI) - return fu_rom_find_version_ati (hdr); - return NULL; -} - -gboolean -fu_rom_load_data (FuRom *self, - guint8 *buffer, gsize buffer_sz, - FuRomLoadFlags flags, - GCancellable *cancellable, - GError **error) -{ - FuRomPciHeader *hdr = NULL; - guint32 sz = buffer_sz; - guint32 jump = 0; - guint32 hdr_sz = 0; - - g_return_val_if_fail (FU_IS_ROM (self), FALSE); - - /* detect optional IFR header and skip to option ROM */ - if (memcmp (buffer, "NVGI", 4) == 0) { - guint16 ifr_sz_raw; - memcpy (&ifr_sz_raw, &buffer[0x15], 2); - hdr_sz = GUINT16_FROM_BE (ifr_sz_raw); - g_debug ("detected IFR header, skipping %x bytes", hdr_sz); - } - - /* read all the ROM headers */ - while (sz > hdr_sz + jump) { - guint32 jump_sz; - g_debug ("looking for PCI ROM @ 0x%04x", hdr_sz + jump); - hdr = fu_rom_pci_get_header (&buffer[hdr_sz + jump], sz - hdr_sz - jump); - if (hdr == NULL) { - gboolean found_data = FALSE; - - /* check it's not just NUL padding */ - for (guint i = jump + hdr_sz; i < buffer_sz; i++) { - if (buffer[i] != 0x00) { - found_data = TRUE; - break; - } - } - if (found_data) { - g_debug ("found junk data, adding fake"); - hdr = g_new0 (FuRomPciHeader, 1); - hdr->vendor_id = 0x0000; - hdr->device_id = 0x0000; - hdr->code_type = 0x00; - hdr->last_image = 0x80; - hdr->rom_offset = hdr_sz + jump; - hdr->rom_len = sz - hdr->rom_offset; - hdr->rom_data = g_memdup (&buffer[hdr->rom_offset], hdr->rom_len); - hdr->image_len = hdr->rom_len; - g_ptr_array_add (self->hdrs, hdr); - } else { - g_debug ("ignoring 0x%04x bytes of padding", - (guint) (buffer_sz - (jump + hdr_sz))); - } - break; - } - - /* save this so we can fix checksums */ - hdr->rom_offset = hdr_sz + jump; - - /* we can't break on hdr->last_image as - * NVIDIA uses packed but not merged extended headers */ - g_ptr_array_add (self->hdrs, hdr); - - /* NVIDIA don't always set a ROM size for extensions */ - jump_sz = hdr->rom_len; - if (jump_sz == 0) - jump_sz = hdr->image_len; - if (jump_sz == 0x0) - break; - jump += jump_sz; - } - - /* we found nothing */ - if (self->hdrs->len == 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Failed to detect firmware header [%02x%02x]", - buffer[0], buffer[1]); - return FALSE; - } - - /* print all headers */ - for (guint i = 0; i < self->hdrs->len; i++) { - hdr = g_ptr_array_index (self->hdrs, i); - fu_rom_pci_print_header (hdr); - } - - /* find first ROM header */ - hdr = g_ptr_array_index (self->hdrs, 0); - self->vendor_id = hdr->vendor_id; - self->device_id = hdr->device_id; - self->kind = FU_ROM_KIND_PCI; - - /* detect intel header */ - if (memcmp (hdr->reserved, "00000000000", 11) == 0) - hdr_sz = (guint32) (((guint16) buffer[0x1b] << 8) + buffer[0x1a]); - if (hdr_sz > sz) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "firmware corrupt (overflow)"); - return FALSE; - } - - if (hdr->entry_point == 0x374beb) { - self->kind = FU_ROM_KIND_NVIDIA; - } else if (memcmp (buffer + hdr_sz, "$VBT", 4) == 0) { - self->kind = FU_ROM_KIND_INTEL; - } else if (memcmp(buffer + 0x30, " 761295520", 10) == 0) { - self->kind = FU_ROM_KIND_ATI; - } - - /* nothing */ - if (self->kind == FU_ROM_KIND_UNKNOWN) { - g_autofree gchar *str = NULL; - str = fu_rom_get_hex_dump (buffer + hdr_sz, 0x32); - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Failed to detect firmware kind from [%s]", - str); - return FALSE; - } - - /* find version string */ - self->version = fu_rom_find_version (self->kind, hdr); - if (self->version != NULL) { - g_strstrip (self->version); - g_strdelimit (self->version, "\r\n ", '\0'); - } - - /* update checksum */ - if (flags & FU_ROM_LOAD_FLAG_BLANK_PPID) - fu_rom_find_and_blank_serial_numbers (self); - - /* not known */ - if (self->version == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Firmware version extractor not known"); - return FALSE; - } - - return TRUE; -} - -gboolean -fu_rom_load_file (FuRom *self, GFile *file, FuRomLoadFlags flags, - GCancellable *cancellable, GError **error) -{ - const gssize buffer_sz = 0x400000; - gssize sz; - guint number_reads = 0; - g_autoptr(GError) error_local = NULL; - g_autofree gchar *fn = NULL; - g_autofree guint8 *buffer = NULL; - g_autoptr(GInputStream) stream = NULL; - - g_return_val_if_fail (FU_IS_ROM (self), FALSE); - - /* open file */ - stream = G_INPUT_STREAM (g_file_read (file, cancellable, &error_local)); - if (stream == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_AUTH_FAILED, - error_local->message); - return FALSE; - } - - /* we have to enable the read for devices */ - fn = g_file_get_path (file); - if (g_str_has_prefix (fn, "/sys")) { - g_autoptr(GFileOutputStream) output_stream = NULL; - output_stream = g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, - cancellable, error); - if (output_stream == NULL) - return FALSE; - if (g_output_stream_write (G_OUTPUT_STREAM (output_stream), "1", 1, - cancellable, error) < 0) - return FALSE; - } - - /* read out the header */ - buffer = g_malloc ((gsize) buffer_sz); - sz = g_input_stream_read (stream, buffer, buffer_sz, - cancellable, error); - if (sz < 0) - return FALSE; - if (sz < 512) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Firmware too small: %" G_GSSIZE_FORMAT " bytes", sz); - return FALSE; - } - - /* ensure we got enough data to fill the buffer */ - while (sz < buffer_sz) { - gssize sz_chunk; - sz_chunk = g_input_stream_read (stream, - buffer + sz, - buffer_sz - sz, - cancellable, - error); - if (sz_chunk == 0) - break; - g_debug ("ROM returned 0x%04x bytes, adding 0x%04x...", - (guint) sz, (guint) sz_chunk); - if (sz_chunk < 0) - return FALSE; - sz += sz_chunk; - - /* check the firmware isn't serving us small chunks */ - if (number_reads++ > 16) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "firmware not fulfilling requests"); - return FALSE; - } - } - g_debug ("ROM buffer filled %" G_GSSIZE_FORMAT "kb/%" G_GSSIZE_FORMAT "kb", - sz / 0x400, buffer_sz / 0x400); - return fu_rom_load_data (self, buffer, sz, flags, cancellable, error); -} - -FuRomKind -fu_rom_get_kind (FuRom *self) -{ - g_return_val_if_fail (FU_IS_ROM (self), FU_ROM_KIND_UNKNOWN); - return self->kind; -} - -const gchar * -fu_rom_get_version (FuRom *self) -{ - g_return_val_if_fail (FU_IS_ROM (self), NULL); - return self->version; -} - -guint16 -fu_rom_get_vendor (FuRom *self) -{ - g_return_val_if_fail (FU_IS_ROM (self), 0x0000); - return self->vendor_id; -} - -guint16 -fu_rom_get_model (FuRom *self) -{ - g_return_val_if_fail (FU_IS_ROM (self), 0x0000); - return self->device_id; -} - -GBytes * -fu_rom_get_data (FuRom *self) -{ - GByteArray *buf = g_byte_array_new (); - for (guint i = 0; i < self->hdrs->len; i++) { - FuRomPciHeader *hdr = g_ptr_array_index (self->hdrs, i); - g_byte_array_append (buf, hdr->rom_data, hdr->rom_len); - } - return g_byte_array_free_to_bytes (buf); -} - -static void -fu_rom_class_init (FuRomClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - object_class->finalize = fu_rom_finalize; -} - -static void -fu_rom_init (FuRom *self) -{ - self->hdrs = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_rom_pci_header_free); -} - -static void -fu_rom_finalize (GObject *object) -{ - FuRom *self = FU_ROM (object); - - g_free (self->version); - g_ptr_array_unref (self->hdrs); - - G_OBJECT_CLASS (fu_rom_parent_class)->finalize (object); -} - -FuRom * -fu_rom_new (void) -{ - FuRom *self; - self = g_object_new (FU_TYPE_ROM, NULL); - return FU_ROM (self); -} diff -Nru fwupd-1.4.5/plugins/optionrom/fu-rom.h fwupd-1.5.8/plugins/optionrom/fu-rom.h --- fwupd-1.4.5/plugins/optionrom/fu-rom.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/optionrom/fu-rom.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2015 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include - -#define FU_TYPE_ROM (fu_rom_get_type ()) -G_DECLARE_FINAL_TYPE (FuRom, fu_rom, FU, ROM, GObject) - -typedef enum { - FU_ROM_KIND_UNKNOWN, - FU_ROM_KIND_ATI, - FU_ROM_KIND_NVIDIA, - FU_ROM_KIND_INTEL, - FU_ROM_KIND_PCI, - FU_ROM_KIND_LAST -} FuRomKind; - -typedef enum { - FU_ROM_LOAD_FLAG_NONE, - FU_ROM_LOAD_FLAG_BLANK_PPID = 1, - FU_ROM_LOAD_FLAG_LAST -} FuRomLoadFlags; - -FuRom *fu_rom_new (void); - -gboolean fu_rom_load_file (FuRom *self, - GFile *file, - FuRomLoadFlags flags, - GCancellable *cancellable, - GError **error); -gboolean fu_rom_load_data (FuRom *self, - guint8 *buffer, - gsize buffer_sz, - FuRomLoadFlags flags, - GCancellable *cancellable, - GError **error); -gboolean fu_rom_extract_all (FuRom *self, - const gchar *path, - GError **error); -FuRomKind fu_rom_get_kind (FuRom *self); -const gchar *fu_rom_get_version (FuRom *self); -GBytes *fu_rom_get_data (FuRom *self); -guint16 fu_rom_get_vendor (FuRom *self); -guint16 fu_rom_get_model (FuRom *self); -const gchar *fu_rom_kind_to_string (FuRomKind kind); diff -Nru fwupd-1.4.5/plugins/optionrom/fu-rom-tool.c fwupd-1.5.8/plugins/optionrom/fu-rom-tool.c --- fwupd-1.4.5/plugins/optionrom/fu-rom-tool.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/optionrom/fu-rom-tool.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,187 +0,0 @@ -/* - * Copyright (C) 2016 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include -#include - -#include "fwupd-common-private.h" - -#include "fu-rom.h" -#include "fu-common.h" - -static gboolean -fu_fuzzer_rom_parse (const gchar *fn, GError **error) -{ - g_autoptr(FuRom) rom = NULL; - g_autoptr(GFile) file = NULL; - - g_debug ("loading %s", fn); - file = g_file_new_for_path (fn); - rom = fu_rom_new (); - if (!fu_rom_load_file (rom, file, FU_ROM_LOAD_FLAG_NONE, NULL, error)) - return FALSE; - g_print ("filename:%s\n", fn); - g_print ("kind:%s\n", fu_rom_kind_to_string (fu_rom_get_kind (rom))); - g_print ("version:%s\n", fu_rom_get_version (rom)); - g_print ("vendor:%u\n", fu_rom_get_vendor (rom)); - g_print ("model:%u\n\n", fu_rom_get_model (rom)); - return TRUE; -} - -static gboolean -fu_fuzzer_write_files (GHashTable *hash, GError **error) -{ - GString *str; - g_autoptr(GList) keys = g_hash_table_get_keys (hash); - - for (GList *l = keys; l != NULL; l = l->next) { - g_autofree gchar *filename = NULL; - const gchar *fn = l->data; - filename = g_build_filename ("fuzzing", fn, NULL); - str = g_hash_table_lookup (hash, fn); - g_debug ("writing %s", fn); - if (!g_file_set_contents (filename, str->str, str->len, error)) { - g_prefix_error (error, - "could not write file %s: ", - filename); - return FALSE; - } - } - return TRUE; -} - -static void -_g_string_unref (GString *str) -{ - g_string_free (str, TRUE); -} - -static gboolean -fu_fuzzer_rom_create (GError **error) -{ - GString *str; - guint8 *buffer; - g_autofree guint8 *blob_header = NULL; - g_autofree guint8 *blob_ifr = NULL; - g_autoptr(GHashTable) hash = NULL; - - hash = g_hash_table_new_full (g_str_hash, g_str_equal, - NULL, - (GDestroyNotify) _g_string_unref); - - /* 24 byte header */ - blob_header = g_malloc0 (0x200); - buffer = blob_header; - memcpy (buffer, "\x55\xaa", 2); - buffer[0x02] = 1; /* rom_len / 512 */ - buffer[0x03] = 0x20; /* entry_point lo to blob just after header */ - buffer[0x04] = 'K'; /* entry_point hi (NVIDIA) */ - buffer[0x05] = '7'; /* entry_point higher (NVIDIA) */ - memcpy (&buffer[0x6], "xxxxxxxxxxxxxxxxxx", 18); /* reserved */ - buffer[0x18] = 0x20; /* cpi_ptr lo */ - buffer[0x19] = 0x00; /* cpi_ptr hi */ - memcpy (&blob_header[0x6], "hdr-no-data ", 18); - g_hash_table_insert (hash, (gpointer) "header-no-data.rom", - g_string_new_len ((gchar *) blob_header, 512)); - - /* data for header */ - buffer = &blob_header[0x20]; - memcpy (&buffer[0x00], "PCIR", 4); /* magic */ - memcpy (&buffer[0x04], "\0\0", 2); /* vendor */ - memcpy (&buffer[0x06], "\0\0", 2); /* device id */ - memcpy (&buffer[0x08], "\0\0", 2); /* device_list_ptr */ - buffer[0x0a] = 0x1c; /* data_len lo */ - buffer[0x0b] = 0x00; /* data_len hi */ - buffer[0x0c] = 0x0; /* data_rev */ - memcpy (&buffer[0x0d], "\0\0\0", 3); /* class_code */ - buffer[0x10] = 0x01; /* image_len lo / 512 */ - buffer[0x11] = 0; /* image_len hi / 512 */ - buffer[0x12] = 0; /* revision_level lo */ - buffer[0x13] = 0; /* revision_level hi */ - buffer[0x14] = 0x00; /* code_type, Intel x86 */ - buffer[0x15] = 0x80; /* last_image */ - buffer[0x16] = 0x0; /* max_runtime_len lo / 512 */ - buffer[0x17] = 0x0; /* max_runtime_len hi / 512 */ - buffer[0x18] = 0x00; /* config_header_ptr lo */ - buffer[0x19] = 0x00; /* config_header_ptr hi */ - buffer[0x1a] = 0x00; /* dmtf_clp_ptr lo (used for Intel FW) */ - buffer[0x1b] = 0x00; /* dmtf_clp_ptr hi (used for Intel FW) */ - blob_header[0x200-1] = 0x5c; /* checksum */ - - /* blob */ - memcpy (&buffer[0x1c], "Version 1.0", 12); - memcpy (&blob_header[0x6], "hdr-data-payload ", 18); - g_hash_table_insert (hash, (gpointer) "header-data-payload.rom", - g_string_new_len ((gchar *) blob_header, 512)); - - /* optional IFR header on some NVIDIA blobs */ - blob_ifr = g_malloc0 (0x80); - buffer = blob_ifr; - memcpy (buffer, "NVGI", 4); - fu_common_write_uint16 (&buffer[0x15], 0x80, G_BIG_ENDIAN); - g_hash_table_insert (hash, (gpointer) "naked-ifr.rom", - g_string_new_len ((const gchar *) blob_ifr, 0x80)); - str = g_string_new_len ((gchar *) blob_ifr, 0x80); - memcpy (&blob_header[0x6], (gpointer) "ifr-hdr-data-payld", 18); - g_string_append_len (str, (gchar *) blob_header, 0x200); - g_hash_table_insert (hash, (gpointer) "ifr-header-data-payload.rom", str); - - /* dump to files */ - return fu_fuzzer_write_files (hash, error); -} - -int -main (int argc, char *argv[]) -{ - gboolean verbose = FALSE; - g_autoptr(GError) error_parse = NULL; - g_autoptr(GOptionContext) context = NULL; - const GOptionEntry options[] = { - { "verbose", '\0', 0, G_OPTION_ARG_NONE, &verbose, - "Run with debugging output enabled", NULL }, - { NULL} - }; - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, options, NULL); - if (!g_option_context_parse (context, &argc, &argv, &error_parse)) { - g_print ("failed to parse command line arguments: %s\n", - error_parse->message); - return EXIT_FAILURE; - } - - if (argc < 3) { - g_print ("Not enough arguments, expected 'rom' 'foo.rom'\n"); - return EXIT_FAILURE; - } - if (verbose) - g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); - if (g_strcmp0 (argv[1], "rom") == 0) { - gboolean all_successful = TRUE; - for (guint i = 2; i < (guint) argc; i++) { - g_autoptr(GError) error = NULL; - if (!fu_fuzzer_rom_parse (argv[i], &error)) { - g_print ("Failed to parse %s: %s\n", - argv[i], error->message); - all_successful = FALSE; - } - } - return all_successful ? EXIT_SUCCESS : EXIT_FAILURE; - } - if (g_strcmp0 (argv[1], "create") == 0) { - g_autoptr(GError) error = NULL; - if (!fu_fuzzer_rom_create (&error)) { - g_print ("Failed to create files: %s\n", error->message); - return EXIT_FAILURE; - } - return EXIT_SUCCESS; - } - - g_print ("Type not known: expected 'rom'\n"); - return EXIT_FAILURE; -} diff -Nru fwupd-1.4.5/plugins/optionrom/fu-self-test.c fwupd-1.5.8/plugins/optionrom/fu-self-test.c --- fwupd-1.4.5/plugins/optionrom/fu-self-test.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/optionrom/fu-self-test.c 2021-03-31 20:08:32.000000000 +0000 @@ -61,7 +61,7 @@ g_assert (rom != NULL); /* load file */ - filename = g_build_filename (TESTDATADIR, data[i].fn, NULL); + filename = g_test_build_filename (G_TEST_DIST, "tests", data[i].fn, NULL); if (!g_file_test (filename, G_FILE_TEST_EXISTS)) continue; g_print ("\nparsing %s...", filename); @@ -83,7 +83,7 @@ g_autofree gchar *path = NULL; /* may or may not exist */ - path = g_build_filename (TESTDATADIR, "roms", NULL); + path = g_test_build_filename (G_TEST_DIST, "tests", "roms", NULL); if (!g_file_test (path, G_FILE_TEST_EXISTS)) return; g_print ("\n"); diff -Nru fwupd-1.4.5/plugins/optionrom/fuzzing.md fwupd-1.5.8/plugins/optionrom/fuzzing.md --- fwupd-1.4.5/plugins/optionrom/fuzzing.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/optionrom/fuzzing.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -CC=afl-gcc ./configure --disable-shared -AFL_HARDEN=1 make -afl-fuzz -m 300 -i fuzzing -o findings ./fu-rom-tool rom @@ diff -Nru fwupd-1.4.5/plugins/optionrom/meson.build fwupd-1.5.8/plugins/optionrom/meson.build --- fwupd-1.4.5/plugins/optionrom/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/optionrom/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,4 @@ +if get_option('gudev') cargs = ['-DG_LOG_DOMAIN="FuPluginOptionrom"'] install_data(['optionrom.quirk'], @@ -9,7 +10,6 @@ sources : [ 'fu-plugin-optionrom.c', 'fu-optionrom-device.c', - 'fu-rom.c', ], include_directories : [ root_incdir, @@ -27,54 +27,4 @@ plugin_deps, ], ) - -executable( - 'fu-rom-tool', - fu_hash, - sources : [ - 'fu-rom-tool.c', - 'fu-rom.c', - ], - include_directories : [ - root_incdir, - fwupd_incdir, - fwupdplugin_incdir, - ], - dependencies : [ - plugin_deps, - libjsonglib, - ], - link_with : [ - fwupd, - fwupdplugin, - ], - c_args : cargs, -) - -if get_option('tests') - cargs += '-DPLUGINBUILDDIR="' + meson.current_build_dir() + '"' - testdatadir = join_paths(meson.current_source_dir(), 'tests') - cargs += '-DTESTDATADIR="' + testdatadir + '"' - e = executable( - 'optionrom-self-test', - fu_hash, - sources : [ - 'fu-self-test.c', - 'fu-rom.c', - ], - include_directories : [ - root_incdir, - fwupd_incdir, - fwupdplugin_incdir, - ], - dependencies : [ - plugin_deps, - ], - link_with : [ - fwupd, - fwupdplugin, - ], - c_args : cargs - ) - test('optionrom-self-test', e) endif diff -Nru fwupd-1.4.5/plugins/optionrom/optionrom.quirk fwupd-1.5.8/plugins/optionrom/optionrom.quirk --- fwupd-1.4.5/plugins/optionrom/optionrom.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/optionrom/optionrom.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,3 @@ # match all devices with this udev subsystem -[DeviceInstanceId=PCI] +[PCI] Plugin = optionrom diff -Nru fwupd-1.4.5/plugins/optionrom/README.md fwupd-1.5.8/plugins/optionrom/README.md --- fwupd-1.4.5/plugins/optionrom/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/optionrom/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -4,10 +4,6 @@ Introduction ------------ -This plugin reads the version numbers of PCI devices. It cannot deploy firmware -onto devices but is used to list devices with known firmware updates that may -require booting into another operating system to apply. - This plugin is also able to read and parse the firmware of some PCI devices which allows some host state verification to be done. @@ -18,9 +14,12 @@ * `PCI\VEN_%04X&DEV_%04X` -Additionally, GUIDs found in OptionROMs may also be added. - Vendor ID Security ------------------ The device is not upgradable and thus requires no vendor ID set. + +External interface access +------------------------- + +This plugin requires read access to the rom file of PCI devices (`/sys/class/pci_bus/*/device/rom`) diff -Nru fwupd-1.4.5/plugins/optionrom/tests/get-nonfree.sh fwupd-1.5.8/plugins/optionrom/tests/get-nonfree.sh --- fwupd-1.4.5/plugins/optionrom/tests/get-nonfree.sh 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/optionrom/tests/get-nonfree.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,7 +0,0 @@ -rm *.rom -wget http://www.techpowerup.com/vgabios/375/Asus.9800PRO.256.unknown.031114.rom -wget http://www.techpowerup.com/vgabios/133037/Asus.HD7970.3072.121018.rom -wget http://www.techpowerup.com/vgabios/148214/Asus.R9290X.4096.131014.rom -wget http://www.techpowerup.com/vgabios/74257/Asus.GTX480.1536.100406_1.rom -wget http://www.techpowerup.com/vgabios/162406/Asus.GTX980.4096.140905.rom -wget http://www.techpowerup.com/vgabios/157835/Asus.TitanBlack.6144.140212.rom Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/pci-bcr/config and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/pci-bcr/config differ diff -Nru fwupd-1.4.5/plugins/pci-bcr/fu-plugin-pci-bcr.c fwupd-1.5.8/plugins/pci-bcr/fu-plugin-pci-bcr.c --- fwupd-1.4.5/plugins/pci-bcr/fu-plugin-pci-bcr.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/pci-bcr/fu-plugin-pci-bcr.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" + +struct FuPluginData { + gboolean has_device; + guint8 bcr_addr; + guint8 bcr; +}; + +#define BCR_WPD (1 << 0) +#define BCR_BLE (1 << 1) +#define BCR_SMM_BWP (1 << 5) + +void +fu_plugin_init (FuPlugin *plugin) +{ + FuPluginData *priv = fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_udev_subsystem (plugin, "pci"); + fu_plugin_add_possible_quirk_key (plugin, "PciBcrAddr"); + + /* this is true except for some Atoms */ + priv->bcr_addr = 0xdc; +} + +static void +fu_plugin_pci_bcr_set_updatable (FuPlugin *plugin, FuDevice *dev) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + if ((priv->bcr & BCR_WPD) == 0 && (priv->bcr & BCR_BLE) > 0) { + fu_device_remove_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_set_update_error (dev, "BIOS locked"); + } +} + +void +fu_plugin_device_registered (FuPlugin *plugin, FuDevice *dev) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + if (g_strcmp0 (fu_device_get_plugin (dev), "cpu") == 0 || + g_strcmp0 (fu_device_get_plugin (dev), "flashrom") == 0) { + guint tmp = fu_device_get_metadata_integer (dev, "PciBcrAddr"); + if (tmp != G_MAXUINT && priv->bcr_addr != tmp) { + g_debug ("overriding BCR addr from 0x%02x to 0x%02x", + priv->bcr_addr, tmp); + priv->bcr_addr = tmp; + } + } + if (g_strcmp0 (fu_device_get_plugin (dev), "flashrom") == 0 && + fu_device_has_instance_id (dev, "main-system-firmware")) { + /* PCI\VEN_8086 added first */ + if (priv->has_device) { + fu_plugin_pci_bcr_set_updatable (plugin, dev); + return; + } + fu_plugin_cache_add (plugin, "main-system-firmware", dev); + } +} + +static void +fu_plugin_add_security_attr_bioswe (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SPI_BIOSWE); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fu_security_attrs_append (attrs, attr); + + /* no device */ + if (!priv->has_device) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND); + return; + } + + /* load file */ + if ((priv->bcr & BCR_WPD) == 1) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); +} + +static void +fu_plugin_add_security_attr_ble (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* no device */ + if (!priv->has_device) + return; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SPI_BLE); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fu_security_attrs_append (attrs, attr); + + /* load file */ + if ((priv->bcr & BCR_BLE) == 0) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); +} + +static void +fu_plugin_add_security_attr_smm_bwp (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* no device */ + if (!priv->has_device) + return; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SPI_SMM_BWP); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fu_security_attrs_append (attrs, attr); + + /* load file */ + if ((priv->bcr & BCR_SMM_BWP) == 0) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_LOCKED); +} + +gboolean +fu_plugin_backend_device_added (FuPlugin *plugin, FuDevice *device, GError **error) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + FuDevice *device_msf; + g_autoptr(FuDeviceLocker) locker = NULL; + + /* not supported */ + if (priv->bcr_addr == 0x0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "BCR not supported on this platform"); + return FALSE; + } + + /* interesting device? */ + if (!FU_IS_UDEV_DEVICE (device)) + return TRUE; + if (g_strcmp0 (fu_udev_device_get_subsystem (FU_UDEV_DEVICE (device)), "pci") != 0) + return TRUE; + + /* open the config */ + fu_udev_device_set_flags (FU_UDEV_DEVICE (device), FU_UDEV_DEVICE_FLAG_USE_CONFIG); + if (!fu_udev_device_set_physical_id (FU_UDEV_DEVICE (device), "pci", error)) + return FALSE; + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + + /* grab BIOS Control Register */ + if (!fu_udev_device_pread (FU_UDEV_DEVICE (device), priv->bcr_addr, &priv->bcr, error)) { + g_prefix_error (error, "could not read BCR: "); + return FALSE; + } + + /* main-system-firmware device added first, probably from flashrom */ + device_msf = fu_plugin_cache_lookup (plugin, "main-system-firmware"); + if (device_msf != NULL) + fu_plugin_pci_bcr_set_updatable (plugin, device_msf); + + /* success */ + priv->has_device = TRUE; + return TRUE; +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + /* only Intel */ + if (fu_common_get_cpu_vendor () != FU_CPU_VENDOR_INTEL) + return; + + /* add attrs */ + fu_plugin_add_security_attr_bioswe (plugin, attrs); + fu_plugin_add_security_attr_ble (plugin, attrs); + fu_plugin_add_security_attr_smm_bwp (plugin, attrs); +} diff -Nru fwupd-1.4.5/plugins/pci-bcr/meson.build fwupd-1.5.8/plugins/pci-bcr/meson.build --- fwupd-1.4.5/plugins/pci-bcr/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/pci-bcr/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,29 @@ +if host_machine.system() == 'linux' +cargs = ['-DG_LOG_DOMAIN="FuPluginPciBcr"'] + +install_data(['pci-bcr.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_pci_bcr', + fu_hash, + sources : [ + 'fu-plugin-pci-bcr.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) +endif diff -Nru fwupd-1.4.5/plugins/pci-bcr/pci-bcr.quirk fwupd-1.5.8/plugins/pci-bcr/pci-bcr.quirk --- fwupd-1.4.5/plugins/pci-bcr/pci-bcr.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/pci-bcr/pci-bcr.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,9 @@ +# ISA bridge i.e. 00:1F.0 +# -> drivers/mfd/lpc_ich.c +[PCI\VEN_8086&CLASS_060100] +Plugin = pci_bcr + +# PCI devices, i.e. 00:1F.5 +# -> drivers/mtd/spi-nor/controllers/intel-spi-pci.c +[PCI\VEN_8086&CLASS_0C8000] +Plugin = pci_bcr diff -Nru fwupd-1.4.5/plugins/pci-bcr/README.md fwupd-1.5.8/plugins/pci-bcr/README.md --- fwupd-1.4.5/plugins/pci-bcr/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/pci-bcr/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,12 @@ +PCI BIOS Control Register +========================= + +Introduction +------------ + +This plugin checks if the system SPI chip is locked. The result will be stored +in an security attribute for HSI. + +External interface access +------------------------- +This plugin requires read access to the config space of PCI devices (`/sys/class/pci_bus/*/device/config`) diff -Nru fwupd-1.4.5/plugins/pci-mei/fu-mei-common.c fwupd-1.5.8/plugins/pci-mei/fu-mei-common.c --- fwupd-1.4.5/plugins/pci-mei/fu-mei-common.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/pci-mei/fu-mei-common.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,395 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-mei-common.h" + +const gchar * +fu_mei_common_family_to_string (FuMeiFamily family) +{ + if (family == FU_MEI_FAMILY_SPS) + return "SPS"; + if (family == FU_MEI_FAMILY_TXE) + return "TXE"; + if (family == FU_MEI_FAMILY_ME) + return "ME"; + if (family == FU_MEI_FAMILY_CSME) + return "CSME"; + return "AMT"; +} + +static gint +fu_mei_common_cmp_version (FuMeiVersion *vers1, FuMeiVersion *vers2) +{ + guint16 vers1buf[] = { + vers1->major, + vers1->minor, + vers1->hotfix, + vers1->buildno, + }; + guint16 vers2buf[] = { + vers2->major, + vers2->minor, + vers2->hotfix, + vers2->buildno, + }; + for (guint i = 0; i < 4; i++) { + if (vers1buf[i] < vers2buf[i]) + return -1; + if (vers1buf[i] > vers2buf[i]) + return 1; + } + return 0; +} + +FuMeiIssue +fu_mei_common_is_csme_vulnerable (FuMeiVersion *vers) +{ + if (vers->major == 11 && vers->minor == 8 && vers->hotfix >= 70) + return FU_MEI_ISSUE_PATCHED; + if (vers->major == 11 && vers->minor == 11 && vers->hotfix >= 70) + return FU_MEI_ISSUE_PATCHED; + if (vers->major == 11 && vers->minor == 22 && vers->hotfix >= 70) + return FU_MEI_ISSUE_PATCHED; + if (vers->major == 12 && vers->minor == 0 && (vers->hotfix == 49 || vers->hotfix >= 56)) + return FU_MEI_ISSUE_PATCHED; + if (vers->major == 13 && vers->minor == 0 && vers->hotfix >= 21) + return FU_MEI_ISSUE_PATCHED; + if (vers->major == 14 && vers->minor == 0 && vers->hotfix >= 11) + return FU_MEI_ISSUE_PATCHED; + if (vers->major == 15) + return FU_MEI_ISSUE_NOT_VULNERABLE; + return FU_MEI_ISSUE_VULNERABLE; +} + +FuMeiIssue +fu_mei_common_is_txe_vulnerable (FuMeiVersion *vers) +{ + if (vers->major == 3 && vers->minor == 1 && vers->hotfix >= 70) + return FU_MEI_ISSUE_PATCHED; + if (vers->major == 4 && vers->minor == 0 && vers->hotfix >= 20) + return FU_MEI_ISSUE_PATCHED; + if (vers->major == 5) + return FU_MEI_ISSUE_NOT_VULNERABLE; + return FU_MEI_ISSUE_VULNERABLE; +} + +FuMeiIssue +fu_mei_common_is_sps_vulnerable (FuMeiVersion *vers) +{ + if (vers->major == 3 || vers->major > 5) + return FU_MEI_ISSUE_NOT_VULNERABLE; + if (vers->major == 4) { + if (vers->hotfix < 44) + return FU_MEI_ISSUE_VULNERABLE; + if (vers->platform == 0xA) { /* Purley */ + FuMeiVersion ver2 = { + .major = 4, + .minor = 1, + .hotfix = 4, + .buildno = 339, + }; + if (fu_mei_common_cmp_version (vers, &ver2) < 0) + return FU_MEI_ISSUE_VULNERABLE; + } else if (vers->platform == 0xE) { /* Bakerville */ + FuMeiVersion ver2 = { + .major = 4, + .minor = 0, + .hotfix = 4, + .buildno = 112, + }; + if (fu_mei_common_cmp_version (vers, &ver2) < 0) + return FU_MEI_ISSUE_VULNERABLE; + } else if (vers->platform == 0xB) { /* Harrisonville */ + FuMeiVersion ver2 = { + .major = 4, + .minor = 0, + .hotfix = 4, + .buildno = 193, + }; + if (fu_mei_common_cmp_version (vers, &ver2) < 0) + return FU_MEI_ISSUE_VULNERABLE; + } else if (vers->platform == 0x9) { /* Greenlow */ + FuMeiVersion ver2 = { + .major = 4, + .minor = 1, + .hotfix = 4, + .buildno = 88, + }; + if (vers->minor < 1) + return FU_MEI_ISSUE_NOT_VULNERABLE; + if (fu_mei_common_cmp_version (vers, &ver2) < 0) + return FU_MEI_ISSUE_VULNERABLE; + } else if (vers->platform == 0xD) { /* MonteVista */ + FuMeiVersion ver2 = { + .major = 4, + .minor = 8, + .hotfix = 4, + .buildno = 51, + }; + if (fu_mei_common_cmp_version (vers, &ver2) < 0) + return FU_MEI_ISSUE_VULNERABLE; + } + return FU_MEI_ISSUE_NOT_VULNERABLE; + } + if (vers->major == 5) { + if (vers->platform == 0x10) { /* Mehlow */ + FuMeiVersion ver2 = { 5, 1, 3, 89 }; + if (fu_mei_common_cmp_version (vers, &ver2) < 0) + return FU_MEI_ISSUE_VULNERABLE; + } + return FU_MEI_ISSUE_NOT_VULNERABLE; + } + return FU_MEI_ISSUE_PATCHED; +} + +/* HFS1[3:0] Current Working State Values */ +static const char *me_cws_values[] = { + [ME_HFS_CWS_RESET] = "reset", + [ME_HFS_CWS_INIT] = "initializing", + [ME_HFS_CWS_REC] = "recovery", + [ME_HFS_CWS_TEST] = "test", + [ME_HFS_CWS_DISABLED] = "disabled", + [ME_HFS_CWS_NORMAL] = "normal", + [ME_HFS_CWS_WAIT] = "wait", + [ME_HFS_CWS_TRANS] = "transition", + [ME_HFS_CWS_INVALID] = "invalid", +}; + +/* HFS1[8:6] Current Operation State Values */ +static const char *me_opstate_values[] = { + [ME_HFS_STATE_PREBOOT] = "preboot", + [ME_HFS_STATE_M0_UMA] = "m0-with-uma", + [ME_HFS_STATE_M3] = "m3-without-uma", + [ME_HFS_STATE_M0] = "m0-without-uma", + [ME_HFS_STATE_BRINGUP] = "bring-up", + [ME_HFS_STATE_ERROR] = "error", +}; + +/* HFS[19:16] Current Operation Mode Values */ +static const char *me_opmode_values[] = { + [ME_HFS_MODE_NORMAL] = "normal", + [ME_HFS_MODE_DEBUG] = "debug", + [ME_HFS_MODE_DIS] = "disable", + [ME_HFS_MODE_OVER_JMPR] = "override-jumper", + [ME_HFS_MODE_OVER_MEI] = "override-mei", + [ME_HFS_MODE_UNKNOWN_6] = "unknown-6", + [ME_HFS_MODE_MAYBE_SPS] = "maybe-sps", +}; + +/* HFS[15:12] Error Code Values */ +static const char *me_error_values[] = { + [ME_HFS_ERROR_NONE] = "no-error", + [ME_HFS_ERROR_UNCAT] = "uncategorized-failure", + [ME_HFS_ERROR_DISABLED] = "disabled", + [ME_HFS_ERROR_IMAGE] = "image-failure", + [ME_HFS_ERROR_DEBUG] = "debug-failure", +}; + +void +fu_mei_hfsts1_to_string (FuMeiHfsts1 hfsts1, guint idt, GString *str) +{ + fu_common_string_append_kv (str, idt, "WorkingState", + me_cws_values[hfsts1.fields.working_state]); + fu_common_string_append_kb (str, idt, "MfgMode", + hfsts1.fields.mfg_mode); + fu_common_string_append_kb (str, idt, "FptBad", + hfsts1.fields.fpt_bad); + fu_common_string_append_kv (str, idt, "OperationState", + me_opstate_values[hfsts1.fields.operation_state]); + fu_common_string_append_kb (str, idt, "FwInitComplete", + hfsts1.fields.fw_init_complete); + fu_common_string_append_kb (str, idt, "FtBupLdFlr", + hfsts1.fields.ft_bup_ld_flr); + fu_common_string_append_kb (str, idt, "UpdateInProgress", + hfsts1.fields.update_in_progress); + fu_common_string_append_kv (str, idt, "ErrorCode", + me_error_values[hfsts1.fields.error_code]); + fu_common_string_append_kv (str, idt, "OperationMode", + me_opmode_values[hfsts1.fields.operation_mode]); + fu_common_string_append_kx (str, idt, "ResetCount", + hfsts1.fields.reset_count); + fu_common_string_append_kb (str, idt, "BootOptions_present", + hfsts1.fields.boot_options_present); + fu_common_string_append_kb (str, idt, "BistFinished", + hfsts1.fields.bist_finished); + fu_common_string_append_kb (str, idt, "BistTestState", + hfsts1.fields.bist_test_state); + fu_common_string_append_kb (str, idt, "BistResetRequest", + hfsts1.fields.bist_reset_request); + fu_common_string_append_kx (str, idt, "CurrentPowerSource", + hfsts1.fields.current_power_source); + fu_common_string_append_kb (str, idt, "D3SupportValid", + hfsts1.fields.d3_support_valid); + fu_common_string_append_kb (str, idt, "D0i3SupportValid", + hfsts1.fields.d0i3_support_valid); +} + +void +fu_mei_hfsts2_to_string (FuMeiHfsts2 hfsts2, guint idt, GString *str) +{ + fu_common_string_append_kb (str, idt, "NftpLoadFailure", + hfsts2.fields.nftp_load_failure); + fu_common_string_append_kx (str, idt, "IccProgStatus", + hfsts2.fields.icc_prog_status); + fu_common_string_append_kb (str, idt, "InvokeMebx", + hfsts2.fields.invoke_mebx); + fu_common_string_append_kb (str, idt, "CpuReplaced", + hfsts2.fields.cpu_replaced); + fu_common_string_append_kb (str, idt, "Rsvd0", + hfsts2.fields.rsvd0); + fu_common_string_append_kb (str, idt, "MfsFailure", + hfsts2.fields.mfs_failure); + fu_common_string_append_kb (str, idt, "WarmResetRqst", + hfsts2.fields.warm_reset_rqst); + fu_common_string_append_kb (str, idt, "CpuReplacedValid", + hfsts2.fields.cpu_replaced_valid); + fu_common_string_append_kb (str, idt, "LowPowerState", + hfsts2.fields.low_power_state); + fu_common_string_append_kb (str, idt, "MePowerGate", + hfsts2.fields.me_power_gate); + fu_common_string_append_kb (str, idt, "IpuNeeded", + hfsts2.fields.ipu_needed); + fu_common_string_append_kb (str, idt, "ForcedSafeBoot", + hfsts2.fields.forced_safe_boot); + fu_common_string_append_kx (str, idt, "Rsvd1", + hfsts2.fields.rsvd1); + fu_common_string_append_kb (str, idt, "ListenerChange", + hfsts2.fields.listener_change); + fu_common_string_append_kx (str, idt, "StatusData", + hfsts2.fields.status_data); + fu_common_string_append_kx (str, idt, "CurrentPmevent", + hfsts2.fields.current_pmevent); + fu_common_string_append_kx (str, idt, "Phase", + hfsts2.fields.phase); +} + +void +fu_mei_hfsts3_to_string (FuMeiHfsts3 hfsts3, guint idt, GString *str) +{ + fu_common_string_append_kx (str, idt, "Chunk0", + hfsts3.fields.chunk0); + fu_common_string_append_kx (str, idt, "Chunk1", + hfsts3.fields.chunk1); + fu_common_string_append_kx (str, idt, "Chunk2", + hfsts3.fields.chunk2); + fu_common_string_append_kx (str, idt, "Chunk3", + hfsts3.fields.chunk3); + fu_common_string_append_kx (str, idt, "FwSku", + hfsts3.fields.fw_sku); + fu_common_string_append_kb (str, idt, "EncryptKeyCheck", + hfsts3.fields.encrypt_key_check); + fu_common_string_append_kb (str, idt, "PchConfigChange", + hfsts3.fields.pch_config_change); + fu_common_string_append_kb (str, idt, "IbbVerificationResult", + hfsts3.fields.ibb_verification_result); + fu_common_string_append_kb (str, idt, "IbbVerificationDone", + hfsts3.fields.ibb_verification_done); + fu_common_string_append_kx (str, idt, "Reserved11", + hfsts3.fields.reserved_11); + fu_common_string_append_kx (str, idt, "ActualIbbSize", + hfsts3.fields.actual_ibb_size * 1024); + fu_common_string_append_ku (str, idt, "NumberOfChunks", + hfsts3.fields.number_of_chunks); + fu_common_string_append_kb (str, idt, "EncryptKeyOverride", + hfsts3.fields.encrypt_key_override); + fu_common_string_append_kb (str, idt, "PowerDownMitigation", + hfsts3.fields.power_down_mitigation); +} + +void +fu_mei_hfsts4_to_string (FuMeiHfsts4 hfsts4, guint idt, GString *str) +{ + fu_common_string_append_kx (str, idt, "Rsvd0", + hfsts4.fields.rsvd0); + fu_common_string_append_kb (str, idt, "EnforcementFlow", + hfsts4.fields.enforcement_flow); + fu_common_string_append_kb (str, idt, "SxResumeType", + hfsts4.fields.sx_resume_type); + fu_common_string_append_kb (str, idt, "Rsvd1", + hfsts4.fields.rsvd1); + fu_common_string_append_kb (str, idt, "TpmsDisconnected", + hfsts4.fields.tpms_disconnected); + fu_common_string_append_kb (str, idt, "Rvsd2", + hfsts4.fields.rvsd2); + fu_common_string_append_kb (str, idt, "FwstsValid", + hfsts4.fields.fwsts_valid); + fu_common_string_append_kb (str, idt, "BootGuardSelfTest", + hfsts4.fields.boot_guard_self_test); + fu_common_string_append_kx (str, idt, "Rsvd3", + hfsts4.fields.rsvd3); +} + +void +fu_mei_hfsts5_to_string (FuMeiHfsts5 hfsts5, guint idt, GString *str) +{ + fu_common_string_append_kb (str, idt, "AcmActive", + hfsts5.fields.acm_active); + fu_common_string_append_kb (str, idt, "Valid", + hfsts5.fields.valid); + fu_common_string_append_kb (str, idt, "ResultCodeSource", + hfsts5.fields.result_code_source); + fu_common_string_append_kx (str, idt, "ErrorStatusCode", + hfsts5.fields.error_status_code); + fu_common_string_append_kx (str, idt, "AcmDoneSts", + hfsts5.fields.acm_done_sts); + fu_common_string_append_kx (str, idt, "TimeoutCount", + hfsts5.fields.timeout_count); + fu_common_string_append_kb (str, idt, "ScrtmIndicator", + hfsts5.fields.scrtm_indicator); + fu_common_string_append_kx (str, idt, "IncBootGuardAcm", + hfsts5.fields.inc_boot_guard_acm); + fu_common_string_append_kx (str, idt, "IncKeyManifest", + hfsts5.fields.inc_key_manifest); + fu_common_string_append_kx (str, idt, "IncBootPolicy", + hfsts5.fields.inc_boot_policy); + fu_common_string_append_kx (str, idt, "Rsvd0", + hfsts5.fields.rsvd0); + fu_common_string_append_kb (str, idt, "StartEnforcement", + hfsts5.fields.start_enforcement); +} + +void +fu_mei_hfsts6_to_string (FuMeiHfsts6 hfsts6, guint idt, GString *str) +{ + fu_common_string_append_kb (str, idt, "ForceBootGuardAcm", + hfsts6.fields.force_boot_guard_acm); + fu_common_string_append_kb (str, idt, "CpuDebugDisable", + hfsts6.fields.cpu_debug_disable); + fu_common_string_append_kb (str, idt, "BspInitDisable", + hfsts6.fields.bsp_init_disable); + fu_common_string_append_kb (str, idt, "ProtectBiosEnv", + hfsts6.fields.protect_bios_env); + fu_common_string_append_kx (str, idt, "Rsvd0", + hfsts6.fields.rsvd0); + fu_common_string_append_kx (str, idt, "ErrorEnforcePolicy", + hfsts6.fields.error_enforce_policy); + fu_common_string_append_kb (str, idt, "MeasuredBoot", + hfsts6.fields.measured_boot); + fu_common_string_append_kb (str, idt, "VerifiedBoot", + hfsts6.fields.verified_boot); + fu_common_string_append_kx (str, idt, "BootGuardAcmsvn", + hfsts6.fields.boot_guard_acmsvn); + fu_common_string_append_kx (str, idt, "Kmsvn", + hfsts6.fields.kmsvn); + fu_common_string_append_kx (str, idt, "Bpmsvn", + hfsts6.fields.bpmsvn); + fu_common_string_append_kx (str, idt, "KeyManifestId", + hfsts6.fields.key_manifest_id); + fu_common_string_append_kb (str, idt, "BootPolicyStatus", + hfsts6.fields.boot_policy_status); + fu_common_string_append_kb (str, idt, "Error", + hfsts6.fields.error); + fu_common_string_append_kb (str, idt, "BootGuardDisable", + hfsts6.fields.boot_guard_disable); + fu_common_string_append_kb (str, idt, "FpfDisable", + hfsts6.fields.fpf_disable); + fu_common_string_append_kb (str, idt, "FpfSocLock", + hfsts6.fields.fpf_soc_lock); + fu_common_string_append_kb (str, idt, "TxtSupport", + hfsts6.fields.txt_support); +} diff -Nru fwupd-1.4.5/plugins/pci-mei/fu-mei-common.h fwupd-1.5.8/plugins/pci-mei/fu-mei-common.h --- fwupd-1.4.5/plugins/pci-mei/fu-mei-common.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/pci-mei/fu-mei-common.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +typedef enum { + FU_MEI_FAMILY_UNKNOWN, + FU_MEI_FAMILY_SPS, + FU_MEI_FAMILY_TXE, + FU_MEI_FAMILY_ME, + FU_MEI_FAMILY_CSME, +} FuMeiFamily; + +typedef enum { + FU_MEI_ISSUE_UNKNOWN, + FU_MEI_ISSUE_NOT_VULNERABLE, + FU_MEI_ISSUE_VULNERABLE, + FU_MEI_ISSUE_PATCHED, +} FuMeiIssue; + +typedef struct { + guint8 platform; + guint8 major; + guint8 minor; + guint8 hotfix; + guint16 buildno; +} FuMeiVersion; + +/* Host Firmware Status register 1 */ +typedef union { + guint32 data; + struct { + guint32 working_state : 4; + guint32 mfg_mode : 1; + guint32 fpt_bad : 1; + guint32 operation_state : 3; + guint32 fw_init_complete : 1; + guint32 ft_bup_ld_flr : 1; + guint32 update_in_progress : 1; + guint32 error_code : 4; + guint32 operation_mode : 4; + guint32 reset_count : 4; + guint32 boot_options_present : 1; + guint32 bist_finished : 1; + guint32 bist_test_state : 1; + guint32 bist_reset_request : 1; + guint32 current_power_source : 2; + guint32 d3_support_valid : 1; + guint32 d0i3_support_valid : 1; + } __attribute__((packed)) fields; +} FuMeiHfsts1; + +/* Host Firmware Status Register 2 */ +typedef union { + guint32 data; + struct { + guint32 nftp_load_failure : 1; + guint32 icc_prog_status : 2; + guint32 invoke_mebx : 1; + guint32 cpu_replaced : 1; + guint32 rsvd0 : 1; + guint32 mfs_failure : 1; + guint32 warm_reset_rqst : 1; + guint32 cpu_replaced_valid : 1; + guint32 low_power_state : 1; + guint32 me_power_gate : 1; + guint32 ipu_needed : 1; + guint32 forced_safe_boot : 1; + guint32 rsvd1 : 2; + guint32 listener_change : 1; + guint32 status_data : 8; + guint32 current_pmevent : 4; + guint32 phase : 4; + } __attribute__((packed)) fields; +} FuMeiHfsts2; + +/* Host Firmware Status Register 3 */ +typedef union { + guint32 data; + struct { + guint32 chunk0 : 1; + guint32 chunk1 : 1; + guint32 chunk2 : 1; + guint32 chunk3 : 1; + guint32 fw_sku : 3; + guint32 encrypt_key_check : 1; + guint32 pch_config_change : 1; + guint32 ibb_verification_result : 1; + guint32 ibb_verification_done : 1; + guint32 reserved_11 : 3; + guint32 actual_ibb_size : 14; + guint32 number_of_chunks : 2; + guint32 encrypt_key_override : 1; + guint32 power_down_mitigation : 1; + } __attribute__((packed)) fields; +} FuMeiHfsts3; + +/* Host Firmware Status Register 4 */ +typedef union { + guint32 data; + struct { + guint32 rsvd0 : 9; + guint32 enforcement_flow : 1; + guint32 sx_resume_type : 1; + guint32 rsvd1 : 1; + guint32 tpms_disconnected : 1; + guint32 rvsd2 : 1; + guint32 fwsts_valid : 1; + guint32 boot_guard_self_test : 1; + guint32 rsvd3 : 16; + } __attribute__((packed)) fields; +} FuMeiHfsts4; + +/* Host Firmware Status Register 5 */ +typedef union { + guint32 data; + struct { + guint32 acm_active : 1; + guint32 valid : 1; + guint32 result_code_source : 1; + guint32 error_status_code : 5; + guint32 acm_done_sts : 1; + guint32 timeout_count : 7; + guint32 scrtm_indicator : 1; + guint32 inc_boot_guard_acm : 4; + guint32 inc_key_manifest : 4; + guint32 inc_boot_policy : 4; + guint32 rsvd0 : 2; + guint32 start_enforcement : 1; + } __attribute__((packed)) fields; +} FuMeiHfsts5; + +/* Host Firmware Status Register 6 */ +typedef union { + guint32 data; + struct { + guint32 force_boot_guard_acm : 1; + guint32 cpu_debug_disable : 1; + guint32 bsp_init_disable : 1; + guint32 protect_bios_env : 1; + guint32 rsvd0 : 2; + guint32 error_enforce_policy : 2; + guint32 measured_boot : 1; + guint32 verified_boot : 1; + guint32 boot_guard_acmsvn : 4; + guint32 kmsvn : 4; + guint32 bpmsvn : 4; + guint32 key_manifest_id : 4; + guint32 boot_policy_status : 1; + guint32 error : 1; + guint32 boot_guard_disable : 1; + guint32 fpf_disable : 1; + guint32 fpf_soc_lock : 1; + guint32 txt_support : 1; + } __attribute__((packed)) fields; +} FuMeiHfsts6; + +#define ME_HFS_CWS_RESET 0 +#define ME_HFS_CWS_INIT 1 +#define ME_HFS_CWS_REC 2 +#define ME_HFS_CWS_TEST 3 +#define ME_HFS_CWS_DISABLED 4 +#define ME_HFS_CWS_NORMAL 5 +#define ME_HFS_CWS_WAIT 6 +#define ME_HFS_CWS_TRANS 7 +#define ME_HFS_CWS_INVALID 8 + +#define ME_HFS_STATE_PREBOOT 0 +#define ME_HFS_STATE_M0_UMA 1 +#define ME_HFS_STATE_M3 4 +#define ME_HFS_STATE_M0 5 +#define ME_HFS_STATE_BRINGUP 6 +#define ME_HFS_STATE_ERROR 7 + +#define ME_HFS_ERROR_NONE 0 +#define ME_HFS_ERROR_UNCAT 1 +#define ME_HFS_ERROR_DISABLED 2 +#define ME_HFS_ERROR_IMAGE 3 +#define ME_HFS_ERROR_DEBUG 4 + +#define ME_HFS_MODE_NORMAL 0 +#define ME_HFS_MODE_DEBUG 2 +#define ME_HFS_MODE_DIS 3 +#define ME_HFS_MODE_OVER_JMPR 4 +#define ME_HFS_MODE_OVER_MEI 5 +#define ME_HFS_MODE_UNKNOWN_6 6 +#define ME_HFS_MODE_MAYBE_SPS 7 + +#define ME_HFS_ENFORCEMENT_POLICY_NOTHING 0b00 +#define ME_HFS_ENFORCEMENT_POLICY_SHUTDOWN_TO 0b01 +#define ME_HFS_ENFORCEMENT_POLICY_SHUTDOWN_NOW 0b11 + +const gchar *fu_mei_common_family_to_string (FuMeiFamily family); +FuMeiIssue fu_mei_common_is_csme_vulnerable (FuMeiVersion *vers); +FuMeiIssue fu_mei_common_is_txe_vulnerable (FuMeiVersion *vers); +FuMeiIssue fu_mei_common_is_sps_vulnerable (FuMeiVersion *vers); + +void fu_mei_hfsts1_to_string (FuMeiHfsts1 hfsts1, + guint idt, + GString *str); +void fu_mei_hfsts2_to_string (FuMeiHfsts2 hfsts2, + guint idt, + GString *str); +void fu_mei_hfsts3_to_string (FuMeiHfsts3 hfsts3, + guint idt, + GString *str); +void fu_mei_hfsts4_to_string (FuMeiHfsts4 hfsts4, + guint idt, + GString *str); +void fu_mei_hfsts5_to_string (FuMeiHfsts5 hfsts5, + guint idt, + GString *str); +void fu_mei_hfsts6_to_string (FuMeiHfsts6 hfsts6, + guint idt, + GString *str); diff -Nru fwupd-1.4.5/plugins/pci-mei/fu-plugin-pci-mei.c fwupd-1.5.8/plugins/pci-mei/fu-plugin-pci-mei.c --- fwupd-1.4.5/plugins/pci-mei/fu-plugin-pci-mei.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/pci-mei/fu-plugin-pci-mei.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,480 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" + +#include "fu-mei-common.h" + +struct FuPluginData { + gboolean has_device; + FuMeiHfsts1 hfsts1; + FuMeiHfsts2 hfsts2; + FuMeiHfsts3 hfsts3; + FuMeiHfsts4 hfsts4; + FuMeiHfsts5 hfsts5; + FuMeiHfsts6 hfsts6; + FuMeiFamily family; + FuMeiVersion vers; + FuMeiIssue issue; +}; + +#define PCI_CFG_HFS_1 0x40 +#define PCI_CFG_HFS_2 0x48 +#define PCI_CFG_HFS_3 0x60 +#define PCI_CFG_HFS_4 0x64 +#define PCI_CFG_HFS_5 0x68 +#define PCI_CFG_HFS_6 0x6c + +static void +fu_mei_hfsts_to_string (FuPlugin *plugin, guint idt, GString *str) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + fu_common_string_append_kv (str, idt, "HFSTS1", NULL); + fu_mei_hfsts1_to_string (priv->hfsts1, idt + 1, str); + fu_common_string_append_kv (str, idt, "HFSTS2", NULL); + fu_mei_hfsts2_to_string (priv->hfsts2, idt + 1, str); + fu_common_string_append_kv (str, idt, "HFSTS3", NULL); + fu_mei_hfsts3_to_string (priv->hfsts3, idt + 1, str); + fu_common_string_append_kv (str, idt, "HFSTS4", NULL); + fu_mei_hfsts4_to_string (priv->hfsts4, idt + 1, str); + fu_common_string_append_kv (str, idt, "HFSTS5", NULL); + fu_mei_hfsts5_to_string (priv->hfsts5, idt + 1, str); + fu_common_string_append_kv (str, idt, "HFSTS6", NULL); + fu_mei_hfsts6_to_string (priv->hfsts6, idt + 1, str); +} + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_udev_subsystem (plugin, "pci"); +} + +static FuMeiFamily +fu_mei_detect_family (FuPlugin *plugin) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + guint8 ver = priv->vers.major; + + if (ver == 1 || ver == 2) { + if (priv->hfsts1.fields.operation_mode == 0xf) + return FU_MEI_FAMILY_SPS; + return FU_MEI_FAMILY_TXE; + } + if (ver == 3 || ver == 4 || ver == 5) + return FU_MEI_FAMILY_TXE; + if (ver == 6 || ver == 7 || ver == 8 || ver == 9 || ver == 10) + return FU_MEI_FAMILY_ME; + if (ver == 11 || ver == 12 || ver == 13 || ver == 14 || ver == 15) + return FU_MEI_FAMILY_CSME; + return FU_MEI_FAMILY_UNKNOWN; +} + +static gboolean +fu_mei_parse_fwvers (FuPlugin *plugin, const gchar *fwvers, GError **error) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_auto(GStrv) lines = NULL; + g_auto(GStrv) sections = NULL; + g_auto(GStrv) split = NULL; + + /* we only care about the first version */ + lines = g_strsplit (fwvers, "\n", -1); + if (g_strv_length (lines) < 1) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "expected data, got %s", fwvers); + return FALSE; + } + + /* split platform : version */ + sections = g_strsplit (lines[0], ":", -1); + if (g_strv_length (sections) != 2) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "expected platform:major.minor.micro.build, got %s", + lines[0]); + return FALSE; + } + + /* parse platform and versions */ + priv->vers.platform = fu_common_strtoull (sections[0]); + split = g_strsplit (sections[1], ".", -1); + if (g_strv_length (split) != 4) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "expected major.minor.micro.build, got %s", + sections[1]); + return FALSE; + } + priv->vers.major = fu_common_strtoull (split[0]); + priv->vers.minor = fu_common_strtoull (split[1]); + priv->vers.hotfix = fu_common_strtoull (split[2]); + priv->vers.buildno = fu_common_strtoull (split[3]); + + /* check the AMT version for issues using the data from: + * https://downloadcenter.intel.com/download/28632 */ + priv->family = fu_mei_detect_family (plugin); + if (priv->family == FU_MEI_FAMILY_CSME) + priv->issue = fu_mei_common_is_csme_vulnerable (&priv->vers); + else if (priv->family == FU_MEI_FAMILY_TXE) + priv->issue = fu_mei_common_is_txe_vulnerable (&priv->vers); + else if (priv->family == FU_MEI_FAMILY_SPS) + priv->issue = fu_mei_common_is_sps_vulnerable (&priv->vers); + if (g_getenv ("FWUPD_MEI_VERBOSE") != NULL) { + g_debug ("%s version parsed as %u.%u.%u", + fu_mei_common_family_to_string (priv->family), + priv->vers.major, priv->vers.minor, priv->vers.hotfix); + } + return TRUE; +} + +gboolean +fu_plugin_backend_device_added (FuPlugin *plugin, FuDevice *device, GError **error) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + const gchar *fwvers; + guint8 buf[4] = { 0x0 }; + g_autoptr(FuDeviceLocker) locker = NULL; + + /* interesting device? */ + if (!FU_IS_UDEV_DEVICE (device)) + return TRUE; + if (g_strcmp0 (fu_udev_device_get_subsystem (FU_UDEV_DEVICE (device)), "pci") != 0) + return TRUE; + + /* open the config */ + fu_udev_device_set_flags (FU_UDEV_DEVICE (device), FU_UDEV_DEVICE_FLAG_USE_CONFIG); + if (!fu_udev_device_set_physical_id (FU_UDEV_DEVICE (device), "pci", error)) + return FALSE; + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + + /* grab MEI config registers */ + if (!fu_udev_device_pread_full (FU_UDEV_DEVICE (device), PCI_CFG_HFS_1, buf, sizeof(buf), error)) { + g_prefix_error (error, "could not read HFS1: "); + return FALSE; + } + priv->hfsts1.data = fu_common_read_uint32 (buf, G_LITTLE_ENDIAN); + if (!fu_udev_device_pread_full (FU_UDEV_DEVICE (device), PCI_CFG_HFS_2, buf, sizeof(buf), error)) { + g_prefix_error (error, "could not read HFS2: "); + return FALSE; + } + priv->hfsts2.data = fu_common_read_uint32 (buf, G_LITTLE_ENDIAN); + if (!fu_udev_device_pread_full (FU_UDEV_DEVICE (device), PCI_CFG_HFS_3, buf, sizeof(buf), error)) { + g_prefix_error (error, "could not read HFS3: "); + return FALSE; + } + priv->hfsts3.data = fu_common_read_uint32 (buf, G_LITTLE_ENDIAN); + if (!fu_udev_device_pread_full (FU_UDEV_DEVICE (device), PCI_CFG_HFS_4, buf, sizeof(buf), error)) { + g_prefix_error (error, "could not read HFS4: "); + return FALSE; + } + priv->hfsts4.data = fu_common_read_uint32 (buf, G_LITTLE_ENDIAN); + if (!fu_udev_device_pread_full (FU_UDEV_DEVICE (device), PCI_CFG_HFS_5, buf, sizeof(buf), error)) { + g_prefix_error (error, "could not read HFS5: "); + return FALSE; + } + priv->hfsts5.data = fu_common_read_uint32 (buf, G_LITTLE_ENDIAN); + if (!fu_udev_device_pread_full (FU_UDEV_DEVICE (device), PCI_CFG_HFS_6, buf, sizeof(buf), error)) { + g_prefix_error (error, "could not read HFS6: "); + return FALSE; + } + priv->hfsts6.data = fu_common_read_uint32 (buf, G_LITTLE_ENDIAN); + priv->has_device = TRUE; + + /* dump to console */ + if (g_getenv ("FWUPD_PCI_MEI_VERBOSE") != NULL) { + g_autoptr(GString) str = g_string_new (NULL); + fu_mei_hfsts_to_string (plugin, 0, str); + g_debug ("\n%s", str->str); + } + + /* check firmware version */ + fwvers = fu_udev_device_get_sysfs_attr (FU_UDEV_DEVICE (device), "mei/mei0/fw_ver", NULL); + if (fwvers != NULL) { + if (!fu_mei_parse_fwvers (plugin, fwvers, error)) + return FALSE; + } + + /* success */ + return TRUE; +} + +static void +fu_plugin_add_security_attrs_manufacturing_mode (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_MEI_MANUFACTURING_MODE); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_add_metadata (attr, "kind", fu_mei_common_family_to_string (priv->family)); + fu_security_attrs_append (attrs, attr); + + /* Manufacturing Mode */ + if (priv->hfsts1.fields.mfg_mode) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_LOCKED); +} + +static void +fu_plugin_add_security_attrs_override_strap (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_MEI_OVERRIDE_STRAP); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_add_metadata (attr, "kind", fu_mei_common_family_to_string (priv->family)); + fu_security_attrs_append (attrs, attr); + + /* Flash Descriptor Security Override Strap */ + if (priv->hfsts1.fields.operation_mode == ME_HFS_MODE_OVER_JMPR) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_LOCKED); +} + +static void +fu_plugin_add_security_attrs_bootguard_enabled (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* not supported */ + if (priv->family == FU_MEI_FAMILY_TXE) + return; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ENABLED); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT); + fwupd_security_attr_set_url (attr, "#org.fwupd.hsi.Kernel.IntelBootguard"); + fu_security_attrs_append (attrs, attr); + + /* disabled at runtime? */ + if (priv->hfsts6.fields.boot_guard_disable) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); +} + +static void +fu_plugin_add_security_attrs_bootguard_verified (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* not supported */ + if (priv->family == FU_MEI_FAMILY_TXE) + return; + + /* disabled */ + if (priv->hfsts6.fields.boot_guard_disable) + return; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_VERIFIED); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT); + fwupd_security_attr_set_url (attr, "#org.fwupd.hsi.Kernel.IntelBootguard"); + fu_security_attrs_append (attrs, attr); + + /* measured boot is not sufficient, verified is required */ + if (!priv->hfsts6.fields.verified_boot) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_VALID); +} + +static void +fu_plugin_add_security_attrs_bootguard_acm (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* not supported */ + if (priv->family == FU_MEI_FAMILY_TXE) + return; + + /* disabled */ + if (priv->hfsts6.fields.boot_guard_disable) + return; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ACM); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT); + fu_security_attrs_append (attrs, attr); + + /* ACM protection required */ + if (!priv->hfsts6.fields.force_boot_guard_acm) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_VALID); +} + +static void +fu_plugin_add_security_attrs_bootguard_policy (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* not supported */ + if (priv->family == FU_MEI_FAMILY_TXE) + return; + + /* disabled */ + if (priv->hfsts6.fields.boot_guard_disable) + return; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_POLICY); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL); + fwupd_security_attr_set_url (attr, "#org.fwupd.hsi.Kernel.IntelBootguard"); + fu_security_attrs_append (attrs, attr); + + /* policy must be to immediately shutdown */ + if (priv->hfsts6.fields.error_enforce_policy != ME_HFS_ENFORCEMENT_POLICY_SHUTDOWN_NOW) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_VALID); +} + +static void +fu_plugin_add_security_attrs_bootguard_otp (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* not supported */ + if (priv->family == FU_MEI_FAMILY_TXE) + return; + + /* disabled */ + if (priv->hfsts6.fields.boot_guard_disable) + return; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_OTP); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT); + fwupd_security_attr_set_url (attr, "#org.fwupd.hsi.Kernel.IntelBootguard"); + fu_security_attrs_append (attrs, attr); + + /* ensure vendor set the FPF OTP fuse */ + if (!priv->hfsts6.fields.fpf_soc_lock) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_VALID); +} + +static void +fu_plugin_add_security_attrs_bootguard (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + fu_plugin_add_security_attrs_bootguard_enabled (plugin, attrs); + fu_plugin_add_security_attrs_bootguard_verified (plugin, attrs); + fu_plugin_add_security_attrs_bootguard_acm (plugin, attrs); + fu_plugin_add_security_attrs_bootguard_policy (plugin, attrs); + fu_plugin_add_security_attrs_bootguard_otp (plugin, attrs); +} + +static void +fu_plugin_add_security_attrs_mei_version (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autofree gchar *version = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* format version as string */ + version = g_strdup_printf ("%u:%u.%u.%u.%u", + priv->vers.platform, + priv->vers.major, + priv->vers.minor, + priv->vers.hotfix, + priv->vers.buildno); + if (priv->issue == FU_MEI_ISSUE_UNKNOWN) { + g_warning ("ME family not supported for %s", version); + return; + } + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_MEI_VERSION); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_add_metadata (attr, "kind", fu_mei_common_family_to_string (priv->family)); + fwupd_security_attr_add_metadata (attr, "version", version); + fu_security_attrs_append (attrs, attr); + + /* Flash Descriptor Security Override Strap */ + if (priv->issue == FU_MEI_ISSUE_VULNERABLE) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); + return; + } + + /* success */ + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_VALID); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + + /* only Intel */ + if (fu_common_get_cpu_vendor () != FU_CPU_VENDOR_INTEL) + return; + if (!priv->has_device) + return; + + fu_plugin_add_security_attrs_manufacturing_mode (plugin, attrs); + fu_plugin_add_security_attrs_override_strap (plugin, attrs); + fu_plugin_add_security_attrs_bootguard (plugin, attrs); + fu_plugin_add_security_attrs_mei_version (plugin, attrs); +} diff -Nru fwupd-1.4.5/plugins/pci-mei/meson.build fwupd-1.5.8/plugins/pci-mei/meson.build --- fwupd-1.4.5/plugins/pci-mei/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/pci-mei/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,30 @@ +if host_machine.system() == 'linux' +cargs = ['-DG_LOG_DOMAIN="FuPluginPciMei"'] + +install_data(['pci-mei.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_pci_mei', + fu_hash, + sources : [ + 'fu-plugin-pci-mei.c', + 'fu-mei-common.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) +endif diff -Nru fwupd-1.4.5/plugins/pci-mei/pci-mei.quirk fwupd-1.5.8/plugins/pci-mei/pci-mei.quirk --- fwupd-1.4.5/plugins/pci-mei/pci-mei.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/pci-mei/pci-mei.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,2 @@ +[PCI\DRIVER_mei_me] +Plugin = pci_mei diff -Nru fwupd-1.4.5/plugins/pci-mei/README.md fwupd-1.5.8/plugins/pci-mei/README.md --- fwupd-1.4.5/plugins/pci-mei/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/pci-mei/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,12 @@ +PCI MEI +======= + +Introduction +------------ + +This plugin checks if the ME is in Manufacturing Mode. The result will be stored +in an security attribute for HSI. + +External interface access +------------------------- +This plugin requires read access to the config space of PCI devices (`/sys/class/pci_bus/*/device/config`) diff -Nru fwupd-1.4.5/plugins/pixart-rf/fu-plugin-pixart-rf.c fwupd-1.5.8/plugins/pixart-rf/fu-plugin-pixart-rf.c --- fwupd-1.4.5/plugins/pixart-rf/fu-plugin-pixart-rf.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/pixart-rf/fu-plugin-pixart-rf.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2020 Jimmy Yu + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" + + +#include "fu-pxi-device.h" +#include "fu-pxi-firmware.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_udev_subsystem (plugin, "hidraw"); + fu_plugin_set_device_gtype (plugin, FU_TYPE_PXI_DEVICE); + fu_plugin_add_firmware_gtype (plugin, "pixart", FU_TYPE_PXI_FIRMWARE); +} diff -Nru fwupd-1.4.5/plugins/pixart-rf/fu-pxi-device.c fwupd-1.5.8/plugins/pixart-rf/fu-pxi-device.c --- fwupd-1.4.5/plugins/pixart-rf/fu-pxi-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/pixart-rf/fu-pxi-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,944 @@ +/* + * Copyright (C) 2020 Jimmy Yu + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#ifdef HAVE_HIDRAW_H +#include +#include +#endif + +#include "fu-common.h" +#include "fu-chunk.h" + +#include "fu-pxi-device.h" +#include "fu-pxi-firmware.h" + +#define PXI_HID_DEV_OTA_INPUT_REPORT_ID 0x05 +#define PXI_HID_DEV_OTA_RETRANSMIT_REPORT_ID 0x06 +#define PXI_HID_DEV_OTA_FEATURE_REPORT_ID 0x07 + +#define PXI_HID_DEV_OTA_REPORT_USAGE_PAGE 0xff02u +#define PXI_HID_DEV_OTA_RETRANSMIT_USAGE_PAGE 0xff01u + +#define FU_PXI_DEVICE_CMD_FW_OTA_INIT 0x10u +#define FU_PXI_DEVICE_CMD_FW_WRITE 0x17u +#define FU_PXI_DEVICE_CMD_FW_UPGRADE 0x18u +#define FU_PXI_DEVICE_CMD_FW_MCU_RESET 0x22u +#define FU_PXI_DEVICE_CMD_FW_GET_INFO 0x23u +#define FU_PXI_DEVICE_CMD_FW_OBJECT_CREATE 0x25u +#define FU_PXI_DEVICE_CMD_FW_OTA_INIT_NEW 0x27u +#define FU_PXI_DEVICE_CMD_FW_OTA_RETRANSMIT 0x28u +#define FU_PXI_DEVICE_CMD_FW_OTA_DISCONNECT 0x29u +#define FU_PXI_DEVICE_CMD_FW_OTA_GET_MODEL 0x2bu +#define ERR_COMMAND_SUCCESS 0x0 + +#define FU_PXI_DEVICE_OBJECT_SIZE_MAX 4096 /* bytes */ +#define FU_PXI_DEVICE_OTA_BUF_SZ 512 /* bytes */ +#define FU_PXI_DEVICE_NOTTFY_RET_LEN 4 /* bytes */ +#define FU_PXI_DEVICE_FW_INFO_RET_LEN 8 /* bytes */ + +#define FU_PXI_DEVICE_NOTIFY_TIMEOUT_MS 5000 + +/* OTA target selection */ +enum ota_process_setting { + OTA_MAIN_FW, /* Main firmware */ + OTA_HELPER_FW, /* Helper firmware */ + OTA_EXTERNAL_RESOURCE, /* External resource */ +}; + +/* OTA spec check result */ +enum ota_spec_check_result { + OTA_SPEC_CHECK_OK = 1, /* Spec check ok */ + OTA_FW_OUT_OF_BOUNDS = 2, /* OTA firmware size out of bound */ + OTA_PROCESS_ILLEGAL = 3, /* Illegal OTA process */ + OTA_RECONNECT = 4, /* Inform OTA app do reconnect */ + OTA_FW_IMG_VERSION_ERROR = 5, /* FW image file version check error */ + OTA_DEVICE_LOW_BATTERY = 6, /* Device is under low battery */ + OTA_SPEC_CHECK_MAX_NUM, /* Max number of OTA driver defined error code */ +}; + +/* OTA disconnect reason */ +enum ota_disconnect_reason { + OTA_CODE_JUMP = 1, /* OTA code jump */ + OTA_UPDATE_DONE = 2, /* OTA update done */ + OTA_RESET, /* OTA reset */ +}; + +struct _FuPxiDevice { + FuUdevDevice parent_instance; + guint8 retransmit_id; + guint8 status; + guint8 new_flow; + guint16 offset; + guint16 checksum; + guint32 max_object_size; + guint16 mtu_size; + guint16 prn_threshold; + guint8 spec_check_result; + gchar *model_name; +}; + +G_DEFINE_TYPE (FuPxiDevice, fu_pxi_device, FU_TYPE_UDEV_DEVICE) + +#ifdef HAVE_HIDRAW_H +static gboolean +fu_pxi_device_get_raw_info (FuPxiDevice *self, struct hidraw_devinfo *info, GError **error) +{ + if (!fu_udev_device_ioctl (FU_UDEV_DEVICE (self), + HIDIOCGRAWINFO, (guint8 *) info, + NULL, error)) { + return FALSE; + } + return TRUE; +} +#endif + +static const gchar * +fu_pxi_device_spec_check_result_to_string (guint8 spec_check_result) +{ + if (spec_check_result == OTA_SPEC_CHECK_OK) + return "ok"; + if (spec_check_result == OTA_FW_OUT_OF_BOUNDS) + return "fw-out-of-bounds"; + if (spec_check_result == OTA_PROCESS_ILLEGAL) + return "process-illegal"; + if (spec_check_result == OTA_RECONNECT) + return "reconnect"; + if (spec_check_result == OTA_FW_IMG_VERSION_ERROR) + return "fw-img-version-error"; + if (spec_check_result == OTA_DEVICE_LOW_BATTERY) + return "device battery is too low"; + return NULL; +} + +static void +fu_pxi_device_to_string (FuDevice *device, guint idt, GString *str) +{ + FuPxiDevice *self = FU_PXI_DEVICE (device); + + /* FuUdevDevice->to_string */ + FU_DEVICE_CLASS (fu_pxi_device_parent_class)->to_string (device, idt, str); + + fu_common_string_append_kv (str, idt, "ModelName", self->model_name); + fu_common_string_append_kx (str, idt, "Status", self->status); + fu_common_string_append_kx (str, idt, "NewFlow", self->new_flow); + fu_common_string_append_kx (str, idt, "CurrentObjectOffset", self->offset); + fu_common_string_append_kx (str, idt, "CurrentChecksum", self->checksum); + fu_common_string_append_kx (str, idt, "MaxObjectSize", self->max_object_size); + fu_common_string_append_kx (str, idt, "MtuSize", self->mtu_size); + fu_common_string_append_kx (str, idt, "PacketReceiptNotificationThreshold", self->prn_threshold); + fu_common_string_append_kv (str, idt, "SpecCheckResult", + fu_pxi_device_spec_check_result_to_string (self->spec_check_result)); + fu_common_string_append_kx (str, idt, "RetransmitID", self->retransmit_id); +} + +static FuFirmware * +fu_pxi_device_prepare_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + FuPxiDevice *self = FU_PXI_DEVICE (device); + const gchar *model_name; + g_autoptr(FuFirmware) firmware = fu_pxi_firmware_new (); + + if (!fu_firmware_parse (firmware, fw, flags, error)) + return NULL; + + /* check is compatible with hardware */ + model_name = fu_pxi_firmware_get_model_name (FU_PXI_FIRMWARE (firmware)); + if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + if (self->model_name == NULL || model_name == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "legacy device or firmware detected, " + "--force required"); + return NULL; + } + if (g_strcmp0 (self->model_name, model_name) != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "incompatible firmware, got %s, expected %s.", + model_name, self->model_name); + return NULL; + } + } + + return g_steal_pointer (&firmware); +} + +static gboolean +fu_pxi_device_set_feature (FuPxiDevice *self, GByteArray *req, GError **error) +{ +#ifdef HAVE_HIDRAW_H + if (g_getenv ("FWUPD_PIXART_RF_VERBOSE") != NULL) { + fu_common_dump_raw (G_LOG_DOMAIN, "SetFeature", + req->data, req->len); + } + return fu_udev_device_ioctl (FU_UDEV_DEVICE (self), + HIDIOCSFEATURE(req->len), (guint8 *) req->data, + NULL, error); +#else + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + " not available"); + return FALSE; +#endif +} + +static gboolean +fu_pxi_device_get_feature (FuPxiDevice *self, guint8 *buf, guint bufsz, GError **error) +{ +#ifdef HAVE_HIDRAW_H + if (!fu_udev_device_ioctl (FU_UDEV_DEVICE (self), + HIDIOCGFEATURE(bufsz), buf, + NULL, error)) { + return FALSE; + } + if (g_getenv ("FWUPD_PIXART_RF_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "GetFeature", buf, bufsz); + + /* prepend the report-id and cmd for versions of bluez that do not have + * https://github.com/bluez/bluez/commit/35a2c50437cca4d26ac6537ce3a964bb509c9b62 */ + if (bufsz > 2 && buf[0] != PXI_HID_DEV_OTA_FEATURE_REPORT_ID) { + g_debug ("doing fixup for old bluez version"); + memmove (buf + 2, buf, bufsz - 2); + buf[0] = PXI_HID_DEV_OTA_FEATURE_REPORT_ID; + buf[1] = 0x0; + } + + return TRUE; +#else + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + " not available"); + return FALSE; +#endif +} + +static guint16 +fu_pxi_device_calculate_checksum (const guint8 *buf, gsize bufsz) +{ + guint16 checksum = 0; + for (gsize idx = 0; idx < bufsz; idx++) + checksum += (guint16) buf[idx]; + return checksum; +} + +static gboolean +fu_pxi_device_search_hid_usage_page (guint8 *report_descriptor, gint size, + guint8 *usage_page, guint8 usage_page_sz) +{ + gint pos = 0; + + if (g_getenv ("FWUPD_PIXART_RF_VERBOSE") != NULL) { + fu_common_dump_raw (G_LOG_DOMAIN, "target usage_page", + usage_page, usage_page_sz); + } + + while (pos < size) { + /* HID info define by HID specification */ + guint8 item = report_descriptor[pos]; + guint8 report_size = item & 0x03; + guint8 report_tag = item & 0xF0; + guint8 usage_page_tmp[4] = {0x00}; + + report_size = (report_size == 3) ? 4 : report_size; + + if (report_tag != 0) { + pos += report_size + 1; + continue; + } + + memmove (usage_page, &report_descriptor[pos + 1], report_size); + if (memcmp (usage_page, usage_page_tmp, usage_page_sz) == 0) { + if (g_getenv ("FWUPD_PIXART_RF_VERBOSE") != NULL) { + g_debug ("hit item: %x ",item); + fu_common_dump_raw (G_LOG_DOMAIN, "usage_page", usage_page, report_size); + g_debug ("hit pos %d",pos); + } + return TRUE; /* finished processing */ + } + pos += report_size + 1; + } + + return FALSE ; /* finished processing */ +} + +static gboolean +fu_pxi_device_check_support_report_id (FuPxiDevice *self, + GError **error) +{ +#ifdef HAVE_HIDRAW_H + gint desc_size = 0; + g_autoptr(GByteArray) req = g_byte_array_new (); + + struct hidraw_report_descriptor rpt_desc; + + /* Get Report Descriptor Size */ + if (!fu_udev_device_ioctl (FU_UDEV_DEVICE (self), HIDIOCGRDESCSIZE, + (guint8*)&desc_size, NULL, error)) + return FALSE; + + rpt_desc.size = desc_size; + if (!fu_udev_device_ioctl (FU_UDEV_DEVICE (self), HIDIOCGRDESC, + (guint8*)&rpt_desc, + NULL, error)) + return FALSE; + fu_common_dump_raw (G_LOG_DOMAIN, "HID descriptor", + rpt_desc.value, rpt_desc.size); + + + /* check ota retransmit feature report usage page exist or not */ + fu_byte_array_append_uint16 (req, PXI_HID_DEV_OTA_RETRANSMIT_USAGE_PAGE, G_LITTLE_ENDIAN); + if (!fu_pxi_device_search_hid_usage_page (rpt_desc.value, rpt_desc.size, + req->data, req->len)) { + /* replace retransmit report id with feature report id, if retransmit report id not found */ + self->retransmit_id = PXI_HID_DEV_OTA_FEATURE_REPORT_ID; + } + return TRUE; + +#else + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + " not available"); + return FALSE +#endif +} + +static gboolean +fu_pxi_device_fw_ota_check_retransmit (FuPxiDevice *self, GError **error) +{ + g_autoptr(GByteArray) req = g_byte_array_new (); + + /* write fw ota retransmit command to reset the ota state */ + fu_byte_array_append_uint8 (req, self->retransmit_id); + fu_byte_array_append_uint8 (req, FU_PXI_DEVICE_CMD_FW_OTA_RETRANSMIT); + return fu_pxi_device_set_feature (self, req, error); +} + +static gboolean +fu_pxi_device_check_support_resume (FuPxiDevice *self, + FuFirmware *firmware, + GError **error) +{ + g_autoptr(GBytes) fw = NULL; + g_autoptr(GPtrArray) chunks = NULL; + guint16 checksum_tmp = 0x0; + + /* get the default image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + + /* check offset is invalid or not */ + chunks = fu_chunk_array_new_from_bytes (fw, 0x0, 0x0, FU_PXI_DEVICE_OBJECT_SIZE_MAX); + if (self->offset > chunks->len) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "offset from device is invalid: " + "got 0x%x, current maximum 0x%x", + self->offset, + chunks->len); + return FALSE; + } + + /* calculate device current checksum */ + for (guint i = 0; i < self->offset; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + checksum_tmp += fu_pxi_device_calculate_checksum (fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk)); + } + + /* check current file is different with previous fw bin or not */ + if (self->checksum != checksum_tmp) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "checksum is different from previous fw: " + "got 0x%04x, expected 0x%04x", + self->checksum, + checksum_tmp); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_pxi_device_wait_notify (FuPxiDevice *self, + goffset port, + guint8 *status, + guint16 *checksum, + GError **error) +{ + g_autoptr(GTimer) timer = g_timer_new (); + guint8 res[FU_PXI_DEVICE_OTA_BUF_SZ] = { 0 }; + guint8 cmd_status = 0x0; + + /* skip the wrong report id ,and keep polling until result is correct */ + while (g_timer_elapsed (timer, NULL) * 1000.f < FU_PXI_DEVICE_NOTIFY_TIMEOUT_MS) { + if (!fu_udev_device_pread_full (FU_UDEV_DEVICE (self), + port, res, (FU_PXI_DEVICE_NOTTFY_RET_LEN + 1) - port, + error)) + return FALSE; + if (res[0] == PXI_HID_DEV_OTA_INPUT_REPORT_ID) + break; + } + + /* timeout */ + if (res[0] != PXI_HID_DEV_OTA_INPUT_REPORT_ID) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Timed-out waiting for HID report"); + return FALSE; + } + /* get the opcode if status is not null */ + if (status != NULL) { + guint8 status_tmp = 0x0; + if (!fu_common_read_uint8_safe (res, sizeof(res), 0x1, + &status_tmp, error)) + return FALSE; + /* need check command result if command is fw upgrade */ + if (status_tmp == FU_PXI_DEVICE_CMD_FW_UPGRADE) { + if (!fu_common_read_uint8_safe (res, sizeof(res), 0x2, + &cmd_status, error)) + return FALSE; + if (cmd_status != ERR_COMMAND_SUCCESS) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "cmd status was 0x%02x", + cmd_status); + return FALSE; + } + } + + /* propagate */ + *status = status_tmp; + } + if (checksum != NULL) { + if (!fu_common_read_uint16_safe (res, sizeof(res), 0x3, + checksum, G_LITTLE_ENDIAN, error)) + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_pxi_device_fw_object_create (FuPxiDevice *self, FuChunk *chk, GError **error) +{ + guint8 opcode = 0; + g_autoptr(GByteArray) req = g_byte_array_new (); + + /* request */ + fu_byte_array_append_uint8 (req, PXI_HID_DEV_OTA_FEATURE_REPORT_ID); + fu_byte_array_append_uint8 (req, FU_PXI_DEVICE_CMD_FW_OBJECT_CREATE); + fu_byte_array_append_uint32 (req, fu_chunk_get_address (chk), G_LITTLE_ENDIAN); + fu_byte_array_append_uint32 (req, fu_chunk_get_data_sz (chk), G_LITTLE_ENDIAN); + if (!fu_pxi_device_set_feature (self, req, error)) + return FALSE; + + /* check object create success or not */ + if (!fu_pxi_device_wait_notify (self, 0x0, &opcode, NULL, error)) + return FALSE; + if (opcode != FU_PXI_DEVICE_CMD_FW_OBJECT_CREATE) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "FwObjectCreate opcode got 0x%02x, expected 0x%02x", + opcode, + FU_PXI_DEVICE_CMD_FW_OBJECT_CREATE); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_pxi_device_write_payload (FuPxiDevice *self, FuChunk *chk, GError **error) +{ + g_autoptr(GByteArray) req = g_byte_array_new (); + fu_byte_array_append_uint8 (req, PXI_HID_DEV_OTA_FEATURE_REPORT_ID); + g_byte_array_append (req, fu_chunk_get_data (chk), fu_chunk_get_data_sz (chk)); + return fu_pxi_device_set_feature (self, req, error); +} + +static gboolean +fu_pxi_device_write_chunk (FuPxiDevice *self, FuChunk *chk, GError **error) +{ + guint32 prn = 0; + guint16 checksum; + guint16 checksum_device = 0; + g_autoptr(GPtrArray) chunks = NULL; + + /* send create fw object command */ + if (!fu_pxi_device_fw_object_create (self, chk, error)) + return FALSE; + + /* write payload */ + chunks = fu_chunk_array_new (fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk), + fu_chunk_get_address (chk), + 0x0, self->mtu_size); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk2 = g_ptr_array_index (chunks, i); + if (!fu_pxi_device_write_payload (self, chk2, error)) + return FALSE; + prn++; + /* wait notify from device when PRN over threshold write or + * offset reach max object sz or write offset reach fw length */ + if (prn >= self->prn_threshold || i == chunks->len - 1) { + guint8 opcode = 0; + if (!fu_pxi_device_wait_notify (self, 0x0, + &opcode, + &checksum_device, + error)) + return FALSE; + if (opcode != FU_PXI_DEVICE_CMD_FW_WRITE) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "FwWrite opcode invalid 0x%02x", + opcode); + return FALSE; + } + prn = 0; + } + } + + /* the last chunk */ + checksum = fu_pxi_device_calculate_checksum (fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk)); + self->checksum += checksum; + if (checksum_device != self->checksum ) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "checksum fail, got 0x%04x, expected 0x%04x", + checksum_device, + checksum); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_pxi_device_reset (FuPxiDevice *self, GError **error) +{ + g_autoptr(GByteArray) req = g_byte_array_new (); + fu_byte_array_append_uint8 (req, PXI_HID_DEV_OTA_FEATURE_REPORT_ID); + fu_byte_array_append_uint8 (req, FU_PXI_DEVICE_CMD_FW_MCU_RESET); /* OTA reset command */ + fu_byte_array_append_uint8 (req, OTA_RESET); /* OTA reset reason */ + fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_RESTART); + + if (!fu_pxi_device_set_feature (self, req, error)) { + g_prefix_error (error, "failed to reset: "); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_pxi_device_fw_ota_init (FuPxiDevice *self, GError **error) +{ + + g_autoptr(GByteArray) req = g_byte_array_new (); + + /* write fw ota init command */ + fu_byte_array_append_uint8 (req, PXI_HID_DEV_OTA_FEATURE_REPORT_ID); + fu_byte_array_append_uint8 (req, FU_PXI_DEVICE_CMD_FW_OTA_INIT); + return fu_pxi_device_set_feature (self, req, error); +} + +static gboolean +fu_pxi_device_fw_ota_init_new (FuPxiDevice *self, gsize bufsz, GError **error) +{ + guint8 res[FU_PXI_DEVICE_OTA_BUF_SZ] = { 0x0 }; + guint8 fw_version[10] = { 0x0 }; + g_autoptr(GByteArray) req = g_byte_array_new (); + + /* write fw ota init new command */ + fu_byte_array_append_uint8 (req, PXI_HID_DEV_OTA_FEATURE_REPORT_ID); + fu_byte_array_append_uint8 (req, FU_PXI_DEVICE_CMD_FW_OTA_INIT_NEW); + fu_byte_array_append_uint32 (req, bufsz, G_LITTLE_ENDIAN); + fu_byte_array_append_uint8 (req, 0x0); /* OTA setting */ + g_byte_array_append (req, fw_version, sizeof(fw_version)); + if (!fu_pxi_device_set_feature (self, req, error)) + return FALSE; + + /* delay for BLE device read command */ + g_usleep (10 * 1000); + + /* read fw ota init new command */ + res[0] = PXI_HID_DEV_OTA_FEATURE_REPORT_ID; + res[1] = FU_PXI_DEVICE_CMD_FW_OTA_INIT_NEW; + if (!fu_pxi_device_get_feature (self, res, sizeof(res), error)) + return FALSE; + + /* shared state */ + if (!fu_common_read_uint8_safe (res, sizeof(res), 0x5, + &self->status, error)) + return FALSE; + if (!fu_common_read_uint8_safe (res, sizeof(res), 0x6, + &self->new_flow, error)) + return FALSE; + if (!fu_common_read_uint16_safe (res, sizeof(res), 0x7, + &self->offset, G_LITTLE_ENDIAN, error)) + return FALSE; + if (!fu_common_read_uint16_safe (res, sizeof(res), 0x9, + &self->checksum, G_LITTLE_ENDIAN, error)) + return FALSE; + if (!fu_common_read_uint32_safe (res, sizeof(res), 0xb, + &self->max_object_size, G_LITTLE_ENDIAN, error)) + return FALSE; + if (!fu_common_read_uint16_safe (res, sizeof(res), 0xf, + &self->mtu_size, G_LITTLE_ENDIAN, error)) + return FALSE; + if (!fu_common_read_uint16_safe (res, sizeof(res), 0x11, + &self->prn_threshold, G_LITTLE_ENDIAN, error)) + return FALSE; + if (!fu_common_read_uint8_safe (res, sizeof(res), 0x13, + &self->spec_check_result, error)) + return FALSE; + + /* sanity check */ + if (self->spec_check_result != OTA_SPEC_CHECK_OK) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "FwInitNew spec check fail: %s [0x%02x]", + fu_pxi_device_spec_check_result_to_string (self->spec_check_result), + self->spec_check_result); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_pxi_device_fw_upgrade (FuPxiDevice *self, FuFirmware *firmware, GError **error) +{ + const gchar *version; + const guint8 *buf; + gsize bufsz = 0; + guint8 fw_version[5] = { 0x0 }; + guint8 opcode = 0; + guint16 checksum; + g_autoptr(GBytes) fw = NULL; + g_autoptr(GByteArray) req = g_byte_array_new (); + + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + buf = g_bytes_get_data (fw, &bufsz); + checksum = fu_pxi_device_calculate_checksum (buf, bufsz); + fu_byte_array_append_uint8 (req, PXI_HID_DEV_OTA_FEATURE_REPORT_ID); + fu_byte_array_append_uint8 (req, FU_PXI_DEVICE_CMD_FW_UPGRADE); + fu_byte_array_append_uint32 (req, bufsz, G_LITTLE_ENDIAN); + fu_byte_array_append_uint16 (req, checksum, G_LITTLE_ENDIAN); + version = fu_firmware_get_version (firmware); + if (!fu_memcpy_safe (fw_version, sizeof(fw_version), 0x0, /* dst */ + (guint8 *) version, strlen (version), 0x0, /* src */ + strlen (version), error)) + return FALSE; + g_byte_array_append (req, fw_version, sizeof(fw_version)); + + /* send fw upgrade command */ + fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_VERIFY); + if (!fu_pxi_device_set_feature (self, req, error)) + return FALSE; + + if (g_getenv ("FWUPD_PIXART_RF_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "fw upgrade", req->data, req->len); + + /* wait fw upgrade command result */ + if (!fu_pxi_device_wait_notify (self, 0x1, &opcode, NULL, error)) { + g_prefix_error (error, + "FwUpgrade command fail, " + "fw-checksum: 0x%04x fw-size: %" G_GSIZE_FORMAT ": ", + checksum, + bufsz); + return FALSE; + } + if (opcode != FU_PXI_DEVICE_CMD_FW_UPGRADE) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "FwUpgrade opcode invalid 0x%02x", + opcode); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_pxi_device_write_firmware (FuDevice *device, + FuFirmware *firmware, + FwupdInstallFlags flags, + GError **error) +{ + FuPxiDevice *self = FU_PXI_DEVICE (device); + g_autoptr(GBytes) fw = NULL; + g_autoptr(GPtrArray) chunks = NULL; + g_autoptr(GError) error_local = NULL; + + /* get the default image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + + + /* send fw ota retransmit command to reset status */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_BUSY); + if (!fu_pxi_device_fw_ota_check_retransmit (self, error)) { + g_prefix_error (error, "failed to OTA check retransmit: "); + return FALSE; + } + /* send fw ota init command */ + if (!fu_pxi_device_fw_ota_init (self, error)) + return FALSE; + if (!fu_pxi_device_fw_ota_init_new (self, g_bytes_get_size (fw), error)) + return FALSE; + + /* prepare write fw into device */ + chunks = fu_chunk_array_new_from_bytes (fw, 0x0, 0x0, FU_PXI_DEVICE_OBJECT_SIZE_MAX); + if (!fu_pxi_device_check_support_resume (self, firmware, &error_local)) { + g_debug ("do not resume: %s", error_local->message); + self->offset = 0; + self->checksum = 0; + } + + /* write fw into device */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + for (guint i = self->offset; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + if (!fu_pxi_device_write_chunk (self, chk, error)) + return FALSE; + fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len); + } + + /* fw upgrade command */ + if (!fu_pxi_device_fw_upgrade (self, firmware, error)) + return FALSE; + + /* send device reset command */ + return fu_pxi_device_reset (self, error); +} + +static gboolean +fu_pxi_device_fw_get_info (FuPxiDevice *self, GError **error) +{ + guint8 res[FU_PXI_DEVICE_OTA_BUF_SZ] = { 0x0 }; + guint8 opcode = 0x0; + guint16 checksum = 0; + g_autofree gchar *version_str = NULL; + g_autoptr(GByteArray) req = g_byte_array_new (); + + fu_byte_array_append_uint8 (req, PXI_HID_DEV_OTA_FEATURE_REPORT_ID); + fu_byte_array_append_uint8 (req, FU_PXI_DEVICE_CMD_FW_GET_INFO); + if (!fu_pxi_device_set_feature (self, req, error)) + return FALSE; + + + /* delay for BLE device read command */ + g_usleep (10 * 1000); + + res[0] = PXI_HID_DEV_OTA_FEATURE_REPORT_ID; + res[1] = FU_PXI_DEVICE_CMD_FW_GET_INFO; + + if (!fu_pxi_device_get_feature (self, res, FU_PXI_DEVICE_FW_INFO_RET_LEN + 3, error)) + return FALSE; + if (!fu_common_read_uint8_safe (res, sizeof(res), 0x4, &opcode, error)) + return FALSE; + if (opcode != FU_PXI_DEVICE_CMD_FW_GET_INFO) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "FwGetInfo opcode invalid 0x%02x", + opcode); + return FALSE; + } + /* set current version */ + version_str = g_strndup ((gchar *) res + 0x6, 5); + fu_device_set_version (FU_DEVICE (self), version_str); + + /* add current checksum */ + if (!fu_common_read_uint16_safe (res, sizeof(res), 0xb, + &checksum, G_LITTLE_ENDIAN, error)) + return FALSE; + + /* success */ + return TRUE; +} + +static gboolean +fu_pxi_device_get_model_info (FuPxiDevice *self, GError **error) +{ + guint8 res[FU_PXI_DEVICE_OTA_BUF_SZ] = { 0x0 }; + guint8 opcode = 0x0; + guint8 model_name[FU_PXI_DEVICE_MODEL_NAME_LEN] = { 0x0 }; + g_autoptr(GByteArray) req = g_byte_array_new (); + + fu_byte_array_append_uint8 (req, PXI_HID_DEV_OTA_FEATURE_REPORT_ID); + fu_byte_array_append_uint8 (req, FU_PXI_DEVICE_CMD_FW_OTA_GET_MODEL); + + if (!fu_pxi_device_set_feature (self, req, error)) + return FALSE; + + /* delay for BLE device read command */ + g_usleep (10 * 1000); + + res[0] = PXI_HID_DEV_OTA_FEATURE_REPORT_ID; + if (!fu_pxi_device_get_feature (self, res, sizeof(res), error)) + return FALSE; + if (!fu_common_read_uint8_safe (res, sizeof(res), 0x4, &opcode, error)) + return FALSE; + + /* old firmware */ + if (opcode != FU_PXI_DEVICE_CMD_FW_OTA_GET_MODEL) + return TRUE; + + /* get model from res */ + if (!fu_memcpy_safe (model_name, sizeof(model_name), 0x0, /* dst */ + (guint8 *) res, sizeof(res), 0x6, /* src */ + sizeof(model_name), error)) + return FALSE; + g_clear_pointer (&self->model_name, g_free); + if (model_name[0] != 0x00 && model_name[0] != 0xFF) + self->model_name = g_strndup ((gchar *) model_name, sizeof(model_name)); + + /* success */ + return TRUE; +} + +static gboolean +fu_pxi_device_probe (FuDevice *device, GError **error) +{ + /* set the logical and physical ID */ + if (!fu_udev_device_set_logical_id (FU_UDEV_DEVICE (device), "hid", error)) + return FALSE; + return fu_udev_device_set_physical_id (FU_UDEV_DEVICE (device), "hid", error); +} + +static gboolean +fu_pxi_device_setup_guid (FuPxiDevice *self, GError **error) +{ +#ifdef HAVE_HIDRAW_H + struct hidraw_devinfo hid_raw_info = { 0x0 }; + g_autofree gchar *devid = NULL; + g_autoptr(GString) dev_name = NULL; + + /* extra GUID with device name */ + if (!fu_pxi_device_get_raw_info (self, &hid_raw_info ,error)) + return FALSE; + dev_name = g_string_new (fu_device_get_name (FU_DEVICE (self))); + g_string_ascii_up (dev_name); + fu_common_string_replace (dev_name, " ", "_"); + devid = g_strdup_printf ("HIDRAW\\VEN_%04X&DEV_%04X&NAME_%s", + (guint) hid_raw_info.vendor, + (guint) hid_raw_info.product, + dev_name->str); + fu_device_add_instance_id (FU_DEVICE (self), devid); + + /* extra GUID with model name*/ + if (self->model_name != NULL) { + g_autofree gchar *devid2 = NULL; + g_autoptr(GString) model_name = NULL; + model_name = g_string_new (self->model_name); + g_string_ascii_up (model_name); + fu_common_string_replace (model_name, " ", "_"); + devid2 = g_strdup_printf ("HIDRAW\\VEN_%04X&DEV_%04X&MODEL_%s", + (guint) hid_raw_info.vendor, + (guint) hid_raw_info.product, + dev_name->str); + fu_device_add_instance_id (FU_DEVICE (self), devid2); + } +#endif + return TRUE; +} + +static gboolean +fu_pxi_device_setup (FuDevice *device, GError **error) +{ + FuPxiDevice *self = FU_PXI_DEVICE (device); + + if (!fu_pxi_device_check_support_report_id (self, error)) { + g_prefix_error (error, "failed to check report id: "); + } + if (!fu_pxi_device_fw_ota_check_retransmit (self, error)) { + g_prefix_error (error, "failed to OTA check retransmit: "); + return FALSE; + } + if (!fu_pxi_device_fw_ota_init (self, error)) { + g_prefix_error (error, "failed to OTA init: "); + return FALSE; + } + if (!fu_pxi_device_fw_get_info (self, error)) { + g_prefix_error (error, "failed to get info: "); + return FALSE; + } + if (!fu_pxi_device_get_model_info (self ,error)) { + g_prefix_error (error, "failed to get model: "); + return FALSE; + } + if (!fu_pxi_device_setup_guid (self ,error)) { + g_prefix_error (error, "failed to setup GUID: "); + return FALSE; + } + + return TRUE; +} + +static void +fu_pxi_device_init (FuPxiDevice *self) +{ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_add_vendor_id (FU_DEVICE (self), "USB:0x093A"); + fu_device_add_protocol (FU_DEVICE (self), "com.pixart.rf"); + self->retransmit_id = PXI_HID_DEV_OTA_RETRANSMIT_REPORT_ID; +} + +static void +fu_pxi_device_finalize (GObject *object) +{ + FuPxiDevice *self = FU_PXI_DEVICE (object); + g_free (self->model_name); +} + +static void +fu_pxi_device_class_init (FuPxiDeviceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + object_class->finalize = fu_pxi_device_finalize; + klass_device->probe = fu_pxi_device_probe; + klass_device->setup = fu_pxi_device_setup; + klass_device->to_string = fu_pxi_device_to_string; + klass_device->write_firmware = fu_pxi_device_write_firmware; + klass_device->prepare_firmware = fu_pxi_device_prepare_firmware; +} diff -Nru fwupd-1.4.5/plugins/pixart-rf/fu-pxi-device.h fwupd-1.5.8/plugins/pixart-rf/fu-pxi-device.h --- fwupd-1.4.5/plugins/pixart-rf/fu-pxi-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/pixart-rf/fu-pxi-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2020 Jimmy Yu + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-udev-device.h" + +#define FU_TYPE_PXI_DEVICE (fu_pxi_device_get_type ()) + +G_DECLARE_FINAL_TYPE (FuPxiDevice, fu_pxi_device, FU, PXI_DEVICE, FuUdevDevice) diff -Nru fwupd-1.4.5/plugins/pixart-rf/fu-pxi-firmware.c fwupd-1.5.8/plugins/pixart-rf/fu-pxi-firmware.c --- fwupd-1.4.5/plugins/pixart-rf/fu-pxi-firmware.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/pixart-rf/fu-pxi-firmware.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2020 Jimmy Yu + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-common.h" +#include "fu-common-version.h" +#include "fu-pxi-firmware.h" + +#define PIXART_RF_FW_HEADER_SIZE 32 /* bytes */ +#define PIXART_RF_FW_HEADER_TAG_OFFSET 24 + +struct _FuPxiFirmware { + FuFirmware parent_instance; + gchar *model_name; +}; + +G_DEFINE_TYPE (FuPxiFirmware, fu_pxi_firmware, FU_TYPE_FIRMWARE) + +const gchar * +fu_pxi_firmware_get_model_name (FuPxiFirmware *self) +{ + g_return_val_if_fail (FU_IS_PXI_FIRMWARE (self), NULL); + return self->model_name; +} + +static void +fu_pxi_firmware_to_string (FuFirmware *firmware, guint idt, GString *str) +{ + FuPxiFirmware *self = FU_PXI_FIRMWARE (firmware); + fu_common_string_append_kv (str, idt, "ModelName", self->model_name); +} + +static gboolean +fu_pxi_firmware_parse (FuFirmware *firmware, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error) +{ + FuPxiFirmware *self = FU_PXI_FIRMWARE (firmware); + const guint8 *buf; + const guint8 tag[] = { + 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, + }; + gsize bufsz = 0; + guint32 version_raw = 0; + guint8 fw_header[PIXART_RF_FW_HEADER_SIZE]; + guint8 model_name[FU_PXI_DEVICE_MODEL_NAME_LEN] = { 0x0 }; + g_autofree gchar *version = NULL; + g_autoptr(FuFirmwareImage) img = fu_firmware_image_new (fw); + + /* get buf */ + buf = g_bytes_get_data (fw, &bufsz); + if (bufsz < sizeof(fw_header)) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "firmware invalid, too small!"); + return FALSE; + } + + /* get fw header from buf */ + if (!fu_memcpy_safe (fw_header, sizeof(fw_header), 0x0, + buf, bufsz, bufsz - sizeof(fw_header), + sizeof(fw_header), error)) { + g_prefix_error (error, "failed to read fw header: "); + return FALSE; + } + if (g_getenv ("FWUPD_PIXART_RF_VERBOSE") != NULL) { + fu_common_dump_raw (G_LOG_DOMAIN, "fw header", + fw_header, sizeof(fw_header)); + } + + /* check the tag from fw header is correct */ + for (guint32 i = 0x0; i < sizeof(tag); i++) { + guint8 tmp = 0; + if (!fu_common_read_uint8_safe (fw_header, sizeof(fw_header), + i + PIXART_RF_FW_HEADER_TAG_OFFSET, + &tmp, error)) + return FALSE; + if (tmp != tag[i]) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "Fw tag is incorrect"); + return FALSE; + } + } + + /* set fw version */ + version_raw = (((guint32) (fw_header[0] - '0')) << 16) + + (((guint32) (fw_header[2] - '0')) << 8) + + (guint32) (fw_header[4] - '0'); + fu_firmware_set_version_raw (firmware, version_raw); + version = fu_common_version_from_uint32 (version_raw, + FWUPD_VERSION_FORMAT_DELL_BIOS); + fu_firmware_set_version (firmware, version); + + /* set fw model name */ + if (!fu_memcpy_safe (model_name, sizeof(model_name), 0x0, + fw_header, sizeof(fw_header), 0x05, + sizeof(model_name), error)) { + g_prefix_error (error, "failed to get fw model name: "); + return FALSE; + } + self->model_name = g_strndup ((gchar *) model_name, sizeof(model_name)); + + /* success */ + fu_firmware_add_image (firmware, img); + return TRUE; +} + +static gboolean +fu_pxi_firmware_build (FuFirmware *firmware, XbNode *n, GError **error) +{ + FuPxiFirmware *self = FU_PXI_FIRMWARE (firmware); + const gchar *tmp; + + /* optional properties */ + tmp = xb_node_query_text (n, "model_name", NULL); + if (tmp != NULL) + self->model_name = g_strdup (tmp); + + /* success */ + return TRUE; +} + +static GBytes * +fu_pxi_firmware_write (FuFirmware *firmware, GError **error) +{ + FuPxiFirmware *self = FU_PXI_FIRMWARE (firmware); + guint8 fw_header[PIXART_RF_FW_HEADER_SIZE] = { 0x0 }; + guint64 version_raw = fu_firmware_get_version_raw (firmware); + g_autoptr(GByteArray) buf = NULL; + g_autoptr(GBytes) blob = NULL; + const guint8 tag[] = { + 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, + }; + + /* data first */ + blob = fu_firmware_get_image_default_bytes (firmware, error); + if (blob == NULL) + return NULL; + buf = g_byte_array_sized_new (g_bytes_get_size (blob) + sizeof (fw_header)); + g_byte_array_append (buf, + g_bytes_get_data (blob, NULL), + g_bytes_get_size (blob)); + + /* footer */ + if (!fu_memcpy_safe (fw_header, sizeof (fw_header), + PIXART_RF_FW_HEADER_TAG_OFFSET, /* dst */ + tag, sizeof(tag), 0x0, /* src */ + sizeof(tag), error)) + return NULL; + fw_header[0] = ((version_raw >> 16) & 0xff) + '0'; + fw_header[1] = '.'; + fw_header[2] = ((version_raw >> 8) & 0xff) + '0'; + fw_header[3] = '.'; + fw_header[4] = ((version_raw >> 0) & 0xff) + '0'; + if (!g_ascii_isdigit (fw_header[0]) || + !g_ascii_isdigit (fw_header[2]) || + !g_ascii_isdigit (fw_header[4])) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "cannot write invalid version number 0x%x", + (guint) version_raw); + return NULL; + } + if (self->model_name != NULL) { + gsize model_namesz = MIN (strlen (self->model_name), + FU_PXI_DEVICE_MODEL_NAME_LEN); + if (!fu_memcpy_safe (fw_header, sizeof(fw_header), 0x05, /* dst */ + (const guint8 *) self->model_name, model_namesz, 0x0, /* src */ + model_namesz, error)) { + g_prefix_error (error, "failed to get fw model name: "); + return NULL; + } + } + + g_byte_array_append (buf, fw_header, sizeof(fw_header)); + return g_byte_array_free_to_bytes (g_steal_pointer (&buf)); +} + +static void +fu_pxi_firmware_init (FuPxiFirmware *self) +{ +} + +static void +fu_pxi_firmware_finalize (GObject *object) +{ + FuPxiFirmware *self = FU_PXI_FIRMWARE (object); + g_free (self->model_name); + G_OBJECT_CLASS (fu_pxi_firmware_parent_class)->finalize (object); +} + +static void +fu_pxi_firmware_class_init (FuPxiFirmwareClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); + object_class->finalize = fu_pxi_firmware_finalize; + klass_firmware->parse = fu_pxi_firmware_parse; + klass_firmware->build = fu_pxi_firmware_build; + klass_firmware->write = fu_pxi_firmware_write; + klass_firmware->to_string = fu_pxi_firmware_to_string; +} + +FuFirmware * +fu_pxi_firmware_new (void) +{ + return FU_FIRMWARE (g_object_new (FU_TYPE_PXI_FIRMWARE, NULL)); +} diff -Nru fwupd-1.4.5/plugins/pixart-rf/fu-pxi-firmware.h fwupd-1.5.8/plugins/pixart-rf/fu-pxi-firmware.h --- fwupd-1.4.5/plugins/pixart-rf/fu-pxi-firmware.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/pixart-rf/fu-pxi-firmware.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2020 Jimmy Yu + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-firmware.h" + +#define FU_PXI_DEVICE_MODEL_NAME_LEN 12 /* bytes */ + +#define FU_TYPE_PXI_FIRMWARE (fu_pxi_firmware_get_type ()) +G_DECLARE_FINAL_TYPE (FuPxiFirmware, fu_pxi_firmware, FU, PXI_FIRMWARE, FuFirmware) + +FuFirmware *fu_pxi_firmware_new (void); +const gchar *fu_pxi_firmware_get_model_name (FuPxiFirmware *self); diff -Nru fwupd-1.4.5/plugins/pixart-rf/meson.build fwupd-1.5.8/plugins/pixart-rf/meson.build --- fwupd-1.4.5/plugins/pixart-rf/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/pixart-rf/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,31 @@ +if host_machine.system() == 'linux' +cargs = ['-DG_LOG_DOMAIN="FuPluginPixartRf"'] + +install_data(['pixart-rf.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_pixart_rf', + fu_hash, + sources : [ + 'fu-plugin-pixart-rf.c', + 'fu-pxi-device.c', + 'fu-pxi-firmware.c', # fuzzing + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + c_args : cargs, + dependencies : [ + plugin_deps, + ], + link_with : [ + fwupd, + fwupdplugin, + ], +) +endif diff -Nru fwupd-1.4.5/plugins/pixart-rf/pixart-rf.quirk fwupd-1.5.8/plugins/pixart-rf/pixart-rf.quirk --- fwupd-1.4.5/plugins/pixart-rf/pixart-rf.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/pixart-rf/pixart-rf.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,47 @@ +# Pixart 2801 +[HIDRAW\VEN_093A&DEV_2801] +Plugin = pixart_rf + +# Pixart 2860 +[HIDRAW\VEN_093A&DEV_2860] +Plugin = pixart_rf + +# Pixart 2802 +[HIDRAW\VEN_093A&DEV_2802] +Plugin = pixart_rf + +# Pixart 2822 +[HIDRAW\VEN_093A&DEV_2822] +Plugin = pixart_rf + +# Pixart 2861 +[HIDRAW\VEN_093A&DEV_2861] +Plugin = pixart_rf + +# Pixart 2862 +[HIDRAW\VEN_093A&DEV_2862] +Plugin = pixart_rf + +# Pixart 2452 +[HIDRAW\VEN_093A&DEV_2452] +Plugin = pixart_rf + +# Primax Mouse +[HIDRAW\VEN_0461&DEV_4EEF] +Plugin = pixart_rf + +# Primax US KB +[HIDRAW\VEN_0461&DEV_4EEE] +Plugin = pixart_rf + +# Primax UK KB +[HIDRAW\VEN_0461&DEV_4EF4] +Plugin = pixart_rf + +# Primax JP KB +[HIDRAW\VEN_0461&DEV_4EF5] +Plugin = pixart_rf + +# Chicony Cheetos +[HIDRAW\VEN_04F2&DEV_2051] +Plugin = pixart_rf diff -Nru fwupd-1.4.5/plugins/pixart-rf/README.md fwupd-1.5.8/plugins/pixart-rf/README.md --- fwupd-1.4.5/plugins/pixart-rf/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/pixart-rf/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,46 @@ +PixArt RF Devices Support +========================= + +Introduction +------------ + +This plugin allows the user to update any supported Pixart RF Device using a +custom HID-based OTA protocol + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecified binary file format. + +This plugin supports the following protocol ID: + + * com.pixart.rf + +GUID Generation +--------------- + +These devices use the standard HIDRAW DeviceInstanceId values for both +Pixart Imaging, Inc and Primax Electronics, Ltd, e.g. + + * `HIDRAW\VEN_093A&DEV_2801` + * `HIDRAW\VEN_0461&DEV_4EEF` + * `HIDRAW\VEN_0461&DEV_4EEF&NAME_${NAME}` + * `HIDRAW\VEN_0461&DEV_4EEF&MODEL_${MODEL_NAME}` + +Additionaly, a custom GUID values including the name is used, e.g. + +Update Behavior +--------------- + +The firmware is deployed when the device is in normal runtime mode, and the +device will reset when the new firmware has been written. + +Vendor ID Security +------------------ + +The vendor ID is set from the USB vendor, in this instance set to `USB:0x093A` + +External interface access +------------------------- +This plugin requires ioctl `HIDIOCSFEATURE` and `HIDIOCGFEATURE` access. diff -Nru fwupd-1.4.5/plugins/platform-integrity/fu-plugin-platform-integrity.c fwupd-1.5.8/plugins/platform-integrity/fu-plugin-platform-integrity.c --- fwupd-1.4.5/plugins/platform-integrity/fu-plugin-platform-integrity.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/platform-integrity/fu-plugin-platform-integrity.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + + +#include "fu-plugin-vfuncs.h" + +struct FuPluginData { + gchar *sysfs_path; +}; + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_udev_subsystem (plugin, "platform-integrity"); +} + +void +fu_plugin_destroy (FuPlugin *plugin) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_free (priv->sysfs_path); +} + +gboolean +fu_plugin_backend_device_added (FuPlugin *plugin, FuDevice *device, GError **error) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + + /* interesting device? */ + if (!FU_IS_UDEV_DEVICE (device)) + return TRUE; + if (g_strcmp0 (fu_udev_device_get_subsystem (FU_UDEV_DEVICE (device)), "platform-integrity") != 0) + return TRUE; + + /* we only care about the first instance */ + if (priv->sysfs_path != NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "only one platform-integrity device supported; already using %s", + priv->sysfs_path); + return FALSE; + } + + /* success */ + priv->sysfs_path = g_strdup (fu_udev_device_get_sysfs_path (FU_UDEV_DEVICE (device))); + return TRUE; +} + +static void +fu_plugin_add_security_attr_bioswe (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + gsize bufsz = 0; + g_autofree gchar *buf = NULL; + g_autofree gchar *fn = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GError) error_local = NULL; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SPI_BIOSWE); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_add_obsolete (attr, "pci_bcr"); + fu_security_attrs_append (attrs, attr); + + /* load file */ + fn = g_build_filename (priv->sysfs_path, "bioswe", NULL); + if (!g_file_get_contents (fn, &buf, &bufsz, &error_local)) { + g_warning ("could not open %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); + return; + } + if (g_strcmp0 (buf, "0\n") != 0) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); +} + +static void +fu_plugin_add_security_attr_ble (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + gsize bufsz = 0; + g_autofree gchar *buf = NULL; + g_autofree gchar *fn = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GError) error_local = NULL; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SPI_BLE); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_add_obsolete (attr, "pci_bcr"); + fu_security_attrs_append (attrs, attr); + + /* load file */ + fn = g_build_filename (priv->sysfs_path, "biosle", NULL); + if (!g_file_get_contents (fn, &buf, &bufsz, &error_local)) { + g_warning ("could not open %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); + return; + } + if (g_strcmp0 (buf, "1\n") != 0) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); +} + +static void +fu_plugin_add_security_attr_smm_bwp (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + gsize bufsz = 0; + g_autofree gchar *buf = NULL; + g_autofree gchar *fn = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GError) error_local = NULL; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_SPI_SMM_BWP); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_add_obsolete (attr, "pci_bcr"); + fu_security_attrs_append (attrs, attr); + + /* load file */ + fn = g_build_filename (priv->sysfs_path, "smm_bioswp", NULL); + if (!g_file_get_contents (fn, &buf, &bufsz, &error_local)) { + g_warning ("could not open %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); + return; + } + if (g_strcmp0 (buf, "1\n") != 0) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_LOCKED); +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + + /* only when the kernel module is available */ + if (priv->sysfs_path == NULL) + return; + + /* look for the three files in sysfs */ + fu_plugin_add_security_attr_bioswe (plugin, attrs); + fu_plugin_add_security_attr_ble (plugin, attrs); + fu_plugin_add_security_attr_smm_bwp (plugin, attrs); +} diff -Nru fwupd-1.4.5/plugins/platform-integrity/fwupd-platform-integrity.conf fwupd-1.5.8/plugins/platform-integrity/fwupd-platform-integrity.conf --- fwupd-1.4.5/plugins/platform-integrity/fwupd-platform-integrity.conf 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/platform-integrity/fwupd-platform-integrity.conf 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +platform-integrity diff -Nru fwupd-1.4.5/plugins/platform-integrity/meson.build fwupd-1.5.8/plugins/platform-integrity/meson.build --- fwupd-1.4.5/plugins/platform-integrity/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/platform-integrity/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,37 @@ +if get_option('plugin_platform_integrity') +cargs = ['-DG_LOG_DOMAIN="FuPluginPlatformIntegrity"'] + +install_data([ + 'platform-integrity.quirk', + ], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +if get_option('systemd') +install_data(['fwupd-platform-integrity.conf'], + install_dir: systemd_modules_load_dir, +) +endif + +shared_module('fu_plugin_platform_integrity', + fu_hash, + sources : [ + 'fu-plugin-platform-integrity.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) +endif diff -Nru fwupd-1.4.5/plugins/platform-integrity/platform-integrity.quirk fwupd-1.5.8/plugins/platform-integrity/platform-integrity.quirk --- fwupd-1.4.5/plugins/platform-integrity/platform-integrity.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/platform-integrity/platform-integrity.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,3 @@ +# match all devices with this udev subsystem +[PLATFORM-INTEGRITY] +Plugin = platform_integrity diff -Nru fwupd-1.4.5/plugins/platform-integrity/README.md fwupd-1.5.8/plugins/platform-integrity/README.md --- fwupd-1.4.5/plugins/platform-integrity/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/platform-integrity/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,12 @@ +Platform Integrity +================== + +Introduction +------------ + +This plugin checks if the system SPI chip is locked. The result will be stored +in an security attribute for HSI. + +External interface access +------------------------- +This plugin requires read access to `/sys/class/platform-integrity` diff -Nru fwupd-1.4.5/plugins/redfish/fu-plugin-redfish.c fwupd-1.5.8/plugins/redfish/fu-plugin-redfish.c --- fwupd-1.4.5/plugins/redfish/fu-plugin-redfish.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/redfish/fu-plugin-redfish.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -7,7 +7,6 @@ #include "config.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #include "fu-redfish-client.h" #include "fu-redfish-common.h" diff -Nru fwupd-1.4.5/plugins/redfish/fu-redfish-client.c fwupd-1.5.8/plugins/redfish/fu-redfish-client.c --- fwupd-1.4.5/plugins/redfish/fu-redfish-client.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/redfish/fu-redfish-client.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -7,13 +7,14 @@ #include "config.h" #include -#include +#include #include #include "fwupd-error.h" #include "fwupd-enums.h" #include "fu-device.h" +#include "fu-efivar.h" #include "fu-redfish-client.h" #include "fu-redfish-common.h" @@ -21,14 +22,11 @@ struct _FuRedfishClient { GObject parent_instance; - SoupSession *session; + CURL *curl; gchar *hostname; guint port; - gchar *username; - gchar *password; gchar *update_uri_path; gchar *push_uri_path; - gboolean auth_created; gboolean use_https; gboolean cacheck; GPtrArray *devices; @@ -36,62 +34,88 @@ G_DEFINE_TYPE (FuRedfishClient, fu_redfish_client, G_TYPE_OBJECT) -static void -fu_redfish_client_set_auth (FuRedfishClient *self, SoupURI *uri, - SoupMessage *msg) -{ - if ((self->username != NULL && self->password != NULL) && - self->auth_created == FALSE) { - /* - * Some redfish implementations miss WWW-Authenticate - * header for a 401 response, and SoupAuthManager couldn't - * generate SoupAuth accordingly. Since DSP0266 makes - * Basic Authorization a requirement for redfish, it shall be - * safe to use Basic Auth for all redfish implementations. - */ - SoupAuthManager *manager = SOUP_AUTH_MANAGER (soup_session_get_feature (self->session, SOUP_TYPE_AUTH_MANAGER)); - g_autoptr(SoupAuth) auth = soup_auth_new (SOUP_TYPE_AUTH_BASIC, - msg, "Basic"); - soup_auth_authenticate (auth, self->username, self->password); - soup_auth_manager_use_auth (manager, uri, auth); - self->auth_created = TRUE; - } +#ifdef HAVE_LIBCURL_7_62_0 +typedef gchar curlptr; +G_DEFINE_AUTOPTR_CLEANUP_FUNC(curlptr, curl_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(CURLU, curl_url_cleanup) +#endif + +static size_t +fu_redfish_client_fetch_data_cb (char *ptr, size_t size, size_t nmemb, void *userdata) +{ + GByteArray *buf = (GByteArray *) userdata; + gsize realsize = size * nmemb; + g_byte_array_append (buf, (const guint8 *) ptr, realsize); + return realsize; } static GBytes * fu_redfish_client_fetch_data (FuRedfishClient *self, const gchar *uri_path, GError **error) { - guint status_code; - g_autoptr(SoupMessage) msg = NULL; - g_autoptr(SoupURI) uri = NULL; + CURLcode res; + g_autofree gchar *port = g_strdup_printf ("%u", self->port); + g_autoptr(GByteArray) buf = g_byte_array_new (); +#ifdef HAVE_LIBCURL_7_62_0 + g_autoptr(CURLU) uri = NULL; +#else + g_autofree gchar *uri = NULL; +#endif /* create URI */ - uri = soup_uri_new (NULL); - soup_uri_set_scheme (uri, self->use_https ? "https" : "http"); - soup_uri_set_path (uri, uri_path); - soup_uri_set_host (uri, self->hostname); - soup_uri_set_port (uri, self->port); - msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri); - if (msg == NULL) { - g_autofree gchar *tmp = soup_uri_to_string (uri, FALSE); +#ifdef HAVE_LIBCURL_7_62_0 + uri = curl_url (); + curl_url_set (uri, CURLU_DEFAULT_SCHEME, self->use_https ? "https" : "http", 0); + curl_url_set (uri, CURLUPART_PATH, uri_path, 0); + curl_url_set (uri, CURLUPART_HOST, self->hostname, 0); + curl_url_set (uri, CURLUPART_PORT, port, 0); + if (curl_easy_setopt (self->curl, CURLOPT_CURLU, uri) != CURLE_OK) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "failed to create message for URI"); + return NULL; + } +#else + uri = g_strdup_printf ("%s://%s:%s%s", + self->use_https ? "https" : "http", + self->hostname, + port, + uri_path); + if (curl_easy_setopt (self->curl, CURLOPT_URL, uri) != CURLE_OK) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "failed to create message for URI"); + return NULL; + } +#endif + curl_easy_setopt (self->curl, CURLOPT_WRITEFUNCTION, fu_redfish_client_fetch_data_cb); + curl_easy_setopt (self->curl, CURLOPT_WRITEDATA, buf); + res = curl_easy_perform (self->curl); + if (res != CURLE_OK) { + glong status_code = 0; +#ifdef HAVE_LIBCURL_7_62_0 + g_autoptr(curlptr) uri_str = NULL; +#endif + curl_easy_getinfo (self->curl, CURLINFO_RESPONSE_CODE, &status_code); +#ifdef HAVE_LIBCURL_7_62_0 + curl_url_get (uri, CURLUPART_URL, &uri_str, 0); g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "failed to create message for URI %s", tmp); - return NULL; - } - fu_redfish_client_set_auth (self, uri, msg); - status_code = soup_session_send_message (self->session, msg); - if (status_code != SOUP_STATUS_OK) { - g_autofree gchar *tmp = soup_uri_to_string (uri, FALSE); + "failed to download %s: %s", + uri_str, curl_easy_strerror (res)); +#else g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "failed to download %s: %s", - tmp, soup_status_get_phrase (status_code)); + uri, curl_easy_strerror (res)); +#endif return NULL; } - return g_bytes_new (msg->response_body->data, msg->response_body->length); + + return g_byte_array_free_to_bytes (g_steal_pointer (&buf)); } static gboolean @@ -123,7 +147,7 @@ id = g_strdup_printf ("Redfish-Inventory-%s", json_object_get_string_member (member, "Id")); fu_device_set_id (dev, id); - fu_device_set_protocol (dev, "org.dmtf.redfish"); + fu_device_add_protocol (dev, "org.dmtf.redfish"); fu_device_add_guid (dev, guid); if (json_object_has_member (member, "Name")) @@ -361,9 +385,9 @@ g_autoptr(GBytes) userpass = NULL; /* get the uint32 specifying if there are EFI variables set */ - indications = fu_redfish_common_get_evivar_raw (REDFISH_EFI_INFORMATION_GUID, - REDFISH_EFI_INFORMATION_INDICATIONS, - error); + indications = fu_efivar_get_data_bytes (REDFISH_EFI_INFORMATION_GUID, + REDFISH_EFI_INFORMATION_INDICATIONS, + NULL, error); if (indications == NULL) return FALSE; if (g_bytes_get_size (indications) != 4) { @@ -385,9 +409,9 @@ } /* read the correct EFI var for runtime */ - userpass = fu_redfish_common_get_evivar_raw (REDFISH_EFI_INFORMATION_GUID, - REDFISH_EFI_INFORMATION_OS_CREDENTIALS, - error); + userpass = fu_efivar_get_data_bytes (REDFISH_EFI_INFORMATION_GUID, + REDFISH_EFI_INFORMATION_OS_CREDENTIALS, + NULL, error); if (userpass == NULL) return FALSE; @@ -568,19 +592,23 @@ return TRUE; } +G_DEFINE_AUTOPTR_CLEANUP_FUNC(curl_mime, curl_mime_free) + gboolean fu_redfish_client_update (FuRedfishClient *self, FuDevice *device, GBytes *blob_fw, GError **error) { + CURLcode res; FwupdRelease *release; + curl_mimepart *part; g_autofree gchar *filename = NULL; - - guint status_code; - g_autoptr(SoupMessage) msg = NULL; - g_autoptr(SoupURI) uri = NULL; - g_autoptr(SoupMultipart) multipart = NULL; - g_autoptr(SoupBuffer) buffer = NULL; - g_autofree gchar *uri_str = NULL; + g_autofree gchar *port = g_strdup_printf ("%u", self->port); +#ifdef HAVE_LIBCURL_7_62_0 + g_autoptr(CURLU) uri = curl_url (); +#else + g_autofree gchar *uri = NULL; +#endif + g_autoptr(curl_mime) mime = curl_mime_init (self->curl); /* Get the update version */ release = fwupd_device_get_release_default (FWUPD_DEVICE (device)); @@ -594,39 +622,63 @@ } /* create URI */ - uri = soup_uri_new (NULL); - soup_uri_set_scheme (uri, self->use_https ? "https" : "http"); - soup_uri_set_path (uri, self->push_uri_path); - soup_uri_set_host (uri, self->hostname); - soup_uri_set_port (uri, self->port); - uri_str = soup_uri_to_string (uri, FALSE); +#ifdef HAVE_LIBCURL_7_62_0 + curl_url_set (uri, CURLU_DEFAULT_SCHEME, self->use_https ? "https" : "http", 0); + curl_url_set (uri, CURLUPART_PATH, self->push_uri_path, 0); + curl_url_set (uri, CURLUPART_HOST, self->hostname, 0); + curl_url_set (uri, CURLUPART_PORT, port, 0); + if (curl_easy_setopt (self->curl, CURLOPT_CURLU, uri) != CURLE_OK) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "failed to create message for URI"); + return FALSE; + } +#else + uri = g_strdup_printf ("%s://%s:%s%s", + self->use_https ? "https" : "http", + self->hostname, + port, + self->push_uri_path); + if (curl_easy_setopt (self->curl, CURLOPT_URL, uri) != CURLE_OK) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "failed to create message for URI"); + return FALSE; + } +#endif /* Create the multipart request */ - multipart = soup_multipart_new (SOUP_FORM_MIME_TYPE_MULTIPART); - buffer = soup_buffer_new (SOUP_MEMORY_COPY, - g_bytes_get_data (blob_fw, NULL), - g_bytes_get_size (blob_fw)); - soup_multipart_append_form_file (multipart, filename, filename, - "application/octet-stream", - buffer); - msg = soup_form_request_new_from_multipart (uri_str, multipart); - if (msg == NULL) { + curl_easy_setopt (self->curl, CURLOPT_MIMEPOST, mime); + part = curl_mime_addpart (mime); + curl_mime_data (part, g_bytes_get_data (blob_fw, NULL), g_bytes_get_size (blob_fw)); + curl_mime_type (part, "application/octet-stream"); + res = curl_easy_perform (self->curl); + if (res != CURLE_OK) { + glong status_code = 0; +#ifdef HAVE_LIBCURL_7_62_0 + g_autoptr(curlptr) uri_str = NULL; +#endif + curl_easy_getinfo (self->curl, CURLINFO_RESPONSE_CODE, &status_code); +#ifdef HAVE_LIBCURL_7_62_0 + curl_url_get (uri, CURLUPART_URL, &uri_str, 0); g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "failed to create message for URI %s", uri_str); + "failed to upload %s to %s: %s", + filename, uri_str, + curl_easy_strerror (res)); return FALSE; - } - fu_redfish_client_set_auth (self, uri, msg); - status_code = soup_session_send_message (self->session, msg); - if (status_code != SOUP_STATUS_OK) { +#else g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "failed to upload %s to %s: %s", - filename, uri_str, - soup_status_get_phrase (status_code)); + filename, uri, + curl_easy_strerror (res)); return FALSE; +#endif } return TRUE; @@ -661,24 +713,12 @@ return FALSE; } - /* create the soup session */ + /* setup networking */ user_agent = g_strdup_printf ("%s/%s", PACKAGE_NAME, PACKAGE_VERSION); - self->session = soup_session_new_with_options (SOUP_SESSION_USER_AGENT, user_agent, - SOUP_SESSION_TIMEOUT, 60, - NULL); - if (self->session == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "failed to setup networking"); - return FALSE; - } - - if (self->cacheck == FALSE) { - g_object_set (G_OBJECT (self->session), - SOUP_SESSION_SSL_STRICT, FALSE, - NULL); - } + curl_easy_setopt (self->curl, CURLOPT_USERAGENT , user_agent); + curl_easy_setopt (self->curl, CURLOPT_CONNECTTIMEOUT, 60L); + if (self->cacheck == FALSE) + curl_easy_setopt (self->curl, CURLOPT_SSL_VERIFYPEER , 0L); /* this is optional */ if (smbios_table != NULL) { @@ -699,10 +739,6 @@ g_debug ("Hostname: %s", self->hostname); if (self->port != 0) g_debug ("Port: %u", self->port); - if (self->username != NULL) - g_debug ("Username: %s", self->username); - if (self->password != NULL) - g_debug ("Password: %s", self->password); /* try to connect */ blob = fu_redfish_client_fetch_data (self, "/redfish/v1/", error); @@ -799,28 +835,24 @@ void fu_redfish_client_set_username (FuRedfishClient *self, const gchar *username) { - g_free (self->username); - self->username = g_strdup (username); + curl_easy_setopt (self->curl, CURLOPT_USERNAME, username); } void fu_redfish_client_set_password (FuRedfishClient *self, const gchar *password) { - g_free (self->password); - self->password = g_strdup (password); + curl_easy_setopt (self->curl, CURLOPT_PASSWORD, password); } static void fu_redfish_client_finalize (GObject *object) { FuRedfishClient *self = FU_REDFISH_CLIENT (object); - if (self->session != NULL) - g_object_unref (self->session); + if (self->curl != NULL) + curl_easy_cleanup (self->curl); g_free (self->update_uri_path); g_free (self->push_uri_path); g_free (self->hostname); - g_free (self->username); - g_free (self->password); g_ptr_array_unref (self->devices); G_OBJECT_CLASS (fu_redfish_client_parent_class)->finalize (object); } @@ -836,6 +868,11 @@ fu_redfish_client_init (FuRedfishClient *self) { self->devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + self->curl = curl_easy_init (); + + /* since DSP0266 makes Basic Authorization a requirement, + * it is safe to use Basic Auth for all implementations */ + curl_easy_setopt (self->curl, CURLOPT_HTTPAUTH, (glong) CURLAUTH_BASIC); } FuRedfishClient * diff -Nru fwupd-1.4.5/plugins/redfish/fu-redfish-client.h fwupd-1.5.8/plugins/redfish/fu-redfish-client.h --- fwupd-1.4.5/plugins/redfish/fu-redfish-client.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/redfish/fu-redfish-client.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/redfish/fu-redfish-common.c fwupd-1.5.8/plugins/redfish/fu-redfish-common.c --- fwupd-1.4.5/plugins/redfish/fu-redfish-common.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/redfish/fu-redfish-common.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -10,26 +10,6 @@ #include "fu-redfish-common.h" -GBytes * -fu_redfish_common_get_evivar_raw (efi_guid_t guid, const gchar *name, GError **error) -{ - gsize sz = 0; - guint32 attribs = 0; - guint8 *data = NULL; - - if (efi_get_variable (guid, name, &data, &sz, &attribs) < 0) { - g_autofree gchar *guid_str = NULL; - efi_guid_to_str (&guid, &guid_str); - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "failed to get efivar for %s %s", - guid_str, name); - return NULL; - } - return g_bytes_new_take (data, sz); -} - gchar * fu_redfish_common_buffer_to_ipv4 (const guint8 *buffer) { diff -Nru fwupd-1.4.5/plugins/redfish/fu-redfish-common.h fwupd-1.5.8/plugins/redfish/fu-redfish-common.h --- fwupd-1.4.5/plugins/redfish/fu-redfish-common.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/redfish/fu-redfish-common.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -7,7 +7,6 @@ #pragma once #include -#include /* SMBIOS */ #define REDFISH_SMBIOS_TABLE_TYPE 0x42 @@ -29,7 +28,7 @@ #define REDFISH_IP_ADDRESS_FORMAT_V6 0x02 /* EFI */ -#define REDFISH_EFI_INFORMATION_GUID EFI_GUID(0x16faa37e,0x4b6a,0x4891,0x9028,0x24,0x2d,0xe6,0x5a,0x3b,0x70) +#define REDFISH_EFI_INFORMATION_GUID "16faa37e-4b6a-4891-9028-242de65a3b70" #define REDFISH_EFI_INFORMATION_INDICATIONS "RedfishIndications" #define REDFISH_EFI_INFORMATION_FW_CREDENTIALS "RedfishFWCredentials" @@ -39,8 +38,5 @@ #define REDFISH_EFI_INDICATIONS_OS_CREDENTIALS 0x00000002 /* shared */ -GBytes *fu_redfish_common_get_evivar_raw (efi_guid_t guid, - const gchar *name, - GError **error); gchar *fu_redfish_common_buffer_to_ipv4 (const guint8 *buffer); gchar *fu_redfish_common_buffer_to_ipv6 (const guint8 *buffer); diff -Nru fwupd-1.4.5/plugins/redfish/fu-self-test.c fwupd-1.5.8/plugins/redfish/fu-self-test.c --- fwupd-1.4.5/plugins/redfish/fu-self-test.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/redfish/fu-self-test.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/redfish/meson.build fwupd-1.5.8/plugins/redfish/meson.build --- fwupd-1.4.5/plugins/redfish/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/redfish/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,7 @@ +if get_option('plugin_redfish') +if not get_option('curl') + error('curl is required for plugin_redfish') +endif cargs = ['-DG_LOG_DOMAIN="FuPluginRedfish"'] shared_module('fu_plugin_redfish', @@ -21,7 +25,7 @@ c_args : cargs, dependencies : [ plugin_deps, - efivar, + libcurl, libjsonglib, ], ) @@ -46,14 +50,17 @@ ], dependencies : [ plugin_deps, - efivar, + libcurl, libjsonglib, ], link_with : [ fwupd, fwupdplugin, ], - c_args : cargs + c_args : cargs, + install : true, + install_dir : installed_test_bindir, ) - test('redfish-self-test', e) + test('redfish-self-test', e) # added to installed-tests +endif endif diff -Nru fwupd-1.4.5/plugins/redfish/README.md fwupd-1.5.8/plugins/redfish/README.md --- fwupd-1.4.5/plugins/redfish/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/redfish/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -26,6 +26,12 @@ These devices use the provided GUID provided in the `SoftwareId` parameter without modification. Devices without GUIDs are not supported. +Update Behavior +--------------- + +The firmware willl be deployed as appropriate. The Redfish API does not specify +when the firmware will actually be written to the SPI device. + Vendor ID Security ------------------ @@ -73,3 +79,7 @@ or $ curl -k https://192.168.0.133:443/redfish/v1/ + +External interface access +------------------------- +This requires HTTP access to a given URL. diff -Nru fwupd-1.4.5/plugins/rts54hid/fu-plugin-rts54hid.c fwupd-1.5.8/plugins/rts54hid/fu-plugin-rts54hid.c --- fwupd-1.4.5/plugins/rts54hid/fu-plugin-rts54hid.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/rts54hid/fu-plugin-rts54hid.c 2021-03-31 20:08:32.000000000 +0000 @@ -7,7 +7,6 @@ #include "config.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #include "fu-rts54hid-device.h" #include "fu-rts54hid-module.h" @@ -17,6 +16,9 @@ { fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_set_device_gtype (plugin, FU_TYPE_RTS54HID_DEVICE); + fu_plugin_add_possible_quirk_key (plugin, "Rts54TargetAddr"); + fu_plugin_add_possible_quirk_key (plugin, "Rts54I2cSpeed"); + fu_plugin_add_possible_quirk_key (plugin, "Rts54RegisterAddrLen"); /* register the custom types */ g_type_ensure (FU_TYPE_RTS54HID_MODULE); diff -Nru fwupd-1.4.5/plugins/rts54hid/fu-rts54hid-common.h fwupd-1.5.8/plugins/rts54hid/fu-rts54hid-common.h --- fwupd-1.4.5/plugins/rts54hid/fu-rts54hid-common.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/rts54hid/fu-rts54hid-common.h 2021-03-31 20:08:32.000000000 +0000 @@ -15,7 +15,7 @@ #define FU_RTS54HID_CMD_BUFFER_OFFSET_DATA 0x40 typedef struct __attribute__ ((packed)) { - guint8 slave_addr; + guint8 target_addr; guint8 data_sz; guint8 speed; } FuRts54HidI2cParameters; diff -Nru fwupd-1.4.5/plugins/rts54hid/fu-rts54hid-device.c fwupd-1.5.8/plugins/rts54hid/fu-rts54hid-device.c --- fwupd-1.4.5/plugins/rts54hid/fu-rts54hid-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/rts54hid/fu-rts54hid-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -132,7 +132,7 @@ FU_HID_DEVICE_FLAG_NONE, error)) return FALSE; - g_usleep (4 * G_USEC_PER_SEC); + fu_device_sleep_with_progress (FU_DEVICE (self), 4); /* seconds */ if (!fu_hid_device_get_report (FU_HID_DEVICE (self), 0x0, buf, sizeof(buf), FU_RTS54HID_DEVICE_TIMEOUT, FU_HID_DEVICE_FLAG_NONE, @@ -140,7 +140,7 @@ return FALSE; /* check device status */ - if (buf[0x40] != 0x01) { + if (buf[0] != 0x01) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_WRITE, @@ -207,11 +207,11 @@ return FALSE; /* check the hardware capabilities */ - self->dual_bank = (buf[0x40 + 7] & 0xf0) == 0x80; - self->fw_auth = (buf[0x40 + 13] & 0x02) > 0; + self->dual_bank = (buf[7] & 0xf0) == 0x80; + self->fw_auth = (buf[13] & 0x02) > 0; /* hub version is more accurate than bcdVersion */ - version = g_strdup_printf ("%x.%x", buf[0x40 + 10], buf[0x40 + 11]); + version = g_strdup_printf ("%x.%x", buf[10], buf[11]); fu_device_set_version (FU_DEVICE (self), version); return TRUE; } @@ -241,12 +241,16 @@ } static gboolean -fu_rts54hid_device_close (FuHidDevice *device, GError **error) +fu_rts54hid_device_close (FuDevice *device, GError **error) { FuRts54HidDevice *self = FU_RTS54HID_DEVICE (device); /* set MCU to normal clock rate */ - return fu_rts54hid_device_set_clock_mode (self, FALSE, error); + if (!fu_rts54hid_device_set_clock_mode (self, FALSE, error)) + return FALSE; + + /* FuHidDevice->close */ + return FU_DEVICE_CLASS (fu_rts54hid_device_parent_class)->close (device, error); } static gboolean @@ -283,12 +287,11 @@ fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); for (guint i = 0; i < chunks->len; i++) { FuChunk *chk = g_ptr_array_index (chunks, i); - /* write chunk */ if (!fu_rts54hid_device_write_flash (self, - chk->address, - chk->data, - chk->data_sz, + fu_chunk_get_address (chk), + fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk), error)) return FALSE; @@ -311,7 +314,7 @@ static void fu_rts54hid_device_init (FuRts54HidDevice *self) { - fu_device_set_protocol (FU_DEVICE (self), "com.realtek.rts54"); + fu_device_add_protocol (FU_DEVICE (self), "com.realtek.rts54"); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_PAIR); } @@ -319,9 +322,8 @@ fu_rts54hid_device_class_init (FuRts54HidDeviceClass *klass) { FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - FuHidDeviceClass *klass_hid_device = FU_HID_DEVICE_CLASS (klass); klass_device->write_firmware = fu_rts54hid_device_write_firmware; klass_device->to_string = fu_rts54hid_device_to_string; klass_device->setup = fu_rts54hid_device_setup; - klass_hid_device->close = fu_rts54hid_device_close; + klass_device->close = fu_rts54hid_device_close; } diff -Nru fwupd-1.4.5/plugins/rts54hid/fu-rts54hid-module.c fwupd-1.5.8/plugins/rts54hid/fu-rts54hid-module.c --- fwupd-1.4.5/plugins/rts54hid/fu-rts54hid-module.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/rts54hid/fu-rts54hid-module.c 2021-03-31 20:08:32.000000000 +0000 @@ -17,7 +17,7 @@ struct _FuRts54HidModule { FuDevice parent_instance; - guint8 slave_addr; + guint8 target_addr; guint8 i2c_speed; guint8 register_addr_len; }; @@ -28,7 +28,7 @@ fu_rts54hid_module_to_string (FuDevice *module, guint idt, GString *str) { FuRts54HidModule *self = FU_RTS54HID_MODULE (module); - fu_common_string_append_kx (str, idt, "SlaveAddr", self->slave_addr); + fu_common_string_append_kx (str, idt, "TargetAddr", self->target_addr); fu_common_string_append_kx (str, idt, "I2cSpeed", self->i2c_speed); fu_common_string_append_kx (str, idt, "RegisterAddrLen", self->register_addr_len); } @@ -59,7 +59,7 @@ .ext = FU_RTS54HID_EXT_I2C_WRITE, .dwregaddr = 0, .bufferlen = GUINT16_TO_LE (data_sz), - .parameters_i2c = {.slave_addr = self->slave_addr, + .parameters_i2c = {.target_addr = self->target_addr, .data_sz = self->register_addr_len, .speed = self->i2c_speed | 0x80}, }; @@ -83,7 +83,7 @@ FU_RTS54HID_DEVICE_TIMEOUT * 2, FU_HID_DEVICE_FLAG_NONE, error)) { - g_prefix_error (error, "failed to write i2c @%04x: ", self->slave_addr); + g_prefix_error (error, "failed to write i2c @%04x: ", self->target_addr); return FALSE; } return TRUE; @@ -102,7 +102,7 @@ .ext = FU_RTS54HID_EXT_I2C_READ, .dwregaddr = GUINT32_TO_LE (cmd), .bufferlen = GUINT16_TO_LE (data_sz), - .parameters_i2c = {.slave_addr = self->slave_addr, + .parameters_i2c = {.target_addr = self->target_addr, .data_sz = self->register_addr_len, .speed = self->i2c_speed | 0x80}, }; @@ -123,7 +123,7 @@ FU_RTS54HID_DEVICE_TIMEOUT * 2, FU_HID_DEVICE_FLAG_NONE, error)) { - g_prefix_error (error, "failed to write i2c @%04x: ", self->slave_addr); + g_prefix_error (error, "failed to write i2c @%04x: ", self->target_addr); return FALSE; } if (!fu_hid_device_get_report (FU_HID_DEVICE (parent), 0x0, buf, sizeof(buf), @@ -144,17 +144,17 @@ { FuRts54HidModule *self = FU_RTS54HID_MODULE (device); - /* load slave address from quirks */ - if (g_strcmp0 (key, "Rts54SlaveAddr") == 0) { + /* load target address from quirks */ + if (g_strcmp0 (key, "Rts54TargetAddr") == 0) { guint64 tmp = fu_common_strtoull (value); if (tmp <= 0xff) { - self->slave_addr = tmp; + self->target_addr = tmp; return TRUE; } g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, - "invalid slave address"); + "invalid target address"); return FALSE; } @@ -258,8 +258,8 @@ /* write chunk */ if (!fu_rts54hid_module_i2c_write (self, - chk->data, - chk->data_sz, + fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk), error)) return FALSE; diff -Nru fwupd-1.4.5/plugins/rts54hid/meson.build fwupd-1.5.8/plugins/rts54hid/meson.build --- fwupd-1.4.5/plugins/rts54hid/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/rts54hid/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,4 @@ +if get_option('gusb') cargs = ['-DG_LOG_DOMAIN="FuPluginRts54Hid"'] install_data([ @@ -29,3 +30,4 @@ plugin_deps, ], ) +endif diff -Nru fwupd-1.4.5/plugins/rts54hid/README.md fwupd-1.5.8/plugins/rts54hid/README.md --- fwupd-1.4.5/plugins/rts54hid/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/rts54hid/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -33,6 +33,12 @@ * `USB\VID_0BDA&PID_1100&I2C_01` +Update Behavior +--------------- + +The firmware is deployed when the device is in normal runtime mode, and the +device will reset when the new firmware has been written. + Vendor ID Security ------------------ @@ -44,6 +50,10 @@ | Quirk | Description | Minimum fwupd version | |------------------------|---------------------------------------------|-----------------------| -| `Rts54SlaveAddr` | The slave address of a child module. | 1.1.3 | +| `Rts54TargetAddr` | The target address of a child module. | 1.1.3 | | `Rts54I2cSpeed` | The I2C speed to operate at (0, 1, 2). | 1.1.3 | | `Rts54RegisterAddrLen` | The I2C register address length of commands | 1.1.3 | + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff -Nru fwupd-1.4.5/plugins/rts54hid/rts54hid.quirk fwupd-1.5.8/plugins/rts54hid/rts54hid.quirk --- fwupd-1.4.5/plugins/rts54hid/rts54hid.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/rts54hid/rts54hid.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,16 +1,16 @@ # RTS5423 -[DeviceInstanceId=USB\VID_0BDA&PID_1100] +[USB\VID_0BDA&PID_1100] Plugin = rts54hid FirmwareSizeMin = 0x10000 FirmwareSizeMax = 0x40000 Children = FuRts54HidModule|USB\VID_0BDA&PID_1100&I2C_01 # this is a fictitious example... -[DeviceInstanceId=USB\VID_0BDA&PID_1100&I2C_01] +[USB\VID_0BDA&PID_1100&I2C_01] Plugin = rts54hid Name = HDMI Converter Flags = updatable FirmwareSize = 0x20000 -Rts54SlaveAddr = 0x00 +Rts54TargetAddr = 0x00 Rts54I2cSpeed = 0x00 Rts54RegisterAddrLen = 0x04 diff -Nru fwupd-1.4.5/plugins/rts54hub/fu-plugin-rts54hub.c fwupd-1.5.8/plugins/rts54hub/fu-plugin-rts54hub.c --- fwupd-1.4.5/plugins/rts54hub/fu-plugin-rts54hub.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/rts54hub/fu-plugin-rts54hub.c 2021-03-31 20:08:32.000000000 +0000 @@ -7,13 +7,17 @@ #include "config.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #include "fu-rts54hub-device.h" +#include "fu-rts54hub-rtd21xx-device.h" void fu_plugin_init (FuPlugin *plugin) { fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_set_device_gtype (plugin, FU_TYPE_RTS54HUB_DEVICE); + fu_plugin_add_possible_quirk_key (plugin, "Rts54TargetAddr"); + fu_plugin_add_possible_quirk_key (plugin, "Rts54I2cSpeed"); + fu_plugin_add_possible_quirk_key (plugin, "Rts54RegisterAddrLen"); + g_type_ensure (FU_TYPE_RTS54HUB_RTD21XX_DEVICE); } diff -Nru fwupd-1.4.5/plugins/rts54hub/fu-rts54hub-device.c fwupd-1.5.8/plugins/rts54hub/fu-rts54hub-device.c --- fwupd-1.4.5/plugins/rts54hub/fu-rts54hub-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/rts54hub/fu-rts54hub-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -21,13 +21,17 @@ G_DEFINE_TYPE (FuRts54HubDevice, fu_rts54hub_device, FU_TYPE_USB_DEVICE) -#define FU_RTS54HUB_DEVICE_TIMEOUT 100 /* ms */ +#define FU_RTS54HUB_DEVICE_TIMEOUT 1000 /* ms */ #define FU_RTS54HUB_DEVICE_TIMEOUT_RW 1000 /* ms */ #define FU_RTS54HUB_DEVICE_TIMEOUT_ERASE 5000 /* ms */ #define FU_RTS54HUB_DEVICE_TIMEOUT_AUTH 10000 /* ms */ #define FU_RTS54HUB_DEVICE_BLOCK_SIZE 4096 #define FU_RTS54HUB_DEVICE_STATUS_LEN 25 +#define FU_RTS54HUB_I2C_CONFIG_REQUEST 0xF6 +#define FU_RTS54HUB_I2C_WRITE_REQUEST 0xC6 +#define FU_RTS54HUB_I2C_READ_REQUEST 0xD6 + typedef enum { FU_RTS54HUB_VENDOR_CMD_NONE = 0x00, FU_RTS54HUB_VENDOR_CMD_STATUS = 1 << 0, @@ -43,6 +47,83 @@ fu_common_string_append_kb (str, idt, "RunningOnFlash", self->running_on_flash); } +gboolean +fu_rts54hub_device_i2c_config (FuRts54HubDevice *self, + guint8 target_addr, + guint8 sub_length, + FuRts54HubI2cSpeed speed, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + guint16 value = 0; + guint16 index = 0x8080; + + value = ((guint16)target_addr << 8) | sub_length; + index += speed; + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + FU_RTS54HUB_I2C_CONFIG_REQUEST, + value, /* value */ + index, /* idx */ + NULL, 0, /* data */ + NULL, /* actual */ + FU_RTS54HUB_DEVICE_TIMEOUT, + NULL, error)) { + g_prefix_error (error, "failed to issue i2c Conf cmd 0x%02x: ", target_addr); + return FALSE; + } + return TRUE; +} + +gboolean +fu_rts54hub_device_i2c_write (FuRts54HubDevice *self, + guint32 sub_addr, const guint8 *data, gsize datasz, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + g_autofree guint8 *datarw = fu_memdup_safe (data, datasz, error); + if (datarw == NULL) + return FALSE; + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + FU_RTS54HUB_I2C_WRITE_REQUEST, + sub_addr, /* value */ + 0x0000, /* idx */ + datarw, datasz, /* data */ + NULL, + FU_RTS54HUB_DEVICE_TIMEOUT, + NULL, error)) { + g_prefix_error (error, "failed to write I2C"); + return FALSE; + } + return TRUE; +} + +gboolean +fu_rts54hub_device_i2c_read (FuRts54HubDevice *self, + guint32 sub_addr, guint8 *data, + gsize datasz, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + FU_RTS54HUB_I2C_READ_REQUEST, 0x0000, + sub_addr, + data, datasz, NULL, + FU_RTS54HUB_DEVICE_TIMEOUT, + NULL, error)) { + g_prefix_error (error, "failed to read I2C: "); + return FALSE; + } + return TRUE; +} + static gboolean fu_rts54hub_device_highclockmode (FuRts54HubDevice *self, guint16 value, GError **error) { @@ -95,7 +176,13 @@ { GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); gsize actual_len = 0; - g_autofree guint8 *datarw = g_memdup (data, datasz); + g_autofree guint8 *datarw = NULL; + + /* make mutable */ + datarw = fu_memdup_safe (data, datasz, error); + if (datarw == NULL) + return FALSE; + if (!g_usb_device_control_transfer (usb_device, G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, G_USB_DEVICE_REQUEST_TYPE_VENDOR, @@ -195,7 +282,7 @@ return TRUE; } -static gboolean +gboolean fu_rts54hub_device_vendor_cmd (FuRts54HubDevice *self, guint8 value, GError **error) { GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); @@ -290,7 +377,7 @@ } static gboolean -fu_rts54hub_device_close (FuUsbDevice *device, GError **error) +fu_rts54hub_device_close (FuDevice *device, GError **error) { FuRts54HubDevice *self = FU_RTS54HUB_DEVICE (device); @@ -302,8 +389,8 @@ } } - /* success */ - return TRUE; + /* FuUsbDevice->close */ + return FU_DEVICE_CLASS (fu_rts54hub_device_parent_class)->close (device, error); } static gboolean @@ -360,9 +447,9 @@ /* write chunk */ if (!fu_rts54hub_device_write_flash (self, - chk->address, - chk->data, - chk->data_sz, + fu_chunk_get_address (chk), + fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk), error)) return FALSE; @@ -394,16 +481,13 @@ FwupdInstallFlags flags, GError **error) { - gsize sz = 0; - const guint8 *data = g_bytes_get_data (fw, &sz); - if (sz < 0x7ef3) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "firmware was too small"); + gsize bufsz = 0; + guint8 tmp = 0; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + + if (!fu_common_read_uint8_safe (buf, bufsz, 0x7ef3, &tmp, error)) return NULL; - } - if ((data[0x7ef3] & 0xf0) != 0x80) { + if ((tmp & 0xf0) != 0x80) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, @@ -416,7 +500,7 @@ static void fu_rts54hub_device_init (FuRts54HubDevice *self) { - fu_device_set_protocol (FU_DEVICE (self), "com.realtek.rts54"); + fu_device_add_protocol (FU_DEVICE (self), "com.realtek.rts54"); fu_device_set_remove_delay (FU_DEVICE (self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); } @@ -424,10 +508,9 @@ fu_rts54hub_device_class_init (FuRts54HubDeviceClass *klass) { FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); klass_device->write_firmware = fu_rts54hub_device_write_firmware; klass_device->setup = fu_rts54hub_device_setup; klass_device->to_string = fu_rts54hub_device_to_string; klass_device->prepare_firmware = fu_rts54hub_device_prepare_firmware; - klass_usb_device->close = fu_rts54hub_device_close; + klass_device->close = fu_rts54hub_device_close; } diff -Nru fwupd-1.4.5/plugins/rts54hub/fu-rts54hub-device.h fwupd-1.5.8/plugins/rts54hub/fu-rts54hub-device.h --- fwupd-1.4.5/plugins/rts54hub/fu-rts54hub-device.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/rts54hub/fu-rts54hub-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -9,4 +9,36 @@ #include "fu-plugin.h" #define FU_TYPE_RTS54HUB_DEVICE (fu_rts54hub_device_get_type ()) + +typedef enum { + FU_RTS54HUB_I2C_SPEED_100K, + FU_RTS54HUB_I2C_SPEED_200K, + FU_RTS54HUB_I2C_SPEED_300K, + FU_RTS54HUB_I2C_SPEED_400K, + FU_RTS54HUB_I2C_SPEED_500K, + FU_RTS54HUB_I2C_SPEED_600K, + FU_RTS54HUB_I2C_SPEED_700K, + FU_RTS54HUB_I2C_SPEED_800K, + FU_RTS54HUB_I2C_SPEED_LAST +} FuRts54HubI2cSpeed; + G_DECLARE_FINAL_TYPE (FuRts54HubDevice, fu_rts54hub_device, FU, RTS54HUB_DEVICE, FuUsbDevice) + +gboolean fu_rts54hub_device_vendor_cmd (FuRts54HubDevice *self, + guint8 value, + GError **error); +gboolean fu_rts54hub_device_i2c_config (FuRts54HubDevice *self, + guint8 target_addr, + guint8 sub_length, + FuRts54HubI2cSpeed speed, + GError **error); +gboolean fu_rts54hub_device_i2c_write (FuRts54HubDevice *self, + guint32 sub_addr, + const guint8 *data, + gsize datasz, + GError **error); +gboolean fu_rts54hub_device_i2c_read (FuRts54HubDevice *self, + guint32 sub_addr, + guint8 *data, + gsize datasz, + GError **error); diff -Nru fwupd-1.4.5/plugins/rts54hub/fu-rts54hub-rtd21xx-device.c fwupd-1.5.8/plugins/rts54hub/fu-rts54hub-rtd21xx-device.c --- fwupd-1.4.5/plugins/rts54hub/fu-rts54hub-rtd21xx-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/rts54hub/fu-rts54hub-rtd21xx-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,605 @@ +/* + * Copyright (C) 2021 Realtek Corporation + * Copyright (C) 2021 Ricky Wu + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-chunk.h" + +#include "fu-rts54hub-rtd21xx-device.h" +#include "fu-rts54hub-device.h" + +struct _FuRts54hubRtd21xxDevice +{ + FuDevice parent_instance; + guint8 target_addr; + guint8 i2c_speed; + guint8 register_addr_len; +}; + +G_DEFINE_TYPE (FuRts54hubRtd21xxDevice, fu_rts54hub_rtd21xx_device, FU_TYPE_DEVICE) + +#define I2C_DELAY_AFTER_SEND 5000 /* us */ + +#define UC_FOREGROUND_SLAVE_ADDR 0x3A +#define UC_FOREGROUND_STATUS 0x31 +#define UC_FOREGROUND_OPCODE 0x33 +#define UC_FOREGROUND_ISP_DATA_OPCODE 0x34 + +#define ISP_DATA_BLOCKSIZE 256 +#define ISP_PACKET_SIZE 257 + +typedef enum { + ISP_STATUS_BUSY = 0xBB, /* host must wait for device */ + ISP_STATUS_IDLE_SUCCESS = 0x11, /* previous command was OK */ + ISP_STATUS_IDLE_FAILURE = 0x12, /* previous command failed */ +} IspStatus; + +typedef enum { + ISP_CMD_ENTER_FW_UPDATE = 0x01, + ISP_CMD_GET_PROJECT_ID_ADDR = 0x02, + ISP_CMD_SYNC_IDENTIFY_CODE = 0x03, + ISP_CMD_GET_FW_INFO = 0x04, + ISP_CMD_FW_UPDATE_START = 0x05, + ISP_CMD_FW_UPDATE_ISP_DONE = 0x06, + ISP_CMD_FW_UPDATE_EXIT = 0x07, + ISP_CMD_FW_UPDATE_RESET = 0x08, +} IspCmd; + +typedef enum { + VENDOR_CMD_DISABLE = 0x00, + VENDOR_CMD_ENABLE = 0x01, + VENDOR_CMD_ACCESS_FLASH = 0x02, +} VendorCmd; + +static void +fu_rts54hub_rtd21xx_device_to_string (FuDevice *module, guint idt, GString *str) +{ + FuRts54hubRtd21xxDevice *self = FU_RTS54HUB_RTD21XX_DEVICE (module); + fu_common_string_append_kx (str, idt, "TargetAddr", self->target_addr); + fu_common_string_append_kx (str, idt, "I2cSpeed", self->i2c_speed); + fu_common_string_append_kx (str, idt, "RegisterAddrLen", self->register_addr_len); +} + +static FuRts54HubDevice * +fu_rts54hub_rtd21xx_device_get_parent (FuRts54hubRtd21xxDevice *self, GError **error) +{ + FuDevice *parent = fu_device_get_parent (FU_DEVICE (self)); + if (parent == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "no parent set"); + return NULL; + } + return FU_RTS54HUB_DEVICE (parent); +} + +static gboolean +fu_rts54hub_rtd21xx_device_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + FuRts54hubRtd21xxDevice *self = FU_RTS54HUB_RTD21XX_DEVICE (device); + /* load target address from quirks */ + if (g_strcmp0 (key, "Rts54TargetAddr") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp <= 0xff) { + self->target_addr = tmp; + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid target address"); + return FALSE; + } + + /* load i2c speed from quirks */ + if (g_strcmp0 (key, "Rts54I2cSpeed") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp < FU_RTS54HUB_I2C_SPEED_LAST) { + self->i2c_speed = tmp; + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid I²C speed"); + return FALSE; + } + + /* load register address length from quirks */ + if (g_strcmp0 (key, "Rts54RegisterAddrLen") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp <= 0xff) { + self->register_addr_len = tmp; + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid register address length"); + return FALSE; + } + + /* failed */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; +} + +static gboolean +fu_rts54hub_rtd21xx_device_i2c_write (FuRts54hubRtd21xxDevice *self, + guint8 target_addr, guint8 sub_addr, + const guint8 *data, gsize datasz, + GError **error) +{ + FuRts54HubDevice *parent; + + parent = fu_rts54hub_rtd21xx_device_get_parent (self, error); + if (parent == NULL) + return FALSE; + if (!fu_rts54hub_device_vendor_cmd (parent, VENDOR_CMD_ENABLE, error)) + return FALSE; + + if (target_addr != self->target_addr) { + if (!fu_rts54hub_device_i2c_config (parent, target_addr, 1, + FU_RTS54HUB_I2C_SPEED_200K, + error)) + return FALSE; + self->target_addr = target_addr; + } + if (!fu_rts54hub_device_i2c_write (parent, sub_addr, data, datasz, error)) { + g_prefix_error (error, + "failed to write I2C @0x%02x:%02x: ", + target_addr, sub_addr); + return FALSE; + } + g_usleep (I2C_DELAY_AFTER_SEND); + return TRUE; +} + +static gboolean +fu_rts54hub_rtd21xx_device_i2c_read (FuRts54hubRtd21xxDevice *self, + guint8 target_addr, guint8 sub_addr, + guint8 *data, gsize datasz, + GError **error) +{ + FuRts54HubDevice *parent; + + parent = fu_rts54hub_rtd21xx_device_get_parent (self, error); + if (parent == NULL) + return FALSE; + if (!fu_rts54hub_device_vendor_cmd (parent, VENDOR_CMD_ENABLE, error)) + return FALSE; + if (target_addr != self->target_addr) { + if (!fu_rts54hub_device_i2c_config (parent, target_addr, 1, + FU_RTS54HUB_I2C_SPEED_200K, + error)) + return FALSE; + self->target_addr = target_addr; + } + if (!fu_rts54hub_device_i2c_read (parent, sub_addr, data, datasz, error)) { + g_prefix_error (error, "failed to read I2C: "); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_rts54hub_rtd21xx_device_read_status_raw (FuRts54hubRtd21xxDevice *self, + guint8 *status, + GError **error) +{ + guint8 buf = 0x00; + if (!fu_rts54hub_rtd21xx_device_i2c_read (self, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_STATUS, + &buf, sizeof(buf), + error)) + return FALSE; + if (status != NULL) + *status = buf; + return TRUE; +} + +static gboolean +fu_rts54hub_rtd21xx_device_read_status_cb (FuDevice *device, + gpointer user_data, + GError **error) +{ + FuRts54hubRtd21xxDevice *self = FU_RTS54HUB_RTD21XX_DEVICE (device); + guint8 status = 0xfd; + if (!fu_rts54hub_rtd21xx_device_read_status_raw (self, &status, error)) + return FALSE; + if (status == ISP_STATUS_BUSY) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "status was 0x%02x", status); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_rts54hub_rtd21xx_device_read_status (FuRts54hubRtd21xxDevice *self, + guint8 *status, + GError **error) +{ + return fu_device_retry (FU_DEVICE (self), + fu_rts54hub_rtd21xx_device_read_status_cb, + 4200, status, error); +} + +static gboolean +fu_rts54hub_rtd21xx_ensure_version_unlocked (FuRts54hubRtd21xxDevice *self, + GError **error) +{ + guint8 buf_rep[7] = { 0x00 }; + guint8 buf_req[] = { ISP_CMD_GET_FW_INFO }; + guint8 buf[] = { ISP_CMD_FW_UPDATE_RESET }; + g_autofree gchar *version = NULL; + if (!fu_rts54hub_rtd21xx_device_i2c_write (self, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_OPCODE, + buf_req, sizeof(buf_req), + error)) { + g_prefix_error (error, "failed to get version number: "); + return FALSE; + } + + /* wait for device ready */ + g_usleep(300000); + if (!fu_rts54hub_rtd21xx_device_i2c_read (self, + UC_FOREGROUND_SLAVE_ADDR, + 0x00, + buf_rep, sizeof(buf_rep), + error)) { + g_prefix_error (error, "failed to get version number: "); + return FALSE; + } + /* set version */ + version = g_strdup_printf ("%u.%u", buf_rep[1], buf_rep[2]); + fu_device_set_version (FU_DEVICE (self), version); + + if (!fu_rts54hub_rtd21xx_device_i2c_write (self, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_OPCODE, + buf, sizeof(buf), + error)) { + g_prefix_error (error, "failed to ISP_CMD_FW_UPDATE_RESET: "); + return FALSE; + } + + return TRUE; +} + +static gboolean +fu_rts54hub_rtd21xx_device_detach_raw (FuRts54hubRtd21xxDevice *self, GError **error) +{ + guint8 buf = 0x03; + if (!fu_rts54hub_rtd21xx_device_i2c_write (self, 0x6A, 0x31, + &buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to detach: "); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_rts54hub_rtd21xx_device_detach_cb (FuDevice *device, + gpointer user_data, + GError **error) +{ + FuRts54hubRtd21xxDevice *self = FU_RTS54HUB_RTD21XX_DEVICE (device); + guint8 status = 0xfe; + + if (!fu_rts54hub_rtd21xx_device_detach_raw (self, error)) + return FALSE; + if (!fu_rts54hub_rtd21xx_device_read_status_raw (self, &status, error)) + return FALSE; + if (status != ISP_STATUS_IDLE_SUCCESS) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "detach status was 0x%02x", status); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_rts54hub_rtd21xx_device_setup (FuDevice *device, GError **error) +{ + FuRts54hubRtd21xxDevice *self = FU_RTS54HUB_RTD21XX_DEVICE (device); + g_autoptr(FuDeviceLocker) locker = NULL; + + /* get version */ + locker = fu_device_locker_new_full (device, + (FuDeviceLockerFunc) fu_device_detach, + (FuDeviceLockerFunc) fu_device_attach, + error); + if (locker == NULL) + return FALSE; + if (!fu_rts54hub_rtd21xx_ensure_version_unlocked (self, error)) + return FALSE; + + /* success */ + return TRUE; +} + +static gboolean +fu_rts54hub_rtd21xx_device_reload (FuDevice *device, GError **error) +{ + FuRts54HubDevice *parent = FU_RTS54HUB_DEVICE (fu_device_get_parent (device)); + g_autoptr(FuDeviceLocker) locker = NULL; + + /* open parent device */ + locker = fu_device_locker_new (parent, error); + if (locker == NULL) + return FALSE; + return fu_rts54hub_rtd21xx_device_setup (device, error); +} + +static gboolean +fu_rts54hub_rtd21xx_device_detach (FuDevice *device, GError **error) +{ + FuRts54HubDevice *parent = FU_RTS54HUB_DEVICE (fu_device_get_parent (device)); + g_autoptr(FuDeviceLocker) locker = NULL; + + /* open device */ + locker = fu_device_locker_new (parent, error); + if (locker == NULL) + return FALSE; + if (!fu_device_retry (device, + fu_rts54hub_rtd21xx_device_detach_cb, + 100, NULL, error)) + return FALSE; + + return TRUE; +} + +static gboolean +fu_rts54hub_rtd21xx_device_write_firmware (FuDevice *device, + FuFirmware *firmware, + FwupdInstallFlags flags, + GError **error) +{ + FuRts54hubRtd21xxDevice *self = FU_RTS54HUB_RTD21XX_DEVICE (device); + const guint8 *fwbuf; + gsize fwbufsz = 0; + guint32 project_addr; + guint8 project_id_count; + guint8 read_buf[10] = { 0x0 }; + guint8 write_buf[ISP_PACKET_SIZE] = { 0x0 }; + g_autoptr(FuDeviceLocker) locker = NULL; + g_autoptr(GBytes) fw = NULL; + g_autoptr(GPtrArray) chunks = NULL; + + /* open device */ + locker = fu_device_locker_new (self, error); + if (locker == NULL) + return FALSE; + + /* simple image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + fwbuf = g_bytes_get_data (fw, &fwbufsz); + + /* enable ISP high priority */ + write_buf[0] = ISP_CMD_ENTER_FW_UPDATE; + write_buf[1] = 0x01; + fu_device_set_status (device, FWUPD_STATUS_DEVICE_BUSY); + if (!fu_rts54hub_rtd21xx_device_i2c_write (self, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_OPCODE, + write_buf, 2, + error)) { + g_prefix_error (error, "failed to enable ISP: "); + return FALSE; + } + if (!fu_rts54hub_rtd21xx_device_read_status (self, NULL, error)) + return FALSE; + + /* get project ID address */ + write_buf[0] = ISP_CMD_GET_PROJECT_ID_ADDR; + fu_device_set_status (device, FWUPD_STATUS_DEVICE_READ); + if (!fu_rts54hub_rtd21xx_device_i2c_write (self, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_OPCODE, + write_buf, 1, + error)) { + g_prefix_error (error, "failed to get project ID address: "); + return FALSE; + } + + /* read back 6 bytes data */ + g_usleep (I2C_DELAY_AFTER_SEND * 40); + if (!fu_rts54hub_rtd21xx_device_i2c_read (self, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_STATUS, + read_buf, 6, + error)) { + g_prefix_error (error, "failed to read project ID: "); + return FALSE; + } + if (read_buf[0] != ISP_STATUS_IDLE_SUCCESS) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, + "failed project ID with error 0x%02x: ", + read_buf[0]); + return FALSE; + } + + /* verify project ID */ + project_addr = fu_common_read_uint32 (read_buf + 1, G_BIG_ENDIAN); + project_id_count = read_buf[5]; + write_buf[0] = ISP_CMD_SYNC_IDENTIFY_CODE; + if (!fu_memcpy_safe (write_buf, sizeof(write_buf), 0x1, /* dst */ + fwbuf, fwbufsz, project_addr, /* src */ + project_id_count, error)) { + g_prefix_error (error, + "failed to write project ID from 0x%04x: ", + project_addr); + return FALSE; + } + fu_device_set_status (device, FWUPD_STATUS_DEVICE_BUSY); + if (!fu_rts54hub_rtd21xx_device_i2c_write (self, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_OPCODE, + write_buf, + project_id_count + 1, + error)) { + g_prefix_error (error, "failed to send fw update start cmd: "); + return FALSE; + } + if (!fu_rts54hub_rtd21xx_device_read_status (self, NULL, error)) + return FALSE; + + /* background FW update start command */ + write_buf[0] = ISP_CMD_FW_UPDATE_START; + fu_common_write_uint16 (write_buf + 1, ISP_DATA_BLOCKSIZE, G_BIG_ENDIAN); + if (!fu_rts54hub_rtd21xx_device_i2c_write (self, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_OPCODE, + write_buf, 3, + error)) { + g_prefix_error (error, "failed to send fw update start cmd: "); + return FALSE; + } + + /* send data */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + chunks = fu_chunk_array_new_from_bytes (fw, + 0x00, /* start addr */ + 0x00, /* page_sz */ + ISP_DATA_BLOCKSIZE); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + if (!fu_rts54hub_rtd21xx_device_read_status (self, NULL, error)) + return FALSE; + if (!fu_rts54hub_rtd21xx_device_i2c_write (self, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_ISP_DATA_OPCODE, + fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk), + error)) { + g_prefix_error (error, + "failed to write @0x%04x: ", + fu_chunk_get_address (chk)); + return FALSE; + } + + /* update progress */ + fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len); + } + + /* update finish command */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_BUSY); + if (!fu_rts54hub_rtd21xx_device_read_status (self, NULL, error)) + return FALSE; + write_buf[0] = ISP_CMD_FW_UPDATE_ISP_DONE; + if (!fu_rts54hub_rtd21xx_device_i2c_write (self, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_OPCODE, + write_buf, 1, + error)) { + g_prefix_error (error, "failed update finish cmd: "); + return FALSE; + } + + /* exit background-fw mode */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + fu_device_set_progress (device, 0); + if (!fu_rts54hub_rtd21xx_device_read_status (self, NULL, error)) + return FALSE; + write_buf[0] = ISP_CMD_FW_UPDATE_EXIT; + if (!fu_rts54hub_rtd21xx_device_i2c_write (self, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_OPCODE, + write_buf, 1, + error)) { + g_prefix_error (error, "exit background-fw mode: "); + return FALSE; + } + + /* the device needs some time to restart with the new firmware before + * it can be queried again */ + fu_device_sleep_with_progress (device, 60); + + /* success */ + return TRUE; +} + +static gboolean +fu_rts54hub_rtd21xx_device_open (FuDevice *device, GError **error) +{ + FuDevice *parent = fu_device_get_parent (device); + if (parent == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "no parent device"); + return FALSE; + } + return fu_device_open (parent, error); +} + +static gboolean +fu_rts54hub_rtd21xx_device_close (FuDevice *device, GError **error) +{ + FuDevice *parent = fu_device_get_parent (device); + if (parent == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "no parent device"); + return FALSE; + } + return fu_device_close (parent, error); +} + +static void +fu_rts54hub_rtd21xx_device_init (FuRts54hubRtd21xxDevice *self) +{ + fu_device_add_icon (FU_DEVICE (self), "video-display"); + fu_device_add_protocol (FU_DEVICE (self), "com.realtek.rts54.i2c"); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_DUAL_IMAGE); + fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_PAIR); + fu_device_set_install_duration (FU_DEVICE (self), 100); /* seconds */ + fu_device_set_logical_id (FU_DEVICE (self), "I2C"); + fu_device_retry_set_delay (FU_DEVICE (self), 30); /* ms */ +} + +static void +fu_rts54hub_rtd21xx_device_class_init (FuRts54hubRtd21xxDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + klass_device->setup = fu_rts54hub_rtd21xx_device_setup; + klass_device->reload = fu_rts54hub_rtd21xx_device_reload; + klass_device->detach = fu_rts54hub_rtd21xx_device_detach; + klass_device->write_firmware = fu_rts54hub_rtd21xx_device_write_firmware; + klass_device->to_string = fu_rts54hub_rtd21xx_device_to_string; + klass_device->set_quirk_kv = fu_rts54hub_rtd21xx_device_set_quirk_kv; + klass_device->open = fu_rts54hub_rtd21xx_device_open; + klass_device->close = fu_rts54hub_rtd21xx_device_close; +} + +FuRts54hubRtd21xxDevice * +fu_rts54hub_rtd21xx_device_new (void) +{ + FuRts54hubRtd21xxDevice *self = NULL; + self = g_object_new (FU_TYPE_RTS54HUB_RTD21XX_DEVICE, NULL); + return self; +} diff -Nru fwupd-1.4.5/plugins/rts54hub/fu-rts54hub-rtd21xx-device.h fwupd-1.5.8/plugins/rts54hub/fu-rts54hub-rtd21xx-device.h --- fwupd-1.4.5/plugins/rts54hub/fu-rts54hub-rtd21xx-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/rts54hub/fu-rts54hub-rtd21xx-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2021 Ricky Wu + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +#define FU_TYPE_RTS54HUB_RTD21XX_DEVICE (fu_rts54hub_rtd21xx_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuRts54hubRtd21xxDevice, fu_rts54hub_rtd21xx_device, FU, RTS54HUB_RTD21XX_DEVICE, FuDevice) + +FuRts54hubRtd21xxDevice *fu_rts54hub_rtd21xx_device_new (void); diff -Nru fwupd-1.4.5/plugins/rts54hub/meson.build fwupd-1.5.8/plugins/rts54hub/meson.build --- fwupd-1.4.5/plugins/rts54hub/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/rts54hub/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,4 @@ +if get_option('gusb') cargs = ['-DG_LOG_DOMAIN="FuPluginRts54Hub"'] install_data([ @@ -10,6 +11,7 @@ fu_hash, sources : [ 'fu-rts54hub-device.c', + 'fu-rts54hub-rtd21xx-device.c', 'fu-plugin-rts54hub.c', ], include_directories : [ @@ -28,3 +30,4 @@ plugin_deps, ], ) +endif diff -Nru fwupd-1.4.5/plugins/rts54hub/README.md fwupd-1.5.8/plugins/rts54hub/README.md --- fwupd-1.4.5/plugins/rts54hub/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/rts54hub/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -16,9 +16,10 @@ The daemon will decompress the cabinet archive and extract a firmware blob in an unspecified binary file format. -This plugin supports the following protocol ID: +This plugin supports the following protocol IDs: * com.realtek.rts54 + * com.realtek.rts54.i2c GUID Generation --------------- @@ -29,7 +30,17 @@ * `USB\VID_0BDA&PID_5423` * `USB\VID_0BDA` +Update Behavior +--------------- + +The firmware is deployed when the device is in normal runtime mode, and the +device will reset when the new firmware has been written. + Vendor ID Security ------------------ The vendor ID is set from the USB vendor, in this instance set to `USB:0x0BDA` + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff -Nru fwupd-1.4.5/plugins/rts54hub/rts54hub.quirk fwupd-1.5.8/plugins/rts54hub/rts54hub.quirk --- fwupd-1.4.5/plugins/rts54hub/rts54hub.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/rts54hub/rts54hub.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,21 @@ # RTS5423 Development Board -[DeviceInstanceId=USB\VID_0BDA&PID_5423] +[USB\VID_0BDA&PID_5423] Plugin = rts54hub FirmwareSizeMin = 0x20000 FirmwareSizeMax = 0x40000 + +# Lenovo HotRod +[USB\VID_17EF&PID_30BF] +Plugin = rts54hub +Vendor = Lenovo +FirmwareSizeMin = 0x20000 +FirmwareSizeMax = 0x40000 +Children = FuRts54hubRtd21xxDevice|USB\VID_17EF&PID_30BF&I2C_01 +[USB\VID_17EF&PID_30BF&I2C_01] +Plugin = rts54hub +Name = HDMI Converter +Flags = updatable +FirmwareSize = 0x30000 +Rts54TargetAddr = 0x20 +Rts54I2cSpeed = 0x2 +Rts54RegisterAddrLen = 0x04 diff -Nru fwupd-1.4.5/plugins/solokey/fu-plugin-solokey.c fwupd-1.5.8/plugins/solokey/fu-plugin-solokey.c --- fwupd-1.4.5/plugins/solokey/fu-plugin-solokey.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/solokey/fu-plugin-solokey.c 2021-03-31 20:08:32.000000000 +0000 @@ -7,7 +7,6 @@ #include "config.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #include "fu-solokey-device.h" #include "fu-solokey-firmware.h" @@ -17,5 +16,5 @@ { fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_set_device_gtype (plugin, FU_TYPE_SOLOKEY_DEVICE); - fu_plugin_add_firmware_gtype (plugin, "solokey", FU_TYPE_SOLOKEY_FIRMWARE); + fu_plugin_add_firmware_gtype (plugin, NULL, FU_TYPE_SOLOKEY_FIRMWARE); } diff -Nru fwupd-1.4.5/plugins/solokey/fu-solokey-device.c fwupd-1.5.8/plugins/solokey/fu-solokey-device.c --- fwupd-1.4.5/plugins/solokey/fu-solokey-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/solokey/fu-solokey-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -63,12 +63,16 @@ } static gboolean -fu_solokey_device_open (FuUsbDevice *device, GError **error) +fu_solokey_device_open (FuDevice *device, GError **error) { - GUsbDevice *usb_device = fu_usb_device_get_dev (device); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); g_autofree gchar *product = NULL; g_auto(GStrv) split = NULL; + /* FuUsbDevice->open */ + if (!FU_DEVICE_CLASS (fu_solokey_device_parent_class)->open (device, error)) + return FALSE; + /* got the version using the HID API */ if (!g_usb_device_set_configuration (usb_device, 0x0001, error)) return FALSE; @@ -109,16 +113,16 @@ return FALSE; } if (g_strcmp0 (split[1], "Bootloader") == 0) { - fu_device_set_version_bootloader (FU_DEVICE (device), split[2]); - fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); - fu_device_remove_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER); + fu_device_set_version_bootloader (device, split[2]); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER); } else if (g_strcmp0 (split[1], "Keys") == 0 && g_strcmp0 (split[2], "Solo") == 0) { - fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); - fu_device_remove_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER); } else { - fu_device_set_version (FU_DEVICE (device), split[1]); - fu_device_remove_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); - fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER); + fu_device_set_version (device, split[1]); + fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER); } /* success */ @@ -126,9 +130,9 @@ } static gboolean -fu_solokey_device_close (FuUsbDevice *device, GError **error) +fu_solokey_device_close (FuDevice *device, GError **error) { - GUsbDevice *usb_device = fu_usb_device_get_dev (device); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); /* rebind kernel driver so it works as a security key again... */ if (!g_usb_device_release_interface (usb_device, 0x0000, @@ -138,8 +142,8 @@ return FALSE; } - /* success */ - return TRUE; + /* FuUsbDevice->close */ + return FU_DEVICE_CLASS (fu_solokey_device_parent_class)->close (device, error); } static gboolean @@ -224,6 +228,7 @@ guint8 buf_cid[4] = { 0x00 }; guint8 buf_len[2] = { 0x00 }; guint8 cmd_id = cmd | 0x80; + guint8 cmd_id_tmp = 0; guint16 first_chunk_size; g_autoptr(GByteArray) req = g_byte_array_new (); g_autoptr(GByteArray) res = NULL; @@ -270,11 +275,13 @@ SOLO_USB_HID_EP_SIZE - 5); for (guint i = 0; i < chunks->len; i++) { FuChunk *chk = g_ptr_array_index (chunks, i); - guint8 seq = chk->idx; + guint8 seq = fu_chunk_get_idx (chk); g_autoptr(GByteArray) req2 = g_byte_array_new (); g_byte_array_append (req2, buf_cid, sizeof(buf_cid)); g_byte_array_append (req2, &seq, sizeof(seq)); - g_byte_array_append (req2, chk->data, chk->data_sz); + g_byte_array_append (req2, + fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk)); if (!fu_solokey_device_packet_tx (self, req2, error)) return NULL; } @@ -296,18 +303,24 @@ return NULL; } if (memcmp (res->data + 0, buf_cid, sizeof(buf_cid)) != 0) { + guint32 cid = 0; + if (!fu_common_read_uint32_safe (res->data, res->len, 0x0, + &cid, G_BIG_ENDIAN, error)) + return NULL; g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, - "CID invalid, got %x", - fu_common_read_uint32 (res->data + 0, G_BIG_ENDIAN)); + "CID invalid, got %x", cid); return NULL; } - if (res->data[4] != cmd_id) { + if (!fu_common_read_uint8_safe (res->data, res->len, 0x4, + &cmd_id_tmp, error)) + return NULL; + if (cmd_id_tmp != cmd_id) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, - "command ID invalid, got %x", res->data[4]); + "command ID invalid, got %x", cmd_id_tmp); return NULL; } return g_steal_pointer (&res); @@ -316,6 +329,7 @@ static gboolean fu_solokey_device_setup_cid (FuSolokeyDevice *self, GError **error) { + guint16 init_len = 0; g_autoptr(GByteArray) nonce = g_byte_array_new (); g_autoptr(GByteArray) res = NULL; @@ -329,21 +343,26 @@ res = fu_solokey_device_packet (self, 0x06, nonce, error); if (res == NULL) return FALSE; - if (fu_common_read_uint16 (res->data + 5, G_LITTLE_ENDIAN) < 0x11) { + if (!fu_common_read_uint16_safe (res->data, res->len, 5, + &init_len, G_LITTLE_ENDIAN, error)) + return FALSE; + if (init_len < 0x11) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "INIT length invalid"); return FALSE; } - if (memcmp (res->data + 7, nonce->data, 8) != 0) { + if (res->len < 7 + 8 || memcmp (res->data + 7, nonce->data, 8) != 0) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "nonce invalid"); return FALSE; } - self->cid = fu_common_read_uint32 (res->data + 7 + 8, G_LITTLE_ENDIAN); + if (!fu_common_read_uint32_safe (res->data, res->len, 7 + 8, + &self->cid, G_LITTLE_ENDIAN, error)) + return FALSE; g_debug ("CID to use for device: %04x", self->cid); return TRUE; } @@ -375,7 +394,7 @@ return FALSE; /* verify version */ - if (fu_device_has_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { if (!fu_solokey_device_get_version_bl (self, error)) return FALSE; } @@ -407,7 +426,6 @@ GError **error) { g_autoptr(FuFirmware) firmware = fu_solokey_firmware_new (); - fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); if (!fu_firmware_parse (firmware, fw, flags, error)) return NULL; return g_steal_pointer (&firmware); @@ -448,8 +466,10 @@ g_autoptr(GByteArray) res = NULL; g_autoptr(GError) error_local = NULL; - g_byte_array_append (buf, chk->data, chk->data_sz); - fu_solokey_device_exchange (req, SOLO_BOOTLOADER_WRITE, chk->address, buf); + g_byte_array_append (buf, + fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk)); + fu_solokey_device_exchange (req, SOLO_BOOTLOADER_WRITE, fu_chunk_get_address (chk), buf); res = fu_solokey_device_packet (self, SOLO_BOOTLOADER_HID_CMD_BOOT, req, &error_local); if (res == NULL) { g_set_error (error, @@ -480,7 +500,7 @@ fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_set_remove_delay (FU_DEVICE (self), FU_DEVICE_REMOVE_DELAY_USER_REPLUG); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_TRIPLET); - fu_device_set_protocol (FU_DEVICE (self), "com.solokeys"); + fu_device_add_protocol (FU_DEVICE (self), "com.solokeys"); fu_device_set_name (FU_DEVICE (self), "Solo Secure"); fu_device_set_summary (FU_DEVICE (self), "An open source FIDO2 security key"); fu_device_add_icon (FU_DEVICE (self), "applications-internet"); @@ -490,10 +510,9 @@ fu_solokey_device_class_init (FuSolokeyDeviceClass *klass) { FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); klass_device->write_firmware = fu_solokey_device_write_firmware; klass_device->prepare_firmware = fu_solokey_device_prepare_firmware; klass_device->setup = fu_solokey_device_setup; - klass_usb_device->open = fu_solokey_device_open; - klass_usb_device->close = fu_solokey_device_close; + klass_device->open = fu_solokey_device_open; + klass_device->close = fu_solokey_device_close; } diff -Nru fwupd-1.4.5/plugins/solokey/fu-solokey-firmware.c fwupd-1.5.8/plugins/solokey/fu-solokey-firmware.c --- fwupd-1.4.5/plugins/solokey/fu-solokey-firmware.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/solokey/fu-solokey-firmware.c 2021-03-31 20:08:32.000000000 +0000 @@ -55,6 +55,13 @@ return FALSE; } json_root = json_parser_get_root (parser); + if (json_root == NULL || !JSON_NODE_HOLDS_OBJECT (json_root)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "JSON invalid as has no root"); + return FALSE; + } json_obj = json_node_get_object (json_root); if (!json_object_has_member (json_obj, "firmware")) { g_set_error_literal (error, @@ -73,6 +80,13 @@ /* decode */ base64 = json_object_get_string_member (json_obj, "firmware"); + if (base64 == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "JSON 'firmware' missing"); + return FALSE; + } fw_ihex = _g_base64_decode_to_bytes (base64); if (!fu_firmware_parse (ihex_firmware, fw_ihex, flags, error)) return FALSE; @@ -82,7 +96,15 @@ fu_firmware_add_image (firmware, img); /* signature */ - base64_websafe = g_string_new (json_object_get_string_member (json_obj, "signature")); + base64 = json_object_get_string_member (json_obj, "signature"); + if (base64 == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "JSON 'signature' missing"); + return FALSE; + } + base64_websafe = g_string_new (base64); fu_common_string_replace (base64_websafe, "-", "+"); fu_common_string_replace (base64_websafe, "_", "/"); g_string_append (base64_websafe, "=="); diff -Nru fwupd-1.4.5/plugins/solokey/meson.build fwupd-1.5.8/plugins/solokey/meson.build --- fwupd-1.4.5/plugins/solokey/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/solokey/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,4 @@ +if get_option('gusb') cargs = ['-DG_LOG_DOMAIN="FuPluginSoloKey"'] install_data([ @@ -10,7 +11,7 @@ fu_hash, sources : [ 'fu-solokey-device.c', - 'fu-solokey-firmware.c', + 'fu-solokey-firmware.c', # fuzzing 'fu-plugin-solokey.c', ], include_directories : [ @@ -30,3 +31,4 @@ libjsonglib, ], ) +endif diff -Nru fwupd-1.4.5/plugins/solokey/README.md fwupd-1.5.8/plugins/solokey/README.md --- fwupd-1.4.5/plugins/solokey/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/solokey/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -27,7 +27,17 @@ * `USB\VID_0483&PID_A2CA&REV_0001` * `USB\VID_0483&PID_A2CA` +Update Behavior +--------------- + +The firmware is deployed when the device is in normal runtime mode, and the +device will reset when the new firmware has been written. + Vendor ID Security ------------------ The vendor ID is set from the USB vendor, in this instance set to `USB:0x0483` + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff -Nru fwupd-1.4.5/plugins/solokey/solokey.quirk fwupd-1.5.8/plugins/solokey/solokey.quirk --- fwupd-1.4.5/plugins/solokey/solokey.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/solokey/solokey.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,4 +1,4 @@ # SoloKey1 -[DeviceInstanceId=USB\VID_0483&PID_A2CA] +[USB\VID_0483&PID_A2CA] Plugin = solokey InstallDuration = 20 diff -Nru fwupd-1.4.5/plugins/steelseries/fu-plugin-steelseries.c fwupd-1.5.8/plugins/steelseries/fu-plugin-steelseries.c --- fwupd-1.4.5/plugins/steelseries/fu-plugin-steelseries.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/steelseries/fu-plugin-steelseries.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2017 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -7,7 +7,6 @@ #include "config.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #include "fu-steelseries-device.h" diff -Nru fwupd-1.4.5/plugins/steelseries/fu-steelseries-device.c fwupd-1.5.8/plugins/steelseries/fu-steelseries-device.c --- fwupd-1.4.5/plugins/steelseries/fu-steelseries-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/steelseries/fu-steelseries-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2017 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -15,11 +15,15 @@ G_DEFINE_TYPE (FuSteelseriesDevice, fu_steelseries_device, FU_TYPE_USB_DEVICE) static gboolean -fu_steelseries_device_open (FuUsbDevice *device, GError **error) +fu_steelseries_device_open (FuDevice *device, GError **error) { - GUsbDevice *usb_device = fu_usb_device_get_dev (device); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); const guint8 iface_idx = 0x00; + /* FuUsbDevice->open */ + if (!FU_DEVICE_CLASS (fu_steelseries_device_parent_class)->open (device, error)) + return FALSE; + /* get firmware version on SteelSeries Rival 100 */ if (!g_usb_device_claim_interface (usb_device, iface_idx, G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, @@ -94,9 +98,9 @@ } static gboolean -fu_steelseries_device_close (FuUsbDevice *device, GError **error) +fu_steelseries_device_close (FuDevice *device, GError **error) { - GUsbDevice *usb_device = fu_usb_device_get_dev (device); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); const guint8 iface_idx = 0x00; /* we're done here */ @@ -107,8 +111,8 @@ return FALSE; } - /* success */ - return TRUE; + /* FuUsbDevice->close */ + return FU_DEVICE_CLASS (fu_steelseries_device_parent_class)->close (device, error); } static void @@ -121,8 +125,7 @@ fu_steelseries_device_class_init (FuSteelseriesDeviceClass *klass) { FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); klass_device->setup = fu_steelseries_device_setup; - klass_usb_device->open = fu_steelseries_device_open; - klass_usb_device->close = fu_steelseries_device_close; + klass_device->open = fu_steelseries_device_open; + klass_device->close = fu_steelseries_device_close; } diff -Nru fwupd-1.4.5/plugins/steelseries/fu-steelseries-device.h fwupd-1.5.8/plugins/steelseries/fu-steelseries-device.h --- fwupd-1.4.5/plugins/steelseries/fu-steelseries-device.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/steelseries/fu-steelseries-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2017 Richard Hughes + * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/steelseries/meson.build fwupd-1.5.8/plugins/steelseries/meson.build --- fwupd-1.4.5/plugins/steelseries/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/steelseries/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,4 @@ +if get_option('gusb') cargs = ['-DG_LOG_DOMAIN="FuPluginSteelSeries"'] install_data(['steelseries.quirk'], @@ -25,3 +26,4 @@ plugin_deps, ], ) +endif diff -Nru fwupd-1.4.5/plugins/steelseries/README.md fwupd-1.5.8/plugins/steelseries/README.md --- fwupd-1.4.5/plugins/steelseries/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/steelseries/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -21,3 +21,7 @@ ------------------ The device is not upgradable and thus requires no vendor ID set. + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff -Nru fwupd-1.4.5/plugins/steelseries/steelseries.quirk fwupd-1.5.8/plugins/steelseries/steelseries.quirk --- fwupd-1.4.5/plugins/steelseries/steelseries.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/steelseries/steelseries.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ # Rival 100 -[DeviceInstanceId=USB\VID_1038&PID_1702] +[USB\VID_1038&PID_1702] Plugin = steelseries Summary = An optical gaming mouse Icon = input-mouse diff -Nru fwupd-1.4.5/plugins/superio/fu-plugin-superio.c fwupd-1.5.8/plugins/superio/fu-plugin-superio.c --- fwupd-1.4.5/plugins/superio/fu-plugin-superio.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/superio/fu-plugin-superio.c 2021-03-31 20:08:32.000000000 +0000 @@ -7,7 +7,6 @@ #include "config.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #include "fu-superio-it85-device.h" #include "fu-superio-it89-device.h" @@ -20,58 +19,37 @@ const gchar *dmi_vendor; g_autoptr(FuSuperioDevice) dev = NULL; g_autoptr(FuDeviceLocker) locker = NULL; - g_autofree gchar *key = g_strdup_printf ("SuperIO=%s", chipset); - guint64 id; - guint64 port; - - /* get ID we need for the chipset */ - id = fu_plugin_lookup_quirk_by_id_as_uint64 (plugin, key, "Id"); - if (id == 0x0000 || id > 0xffff) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - "SuperIO chip %s has invalid Id", chipset); - return FALSE; - } - - /* set address */ - port = fu_plugin_lookup_quirk_by_id_as_uint64 (plugin, key, "Port"); - if (port == 0x0 || port > 0xffff) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - "SuperIO chip %s has invalid Port", chipset); - return FALSE; - } /* create IT89xx or IT89xx */ - if (id >> 8 == 0x85) { + if (g_strcmp0 (chipset, "IT8587") == 0) { dev = g_object_new (FU_TYPE_SUPERIO_IT85_DEVICE, "device-file", "/dev/port", "chipset", chipset, - "id", id, - "port", port, + "quirks", fu_plugin_get_quirks (plugin), NULL); - } else if (id >> 8 == 0x89) { + } else if (g_strcmp0 (chipset, "IT8987") == 0) { dev = g_object_new (FU_TYPE_SUPERIO_IT89_DEVICE, "device-file", "/dev/port", "chipset", chipset, - "id", id, - "port", port, + "quirks", fu_plugin_get_quirks (plugin), NULL); } else { g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - "SuperIO chip %s has unsupported Id", chipset); + "SuperIO chip %s has unsupported SuperioId", chipset); return FALSE; } + /* set ID and port via quirks */ + if (!fu_device_probe (FU_DEVICE (dev), error)) + return FALSE; + /* set vendor ID as the motherboard vendor */ dmi_vendor = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_BASEBOARD_MANUFACTURER); if (dmi_vendor != NULL) { g_autofree gchar *vendor_id = g_strdup_printf ("DMI:%s", dmi_vendor); - fu_device_set_vendor_id (FU_DEVICE (dev), vendor_id); + fu_device_add_vendor_id (FU_DEVICE (dev), vendor_id); } /* unlock */ @@ -83,21 +61,14 @@ return TRUE; } -static gboolean -fu_plugin_superio_coldplug_chipsets (FuPlugin *plugin, const gchar *str, GError **error) -{ - g_auto(GStrv) chipsets = g_strsplit (str, ",", -1); - for (guint i = 0; chipsets[i] != NULL; i++) { - if (!fu_plugin_superio_coldplug_chipset (plugin, chipsets[i], error)) - return FALSE; - } - return TRUE; -} - void fu_plugin_init (FuPlugin *plugin) { fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_METADATA_SOURCE, "linux_lockdown"); + fu_plugin_add_possible_quirk_key (plugin, "SuperioChipsets"); + fu_plugin_add_possible_quirk_key (plugin, "SuperioId"); + fu_plugin_add_possible_quirk_key (plugin, "SuperioPort"); } gboolean @@ -117,11 +88,11 @@ for (guint i = 0; i < hwids->len; i++) { const gchar *tmp; const gchar *guid = g_ptr_array_index (hwids, i); - g_autofree gchar *key = g_strdup_printf ("HwId=%s", guid); + g_autofree gchar *key = g_strdup_printf ("%s", guid); tmp = fu_plugin_lookup_quirk_by_id (plugin, key, FU_QUIRKS_SUPERIO_CHIPSETS); if (tmp == NULL) continue; - if (!fu_plugin_superio_coldplug_chipsets (plugin, tmp, error)) + if (!fu_plugin_superio_coldplug_chipset (plugin, tmp, error)) return FALSE; } return TRUE; diff -Nru fwupd-1.4.5/plugins/superio/fu-superio-common.h fwupd-1.5.8/plugins/superio/fu-superio-common.h --- fwupd-1.4.5/plugins/superio/fu-superio-common.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/superio/fu-superio-common.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2019 Richard Hughes + * Copyright (C) 2018 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/superio/fu-superio-device.c fwupd-1.5.8/plugins/superio/fu-superio-device.c --- fwupd-1.4.5/plugins/superio/fu-superio-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/superio/fu-superio-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -27,8 +27,6 @@ enum { PROP_0, PROP_CHIPSET, - PROP_PORT, - PROP_ID, PROP_LAST }; @@ -115,6 +113,10 @@ { FuSuperioDevice *self = FU_SUPERIO_DEVICE (device); FuSuperioDevicePrivate *priv = GET_PRIVATE (self); + + /* FuUdevDevice->to_string */ + FU_DEVICE_CLASS (fu_superio_device_parent_class)->to_string (device, idt, str); + fu_common_string_append_kv (str, idt, "Chipset", priv->chipset); fu_common_string_append_kx (str, idt, "Id", priv->id); fu_common_string_append_kx (str, idt, "Port", priv->port); @@ -122,12 +124,21 @@ fu_common_string_append_kx (str, idt, "PM1_IOBAD1", priv->pm1_iobad1); } -static guint16 +static gboolean fu_superio_device_check_id (FuSuperioDevice *self, GError **error) { FuSuperioDevicePrivate *priv = GET_PRIVATE (self); guint16 id_tmp; + /* no quirk entry */ + if (priv->id == 0x0) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "invalid SuperioId"); + return FALSE; + } + /* check ID, which can be done from any LDN */ if (!fu_superio_device_regval16 (self, SIO_LDNxx_IDX_CHIPID1, &id_tmp, error)) return FALSE; @@ -260,7 +271,6 @@ static gboolean fu_superio_device_setup (FuDevice *device, GError **error) { - FuSuperioDeviceClass *klass = FU_SUPERIO_DEVICE_GET_CLASS (device); FuSuperioDevice *self = FU_SUPERIO_DEVICE (device); FuSuperioDevicePrivate *priv = GET_PRIVATE (self); @@ -311,10 +321,6 @@ fu_common_dump_raw (G_LOG_DOMAIN, "EC Registers", buf, 0x100); } - /* subclassed setup */ - if (klass->setup != NULL) - return klass->setup (self, error); - /* success */ return TRUE; } @@ -355,12 +361,6 @@ case PROP_CHIPSET: g_value_set_string (value, priv->chipset); break; - case PROP_PORT: - g_value_set_uint (value, priv->port); - break; - case PROP_ID: - g_value_set_uint (value, priv->id); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -378,25 +378,61 @@ g_free (priv->chipset); priv->chipset = g_value_dup_string (value); break; - case PROP_PORT: - priv->port = g_value_get_uint (value); - break; - case PROP_ID: - priv->id = g_value_get_uint (value); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } +static gboolean +fu_superio_device_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + FuSuperioDevice *self = FU_SUPERIO_DEVICE (device); + FuSuperioDevicePrivate *priv = GET_PRIVATE (self); + + if (g_strcmp0 (key, "SuperioId") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp < G_MAXUINT16) { + priv->id = tmp; + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid value"); + return FALSE; + } + if (g_strcmp0 (key, "SuperioPort") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp < G_MAXUINT16) { + priv->port = tmp; + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid value"); + return FALSE; + } + + /* failed */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; +} + static void fu_superio_device_init (FuSuperioDevice *self) { fu_device_set_physical_id (FU_DEVICE (self), "/dev/port"); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE); - fu_device_set_protocol (FU_DEVICE (self), "tw.com.ite.superio"); + fu_device_add_protocol (FU_DEVICE (self), "tw.com.ite.superio"); fu_device_set_summary (FU_DEVICE (self), "Embedded Controller"); fu_device_add_icon (FU_DEVICE (self), "computer"); } @@ -422,21 +458,10 @@ G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_CHIPSET, pspec); - pspec = g_param_spec_uint ("port", NULL, NULL, - 0, G_MAXUINT, 0, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_NAME); - g_object_class_install_property (object_class, PROP_PORT, pspec); - pspec = g_param_spec_uint ("id", NULL, NULL, - 0, G_MAXUINT, 0, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_NAME); - g_object_class_install_property (object_class, PROP_ID, pspec); object_class->finalize = fu_superio_device_finalize; klass_device->to_string = fu_superio_device_to_string; + klass_device->set_quirk_kv = fu_superio_device_set_quirk_kv; klass_device->probe = fu_superio_device_probe; klass_device->setup = fu_superio_device_setup; klass_device->prepare_firmware = fu_superio_device_prepare_firmware; diff -Nru fwupd-1.4.5/plugins/superio/fu-superio-device.h fwupd-1.5.8/plugins/superio/fu-superio-device.h --- fwupd-1.4.5/plugins/superio/fu-superio-device.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/superio/fu-superio-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -14,8 +14,6 @@ struct _FuSuperioDeviceClass { FuUdevDeviceClass parent_class; - gboolean (*setup) (FuSuperioDevice *self, - GError **error); }; gboolean fu_superio_device_ec_read (FuSuperioDevice *self, diff -Nru fwupd-1.4.5/plugins/superio/fu-superio-it85-device.c fwupd-1.5.8/plugins/superio/fu-superio-it85-device.c --- fwupd-1.4.5/plugins/superio/fu-superio-it85-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/superio/fu-superio-it85-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2019 Richard Hughes + * Copyright (C) 2018 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -34,12 +34,17 @@ } static gboolean -fu_superio_it85_device_setup (FuSuperioDevice *self, GError **error) +fu_superio_it85_device_setup (FuDevice *device, GError **error) { + FuSuperioDevice *self = FU_SUPERIO_DEVICE (device); guint8 size_tmp = 0; g_autofree gchar *name = NULL; g_autofree gchar *version = NULL; + /* FuSuperioDevice->setup */ + if (!FU_DEVICE_CLASS (fu_superio_it85_device_parent_class)->setup (device, error)) + return FALSE; + /* get EC size */ if (!fu_superio_device_ec_get_param (self, 0xe5, &size_tmp, error)) { g_prefix_error (error, "failed to get EC size: "); @@ -71,6 +76,6 @@ static void fu_superio_it85_device_class_init (FuSuperioIt85DeviceClass *klass) { - FuSuperioDeviceClass *klass_superio_device = FU_SUPERIO_DEVICE_CLASS (klass); - klass_superio_device->setup = fu_superio_it85_device_setup; + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + klass_device->setup = fu_superio_it85_device_setup; } diff -Nru fwupd-1.4.5/plugins/superio/fu-superio-it85-device.h fwupd-1.5.8/plugins/superio/fu-superio-it85-device.h --- fwupd-1.4.5/plugins/superio/fu-superio-it85-device.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/superio/fu-superio-it85-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2019 Richard Hughes + * Copyright (C) 2018 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/superio/fu-superio-it89-device.c fwupd-1.5.8/plugins/superio/fu-superio-it89-device.c --- fwupd-1.4.5/plugins/superio/fu-superio-it89-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/superio/fu-superio-it89-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2019 Richard Hughes + * Copyright (C) 2018 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -90,11 +90,16 @@ } static gboolean -fu_superio_it89_device_setup (FuSuperioDevice *self, GError **error) +fu_superio_it89_device_setup (FuDevice *device, GError **error) { + FuSuperioDevice *self = FU_SUPERIO_DEVICE (device); guint8 version_tmp[2] = { 0x00 }; g_autofree gchar *version = NULL; + /* FuSuperioDevice->setup */ + if (!FU_DEVICE_CLASS (fu_superio_it89_device_parent_class)->setup (device, error)) + return FALSE; + /* try to recover this */ if (g_getenv ("FWUPD_SUPERIO_RECOVER") != NULL) { fu_device_set_firmware_size (FU_DEVICE (self), 0x20000); @@ -412,23 +417,42 @@ } /* fix signature to match SMT version */ - buf2 = g_memdup (buf, sz); + buf2 = fu_memdup_safe (buf, sz, error); + if (buf2 == NULL) + return NULL; buf2[signature_offset] = 0x7f; return g_bytes_new_take (g_steal_pointer (&buf2), sz); } -static FuFirmware * -fu_superio_it89_device_read_firmware (FuDevice *device, GError **error) +static GBytes * +fu_superio_it89_device_dump_firmware (FuDevice *device, GError **error) { FuSuperioDevice *self = FU_SUPERIO_DEVICE (device); guint64 fwsize = fu_device_get_firmware_size_min (device); - g_autoptr(GBytes) blob = NULL; - g_autoptr(GBytes) fw = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; + + /* require detach -> attach */ + locker = fu_device_locker_new_full (device, + (FuDeviceLockerFunc) fu_device_detach, + (FuDeviceLockerFunc) fu_device_attach, + error); + if (locker == NULL) + return NULL; fu_device_set_status (device, FWUPD_STATUS_DEVICE_READ); - blob = fu_superio_it89_device_read_addr (self, 0x0, fwsize, + return fu_superio_it89_device_read_addr (self, 0x0, fwsize, fu_superio_it89_device_progress_cb, error); +} + +static FuFirmware * +fu_superio_it89_device_read_firmware (FuDevice *device, GError **error) +{ + FuSuperioDevice *self = FU_SUPERIO_DEVICE (device); + g_autoptr(GBytes) blob = NULL; + g_autoptr(GBytes) fw = NULL; + + blob = fu_superio_it89_device_dump_firmware (device, error); fw = fu_plugin_superio_fix_signature (self, blob, error); return fu_firmware_new_from_bytes (fw); } @@ -483,7 +507,7 @@ fw = fu_superio_it89_device_read_addr (self, fwsize - sigsz, sigsz, NULL, error); if (fw == NULL) { - g_prefix_error (error, "failed to read signature bytes"); + g_prefix_error (error, "failed to read signature bytes: "); return FALSE; } @@ -516,18 +540,18 @@ g_autoptr(GBytes) fw3 = NULL; /* erase page */ - if (!fu_superio_it89_device_erase_addr (self, chk->address, error)) { - g_prefix_error (error, "failed to erase @0x%04x", (guint) chk->address); + if (!fu_superio_it89_device_erase_addr (self, fu_chunk_get_address (chk), error)) { + g_prefix_error (error, "failed to erase @0x%04x: ", (guint) fu_chunk_get_address (chk)); return FALSE; } /* check erased */ - fw1 = fu_superio_it89_device_read_addr (self, chk->address, - chk->data_sz, NULL, + fw1 = fu_superio_it89_device_read_addr (self, fu_chunk_get_address (chk), + fu_chunk_get_data_sz (chk), NULL, error); if (fw1 == NULL) { - g_prefix_error (error, "failed to read erased " - "bytes @0x%04x", (guint) chk->address); + g_prefix_error (error, "failed to read erased bytes @0x%04x: ", + (guint) fu_chunk_get_address (chk)); return FALSE; } if (!fu_common_bytes_is_empty (fw1)) { @@ -539,28 +563,34 @@ } /* skip empty page */ - fw2 = g_bytes_new_static (chk->data, chk->data_sz); + fw2 = g_bytes_new_static (fu_chunk_get_data (chk), fu_chunk_get_data_sz (chk)); if (fu_common_bytes_is_empty (fw2)) return TRUE; /* write page */ - if (!fu_superio_it89_device_write_addr (self, chk->address, fw2, error)) { - g_prefix_error (error, "failed to write @0x%04x", (guint) chk->address); + if (!fu_superio_it89_device_write_addr (self, + fu_chunk_get_address (chk), + fw2, + error)) { + g_prefix_error (error, "failed to write @0x%04x: ", + (guint) fu_chunk_get_address (chk)); return FALSE; } /* verify page */ - fw3 = fu_superio_it89_device_read_addr (self, chk->address, - chk->data_sz, NULL, + fw3 = fu_superio_it89_device_read_addr (self, + fu_chunk_get_address (chk), + fu_chunk_get_data_sz (chk), + NULL, error); if (fw3 == NULL) { g_prefix_error (error, "failed to read written " - "bytes @0x%04x", (guint) chk->address); + "bytes @0x%04x: ", (guint) fu_chunk_get_address (chk)); return FALSE; } if (!fu_common_bytes_compare (fw2, fw3, error)) { - g_prefix_error (error, "failed to verify @0x%04x", - (guint) chk->address); + g_prefix_error (error, "failed to verify @0x%04x: ", + (guint) fu_chunk_get_address (chk)); return FALSE; } @@ -677,10 +707,10 @@ fu_superio_it89_device_class_init (FuSuperioIt89DeviceClass *klass) { FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - FuSuperioDeviceClass *klass_superio_device = FU_SUPERIO_DEVICE_CLASS (klass); klass_device->attach = fu_superio_it89_device_attach; klass_device->detach = fu_superio_it89_device_detach; klass_device->read_firmware = fu_superio_it89_device_read_firmware; + klass_device->dump_firmware = fu_superio_it89_device_dump_firmware; klass_device->write_firmware = fu_superio_it89_device_write_firmware; - klass_superio_device->setup = fu_superio_it89_device_setup; + klass_device->setup = fu_superio_it89_device_setup; } diff -Nru fwupd-1.4.5/plugins/superio/fu-superio-it89-device.h fwupd-1.5.8/plugins/superio/fu-superio-it89-device.h --- fwupd-1.4.5/plugins/superio/fu-superio-it89-device.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/superio/fu-superio-it89-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2019 Richard Hughes + * Copyright (C) 2018 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/superio/meson.build fwupd-1.5.8/plugins/superio/meson.build --- fwupd-1.4.5/plugins/superio/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/superio/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,4 @@ +if get_option('gudev') cargs = ['-DG_LOG_DOMAIN="FuPluginSuperio"'] install_data(['superio.quirk'], @@ -29,3 +30,4 @@ plugin_deps, ], ) +endif diff -Nru fwupd-1.4.5/plugins/superio/README.md fwupd-1.5.8/plugins/superio/README.md --- fwupd-1.4.5/plugins/superio/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/superio/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -23,7 +23,19 @@ * `SuperIO-$(chipset)`, for example `SuperIO-IT8512` +Update Behavior +--------------- + +The firmware is deployed when the device is in normal runtime mode, but it is +only activated on machine reboot. The firware write is normally scheduled to be +done very early in the boot process to minimize the chance the EC chip locking +up if the user is actually using the kerboard controller. + Vendor ID Security ------------------ The vendor ID is set from the baseboard vendor, for example `DMI:Star Labs` + +External interface access +------------------------- +This plugin requires access to raw system memory via `inb`/`outb`. diff -Nru fwupd-1.4.5/plugins/superio/superio.quirk fwupd-1.5.8/plugins/superio/superio.quirk --- fwupd-1.4.5/plugins/superio/superio.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/superio/superio.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,49 +1,59 @@ # N13xWU -[HwId=992f1bc7-f8ee-567a-88dd-30e5158d72ed] +[992f1bc7-f8ee-567a-88dd-30e5158d72ed] SuperioChipsets=IT8587 # W740SU -[HwId=f00d8c4e-dce2-51c3-89d6-6cbc5fc5cdbb] +[f00d8c4e-dce2-51c3-89d6-6cbc5fc5cdbb] SuperioChipsets=IT8587 -# Star LabTop Mk3 -[HwId=3dc52d2c-9e9b-5ba5-b10d-9ba1eb11dacc] +# Star LabTop Mk III (HwId) +[013b60e5-1023-5bee-8ae5-14cae21377b7] SuperioChipsets=IT8987 InstallDuration=20 -# Star Lite Mk2 -[HwId=d1a64840-4307-58fb-a62c-de28a07c0151] +# Star LabTop Mk IV (HwId) +[baf1d04e-fd16-5e6a-93cc-1c23d171f879] SuperioChipsets=IT8987 InstallDuration=20 -[SuperIO=IT8510] -Id=0x8510 -Port=0x2e - -[SuperIO=IT8511] -Id=0x8511 -Port=0x2e - -[SuperIO=IT8512] -Id=0x8512 -Port=0x2e - -[SuperIO=IT8513] -Id=0x8513 -Port=0x2e - -[SuperIO=IT8516] -Id=0x8516 -Port=0x2e - -[SuperIO=IT8518] -Id=0x8518 -Port=0x2e - -[SuperIO=IT8587] -Id=0x8587 -Port=0x2e - -[SuperIO=IT8987] -Id=0x8987 -Port=0x4e +# Star Lite Mk II (HwId) +[013b60e5-1023-5bee-8ae5-14cae21377b7] +SuperioChipsets=IT8987 +InstallDuration=20 + +# Star Lite Mk III (HwId) +[d5521faa-c50b-5d64-971d-8fd400030c51] +SuperioChipsets=IT8987 +InstallDuration=20 + +[SuperIO-IT8510] +SuperioId=0x8510 +SuperioPort=0x2e + +[SuperIO-IT8511] +SuperioId=0x8511 +SuperioPort=0x2e + +[SuperIO-IT8512] +SuperioId=0x8512 +SuperioPort=0x2e + +[SuperIO-IT8513] +SuperioId=0x8513 +SuperioPort=0x2e + +[SuperIO-IT8516] +SuperioId=0x8516 +SuperioPort=0x2e + +[SuperIO-IT8518] +SuperioId=0x8518 +SuperioPort=0x2e + +[SuperIO-IT8587] +SuperioId=0x8587 +SuperioPort=0x2e + +[SuperIO-IT8987] +SuperioId=0x8987 +SuperioPort=0x4e diff -Nru fwupd-1.4.5/plugins/synaptics-cxaudio/fu-plugin-synaptics-cxaudio.c fwupd-1.5.8/plugins/synaptics-cxaudio/fu-plugin-synaptics-cxaudio.c --- fwupd-1.4.5/plugins/synaptics-cxaudio/fu-plugin-synaptics-cxaudio.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-cxaudio/fu-plugin-synaptics-cxaudio.c 2021-03-31 20:08:32.000000000 +0000 @@ -7,7 +7,6 @@ #include "config.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #include "fu-synaptics-cxaudio-device.h" #include "fu-synaptics-cxaudio-firmware.h" @@ -17,5 +16,9 @@ { fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_set_device_gtype (plugin, FU_TYPE_SYNAPTICS_CXAUDIO_DEVICE); - fu_plugin_add_firmware_gtype (plugin, "conexant", FU_TYPE_SYNAPTICS_CXAUDIO_FIRMWARE); + fu_plugin_add_firmware_gtype (plugin, NULL, FU_TYPE_SYNAPTICS_CXAUDIO_FIRMWARE); + fu_plugin_add_possible_quirk_key (plugin, "CxaudioChipIdBase"); + fu_plugin_add_possible_quirk_key (plugin, "CxaudioPatch1ValidAddr"); + fu_plugin_add_possible_quirk_key (plugin, "CxaudioPatch2ValidAddr"); + fu_plugin_add_possible_quirk_key (plugin, "CxaudioSoftwareReset"); } diff -Nru fwupd-1.4.5/plugins/synaptics-cxaudio/fu-synaptics-cxaudio-common.h fwupd-1.5.8/plugins/synaptics-cxaudio/fu-synaptics-cxaudio-common.h --- fwupd-1.4.5/plugins/synaptics-cxaudio/fu-synaptics-cxaudio-common.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-cxaudio/fu-synaptics-cxaudio-common.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2019 Synaptics Incorporated + * Copyright (C) 2005 Synaptics Incorporated * Copyright (C) 2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ diff -Nru fwupd-1.4.5/plugins/synaptics-cxaudio/fu-synaptics-cxaudio-device.c fwupd-1.5.8/plugins/synaptics-cxaudio/fu-synaptics-cxaudio-device.c --- fwupd-1.4.5/plugins/synaptics-cxaudio/fu-synaptics-cxaudio-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-cxaudio/fu-synaptics-cxaudio-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,6 +1,6 @@ /* - * Copyright (C) 2005-2019 Synaptics Incorporated - * Copyright (C) 2019-2020 Richard Hughes + * Copyright (C) 2005 Synaptics Incorporated + * Copyright (C) 2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -67,7 +67,7 @@ return fu_hid_device_set_report (FU_HID_DEVICE (self), buf[0], buf, bufsz, FU_SYNAPTICS_CXAUDIO_USB_TIMEOUT, - FU_HID_DEVICE_FLAG_NONE, + FU_HID_DEVICE_FLAG_RETRY_FAILURE, error); } @@ -139,9 +139,9 @@ } /* send to hardware */ - chunks = fu_chunk_array_new (buf, bufsz, addr, 0x0, payload_max); + chunks = fu_chunk_array_mutable_new (buf, bufsz, addr, 0x0, payload_max); for (guint i = 0; i < chunks->len; i++) { - FuChunk *chunk = g_ptr_array_index (chunks, i); + FuChunk *chk = g_ptr_array_index (chunks, i); guint8 inbuf[FU_SYNAPTICS_CXAUDIO_INPUT_REPORT_SIZE] = { 0 }; guint8 outbuf[FU_SYNAPTICS_CXAUDIO_OUTPUT_REPORT_SIZE] = { 0 }; @@ -149,10 +149,10 @@ outbuf[0] = FU_SYNAPTICS_CXAUDIO_MEM_WRITEID; /* set memory address and payload length (if relevant) */ - if (chunk->address >= 64 * 1024) + if (fu_chunk_get_address (chk) >= 64 * 1024) outbuf[1] |= 1 << 4; - outbuf[2] = chunk->data_sz; - fu_common_write_uint16 (outbuf + 3, chunk->address, G_BIG_ENDIAN); + outbuf[2] = fu_chunk_get_data_sz (chk); + fu_common_write_uint16 (outbuf + 3, fu_chunk_get_address (chk), G_BIG_ENDIAN); /* set memtype */ if (mem_kind == FU_SYNAPTICS_CXAUDIO_MEM_KIND_EEPROM) @@ -162,8 +162,9 @@ if (operation == FU_SYNAPTICS_CXAUDIO_OPERATION_WRITE) { outbuf[1] |= 1 << 6; if (!fu_memcpy_safe (outbuf, sizeof(outbuf), idx_write, /* dst */ - chunk->data, chunk->data_sz, 0x0, /* src */ - chunk->data_sz, error)) + fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk), 0x0, /* src */ + fu_chunk_get_data_sz (chk), error)) return FALSE; } if (!fu_synaptics_cxaudio_device_output_report (self, outbuf, sizeof(outbuf), error)) @@ -191,14 +192,15 @@ error)) { g_prefix_error (error, "failed to verify on packet %u @0x%x: ", - chunk->idx, chunk->address); + fu_chunk_get_idx (chk), fu_chunk_get_address (chk)); return FALSE; } } if (operation == FU_SYNAPTICS_CXAUDIO_OPERATION_READ) { - if (!fu_memcpy_safe ((guint8 *) chunk->data, chunk->data_sz, 0x0, /* dst */ + if (!fu_memcpy_safe (fu_chunk_get_data_out (chk), + fu_chunk_get_data_sz (chk), 0x0, /* dst */ inbuf, sizeof(inbuf), idx_read, /* src */ - chunk->data_sz, error)) + fu_chunk_get_data_sz (chk), error)) return FALSE; } } @@ -550,8 +552,6 @@ FuSynapticsCxaudioDevice *self = FU_SYNAPTICS_CXAUDIO_DEVICE (device); guint32 chip_id_base; g_autoptr(FuFirmware) firmware = fu_synaptics_cxaudio_firmware_new (); - - fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); if (!fu_firmware_parse (firmware, fw, flags, error)) return NULL; chip_id_base = fu_synaptics_cxaudio_firmware_get_devtype (FU_SYNAPTICS_CXAUDIO_FIRMWARE (firmware)); @@ -612,7 +612,7 @@ &value, sizeof(value), FU_SYNAPTICS_CXAUDIO_OPERATION_FLAG_NONE, error)) { - g_prefix_error (error, "failed to initialize layout signature "); + g_prefix_error (error, "failed to initialize layout signature: "); return FALSE; } if (!fu_synaptics_cxaudio_device_operation (self, @@ -622,7 +622,7 @@ &value, sizeof(value), FU_SYNAPTICS_CXAUDIO_OPERATION_FLAG_NONE, error)) { - g_prefix_error (error, "failed to initialize layout signature "); + g_prefix_error (error, "failed to initialize layout signature: "); return FALSE; } g_debug ("initialized layout signature"); @@ -672,7 +672,7 @@ (guint8 *) &pinfo, sizeof(pinfo), FU_SYNAPTICS_CXAUDIO_OPERATION_FLAG_NONE, error)) { - g_prefix_error (error, "failed to write empty EEPROM patch info"); + g_prefix_error (error, "failed to write empty EEPROM patch info: "); return FALSE; } g_debug ("invalidated old FW patch for CX2070x (RAM) device"); @@ -730,19 +730,19 @@ GError **error) { FuSynapticsCxaudioDevice *self = FU_SYNAPTICS_CXAUDIO_DEVICE (device); - if (g_strcmp0 (key, "ChipIdBase") == 0) { + if (g_strcmp0 (key, "CxaudioChipIdBase") == 0) { self->chip_id_base = fu_common_strtoull (value); return TRUE; } - if (g_strcmp0 (key, "IsSoftwareResetSupported") == 0) { + if (g_strcmp0 (key, "CxaudioSoftwareReset") == 0) { self->sw_reset_supported = fu_common_strtoull (value); return TRUE; } - if (g_strcmp0 (key, "EepromPatchValidAddr") == 0) { + if (g_strcmp0 (key, "CxaudioPatch1ValidAddr") == 0) { self->eeprom_patch_valid_addr = fu_common_strtoull (value); return TRUE; } - if (g_strcmp0 (key, "EepromPatch2ValidAddr") == 0) { + if (g_strcmp0 (key, "CxaudioPatch2ValidAddr") == 0) { self->eeprom_patch2_valid_addr = fu_common_strtoull (value); return TRUE; } @@ -761,7 +761,8 @@ fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_PLAIN); fu_device_set_install_duration (FU_DEVICE (self), 3); /* seconds */ - fu_device_set_protocol (FU_DEVICE (self), "com.synaptics.cxaudio"); + fu_device_add_protocol (FU_DEVICE (self), "com.synaptics.cxaudio"); + fu_device_retry_set_delay (FU_DEVICE (self), 100); /* ms */ fu_device_set_remove_delay (FU_DEVICE (self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); } diff -Nru fwupd-1.4.5/plugins/synaptics-cxaudio/fu-synaptics-cxaudio-firmware.c fwupd-1.5.8/plugins/synaptics-cxaudio/fu-synaptics-cxaudio-firmware.c --- fwupd-1.4.5/plugins/synaptics-cxaudio/fu-synaptics-cxaudio-firmware.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-cxaudio/fu-synaptics-cxaudio-firmware.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2019 Synaptics Incorporated + * Copyright (C) 2005 Synaptics Incorporated * Copyright (C) 2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ @@ -7,6 +7,8 @@ #include "config.h" +#include + #include "fu-common.h" #include "fu-synaptics-cxaudio-firmware.h" @@ -153,6 +155,13 @@ continue; if (rcd->addr > FU_SYNAPTICS_CXAUDIO_EEPROM_SHADOW_SIZE) continue; + if (rcd->buf->len == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "record 0x%x had zero size", i); + return FALSE; + } if (!fu_memcpy_safe (shadow, FU_SYNAPTICS_CXAUDIO_EEPROM_SHADOW_SIZE, rcd->addr, /* dst */ rcd->buf->data, rcd->buf->len, 0x0, /* src */ rcd->buf->len, error)) diff -Nru fwupd-1.4.5/plugins/synaptics-cxaudio/fu-synaptics-cxaudio-firmware.h fwupd-1.5.8/plugins/synaptics-cxaudio/fu-synaptics-cxaudio-firmware.h --- fwupd-1.4.5/plugins/synaptics-cxaudio/fu-synaptics-cxaudio-firmware.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-cxaudio/fu-synaptics-cxaudio-firmware.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2019 Synaptics Incorporated + * Copyright (C) 2005 Synaptics Incorporated * Copyright (C) 2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ diff -Nru fwupd-1.4.5/plugins/synaptics-cxaudio/meson.build fwupd-1.5.8/plugins/synaptics-cxaudio/meson.build --- fwupd-1.4.5/plugins/synaptics-cxaudio/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-cxaudio/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,4 @@ +if get_option('gusb') cargs = ['-DG_LOG_DOMAIN="FuPluginSynapticsCxaudio"'] install_data(['synaptics-cxaudio.quirk'], @@ -27,3 +28,4 @@ plugin_deps, ], ) +endif diff -Nru fwupd-1.4.5/plugins/synaptics-cxaudio/README.md fwupd-1.5.8/plugins/synaptics-cxaudio/README.md --- fwupd-1.4.5/plugins/synaptics-cxaudio/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-cxaudio/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -31,6 +31,12 @@ * `SYNAPTICS_CXAUDIO\CX2198X` * `SYNAPTICS_CXAUDIO\CX21985` +Update Behavior +--------------- + +The firmware is deployed when the device is in normal runtime mode, and the +device will reset when the new firmware has been written. + Vendor ID Security ------------------ @@ -43,7 +49,11 @@ | Quirk | Description | Minimum fwupd version | |----------------------------|----------------------------------|-----------------------| -| `ChipIdBase` | Base integer for ChipID | 1.3.2 | -| `IsSoftwareResetSupported` | If the chip supports self-reset | 1.3.2 | -| `EepromPatchValidAddr` | Address of patch location #1 | 1.3.2 | -| `EepromPatch2ValidAddr` | Address of patch location #2 | 1.3.2 | +| `CxaudioChipIdBase` | Base integer for ChipID | 1.3.2 | +| `CxaudioSoftwareReset` | If the chip supports self-reset | 1.3.2 | +| `CxaudioPatch1ValidAddr` | Address of patch location #1 | 1.3.2 | +| `CxaudioPatch2ValidAddr` | Address of patch location #2 | 1.3.2 | + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff -Nru fwupd-1.4.5/plugins/synaptics-cxaudio/synaptics-cxaudio.quirk fwupd-1.5.8/plugins/synaptics-cxaudio/synaptics-cxaudio.quirk --- fwupd-1.4.5/plugins/synaptics-cxaudio/synaptics-cxaudio.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-cxaudio/synaptics-cxaudio.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,32 +1,32 @@ # ThinkPad TBT3-TR Gen 2 dock -[DeviceInstanceId=USB\VID_17EF&PID_3083] +[USB\VID_17EF&PID_3083] Guid = SYNAPTICS_CXAUDIO\CX2098X -ParentGuid = TBT-01081720 +ParentGuid = USB\VID_17EF&PID_307F&HUB_0006 # ThinkPad TBT3-MS Gen 2 dock -[DeviceInstanceId=USB\VID_17EF&PID_3092] +[USB\VID_17EF&PID_3092] Guid = SYNAPTICS_CXAUDIO\CX2198X ParentGuid = USB\VID_17EF&PID_308F # ThinkPad USB-C Dock Gen2 Audio -[DeviceInstanceId=USB\VID_17EF&PID_A396] +[USB\VID_17EF&PID_A396] Guid = SYNAPTICS_CXAUDIO\CX2198X ParentGuid = USB\VID_17EF&PID_A391 # Google Pixel USB-C headphones -[DeviceInstanceId=USB\VID_18D1&PID_5033] +[USB\VID_18D1&PID_5033] Guid = SYNAPTICS_CXAUDIO\CX2198X # Google Pixel USB-C <-> 3.5mm adapter -[DeviceInstanceId=USB\VID_18D1&PID_5034] +[USB\VID_18D1&PID_5034] Guid = SYNAPTICS_CXAUDIO\CX2198X -[Guid=SYNAPTICS_CXAUDIO\CX2098X] +[SYNAPTICS_CXAUDIO\CX2098X] Plugin = synaptics_cxaudio -ChipIdBase = 20980 +CxaudioChipIdBase = 20980 -[Guid=SYNAPTICS_CXAUDIO\CX2198X] +[SYNAPTICS_CXAUDIO\CX2198X] Plugin = synaptics_cxaudio -ChipIdBase = 21980 -EepromPatchValidAddr = 0x0014 -EepromPatch2ValidAddr = 0x0171 +CxaudioChipIdBase = 21980 +CxaudioPatch1ValidAddr = 0x0014 +CxaudioPatch2ValidAddr = 0x0171 diff -Nru fwupd-1.4.5/plugins/synaptics-mst/fu-plugin-synaptics-mst.c fwupd-1.5.8/plugins/synaptics-mst/fu-plugin-synaptics-mst.c --- fwupd-1.4.5/plugins/synaptics-mst/fu-plugin-synaptics-mst.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-mst/fu-plugin-synaptics-mst.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,7 +1,7 @@ /* * Copyright (C) 2017 Mario Limonciello * Copyright (C) 2017 Peichen Huang - * Copyright (C) 2017-2019 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -9,10 +9,10 @@ #include "config.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #include "fu-synaptics-mst-common.h" #include "fu-synaptics-mst-device.h" +#include "fu-synaptics-mst-firmware.h" #define FU_SYNAPTICS_MST_DRM_REPLUG_DELAY 5 /* s */ @@ -71,7 +71,6 @@ if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_REGISTERED)) fu_plugin_device_remove (plugin, device); } else { - fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); fu_plugin_device_add (plugin, device); } } @@ -98,12 +97,14 @@ } gboolean -fu_plugin_udev_device_changed (FuPlugin *plugin, FuUdevDevice *device, GError **error) +fu_plugin_backend_device_changed (FuPlugin *plugin, FuDevice *device, GError **error) { FuPluginData *priv = fu_plugin_get_data (plugin); /* interesting device? */ - if (g_strcmp0 (fu_udev_device_get_subsystem (device), "drm") != 0) + if (!FU_IS_UDEV_DEVICE (device)) + return TRUE; + if (g_strcmp0 (fu_udev_device_get_subsystem (FU_UDEV_DEVICE (device)), "drm") != 0) return TRUE; /* recoldplug all drm_dp_aux_dev devices after a *long* delay */ @@ -116,18 +117,22 @@ } gboolean -fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **error) +fu_plugin_backend_device_added (FuPlugin *plugin, FuDevice *device, GError **error) { FuPluginData *priv = fu_plugin_get_data (plugin); g_autoptr(FuDeviceLocker) locker = NULL; g_autoptr(FuSynapticsMstDevice) dev = NULL; - dev = fu_synaptics_mst_device_new (device); + /* interesting device? */ + if (!FU_IS_UDEV_DEVICE (device)) + return TRUE; + + dev = fu_synaptics_mst_device_new (FU_UDEV_DEVICE (device)); locker = fu_device_locker_new (dev, error); if (locker == NULL) return FALSE; - /* for DeviceKind=system devices */ + /* for SynapticsMstDeviceKind=system devices */ fu_synaptics_mst_device_set_system_type (FU_SYNAPTICS_MST_DEVICE (dev), fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_PRODUCT_SKU)); @@ -171,6 +176,8 @@ fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_udev_subsystem (plugin, "drm"); /* used for uevent only */ fu_plugin_add_udev_subsystem (plugin, "drm_dp_aux_dev"); + fu_plugin_add_firmware_gtype (plugin, NULL, FU_TYPE_SYNAPTICS_MST_FIRMWARE); + fu_plugin_add_possible_quirk_key (plugin, "SynapticsMstDeviceKind"); } void diff -Nru fwupd-1.4.5/plugins/synaptics-mst/fu-self-test.c fwupd-1.5.8/plugins/synaptics-mst/fu-self-test.c --- fwupd-1.4.5/plugins/synaptics-mst/fu-self-test.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-mst/fu-self-test.c 2021-03-31 20:08:32.000000000 +0000 @@ -42,7 +42,7 @@ "device-file", fn, NULL); g_debug ("creating drm_dp_aux_dev object backed by %s", fn); - ret = fu_plugin_runner_udev_device_added (plugin, dev, &error); + ret = fu_plugin_runner_backend_device_added (plugin, FU_DEVICE (dev), &error); g_assert_no_error (error); g_assert (ret); } @@ -53,15 +53,17 @@ fu_plugin_synaptics_mst_none_func (void) { gboolean ret; + const gchar *ci = g_getenv ("CI_NETWORK"); g_autoptr(FuPlugin) plugin = fu_plugin_new (); g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); g_autofree gchar *pluginfn = NULL; + g_autofree gchar *filename = NULL; g_signal_connect (plugin, "device-added", G_CALLBACK (_plugin_device_added_cb), &devices); - pluginfn = g_build_filename (PLUGINBUILDDIR, + pluginfn = g_test_build_filename (G_TEST_BUILT, "libfu_plugin_synaptics_mst." G_MODULE_SUFFIX, NULL); ret = fu_plugin_open (plugin, pluginfn, &error); @@ -75,7 +77,12 @@ g_assert_no_error (error); g_assert (ret); - _test_add_fake_devices_from_dir (plugin, SOURCEDIR "/tests/no_devices"); + filename = g_test_build_filename (G_TEST_DIST, "tests", "no_devices", NULL); + if (!g_file_test (filename, G_FILE_TEST_EXISTS) && ci == NULL) { + g_test_skip ("Missing no_devices"); + return; + } + _test_add_fake_devices_from_dir (plugin, filename); g_assert_cmpint (devices->len, ==, 0); } @@ -84,15 +91,17 @@ fu_plugin_synaptics_mst_tb16_func (void) { gboolean ret; + const gchar *ci = g_getenv ("CI_NETWORK"); g_autoptr(FuPlugin) plugin = fu_plugin_new (); g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); g_autofree gchar *pluginfn = NULL; + g_autofree gchar *filename = NULL; g_signal_connect (plugin, "device-added", G_CALLBACK (_plugin_device_added_cb), &devices); - pluginfn = g_build_filename (PLUGINBUILDDIR, + pluginfn = g_test_build_filename (G_TEST_BUILT, "libfu_plugin_synaptics_mst." G_MODULE_SUFFIX, NULL); ret = fu_plugin_open (plugin, pluginfn, &error); @@ -106,7 +115,12 @@ g_assert_no_error (error); g_assert (ret); - _test_add_fake_devices_from_dir (plugin, SOURCEDIR "/tests/tb16_dock"); + filename = g_test_build_filename (G_TEST_DIST, "tests", "tb16_dock", NULL); + if (!g_file_test (filename, G_FILE_TEST_EXISTS) && ci == NULL) { + g_test_skip ("Missing tb16_dock"); + return; + } + _test_add_fake_devices_from_dir (plugin, filename); for (guint i = 0; i < devices->len; i++) { FuDevice *device = g_ptr_array_index (devices, i); g_autofree gchar *tmp = fu_device_to_string (device); diff -Nru fwupd-1.4.5/plugins/synaptics-mst/fu-synaptics-mst-connection.c fwupd-1.5.8/plugins/synaptics-mst/fu-synaptics-mst-connection.c --- fwupd-1.4.5/plugins/synaptics-mst/fu-synaptics-mst-connection.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-mst/fu-synaptics-mst-connection.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2017 Richard Hughes + * Copyright (C) 2015 Richard Hughes * Copyright (C) 2016 Mario Limonciello * Copyright (C) 2017 Peichen Huang * diff -Nru fwupd-1.4.5/plugins/synaptics-mst/fu-synaptics-mst-device.c fwupd-1.5.8/plugins/synaptics-mst/fu-synaptics-mst-device.c --- fwupd-1.4.5/plugins/synaptics-mst/fu-synaptics-mst-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-mst/fu-synaptics-mst-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2019 Richard Hughes + * Copyright (C) 2015 Richard Hughes * Copyright (C) 2016 Mario Limonciello * Copyright (C) 2017 Peichen Huang * Copyright (C) 2018 Ryan Chang @@ -14,6 +14,7 @@ #include "fu-synaptics-mst-common.h" #include "fu-synaptics-mst-connection.h" #include "fu-synaptics-mst-device.h" +#include "fu-synaptics-mst-firmware.h" #define FU_SYNAPTICS_MST_ID_CTRL_SIZE 0x1000 #define SYNAPTICS_UPDATE_ENUMERATE_TRIES 3 @@ -42,6 +43,7 @@ struct _FuSynapticsMstDevice { FuUdevDevice parent_instance; + gchar *device_kind; gchar *system_type; guint64 write_block_size; FuSynapticsMstFamily family; @@ -60,6 +62,7 @@ { FuSynapticsMstDevice *self = FU_SYNAPTICS_MST_DEVICE (object); + g_free (self->device_kind); g_free (self->system_type); G_OBJECT_CLASS (fu_synaptics_mst_device_parent_class)->finalize (object); @@ -68,9 +71,9 @@ static void fu_synaptics_mst_device_init (FuSynapticsMstDevice *self) { - fu_device_set_protocol (FU_DEVICE (self), "com.synaptics.mst"); + fu_device_add_protocol (FU_DEVICE (self), "com.synaptics.mst"); fu_device_set_vendor (FU_DEVICE (self), "Synaptics"); - fu_device_set_vendor_id (FU_DEVICE (self), "DRM_DP_AUX_DEV:0x06CB"); + fu_device_add_vendor_id (FU_DEVICE (self), "DRM_DP_AUX_DEV:0x06CB"); fu_device_set_summary (FU_DEVICE (self), "Multi-Stream Transport Device"); fu_device_add_icon (FU_DEVICE (self), "video-display"); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_TRIPLET); @@ -84,6 +87,11 @@ fu_synaptics_mst_device_to_string (FuDevice *device, guint idt, GString *str) { FuSynapticsMstDevice *self = FU_SYNAPTICS_MST_DEVICE (device); + + /* FuUdevDevice->to_string */ + FU_DEVICE_CLASS (fu_synaptics_mst_device_parent_class)->to_string (device, idt, str); + + fu_common_string_append_kv (str, idt, "DeviceKind", self->device_kind); if (self->mode != FU_SYNAPTICS_MST_MODE_UNKNOWN) { fu_common_string_append_kv (str, idt, "Mode", fu_synaptics_mst_mode_to_string (self->mode)); @@ -127,14 +135,19 @@ } static gboolean -fu_synaptics_mst_device_probe (FuUdevDevice *device, GError **error) +fu_synaptics_mst_device_probe (FuDevice *device, GError **error) { - g_autofree gchar *logical_id = NULL; - logical_id = g_path_get_basename (fu_udev_device_get_sysfs_path(device)); - fu_device_set_logical_id (FU_DEVICE (device), logical_id); - if (!fu_udev_device_set_physical_id (device, "pci,drm_dp_aux_dev", error)) + /* FuUdevDevice->probe */ + if (!FU_DEVICE_CLASS (fu_synaptics_mst_device_parent_class)->probe (device, error)) return FALSE; - return TRUE; + + /* get from sysfs if not set from tests */ + if (fu_device_get_logical_id (device) == NULL) { + g_autofree gchar *logical_id = NULL; + logical_id = g_path_get_basename (fu_udev_device_get_sysfs_path (FU_UDEV_DEVICE (device))); + fu_device_set_logical_id (device, logical_id); + } + return fu_udev_device_set_physical_id (FU_UDEV_DEVICE (device), "pci,drm_dp_aux_dev", error); } static gboolean @@ -235,7 +248,7 @@ UPDC_FLASH_ERASE, 2, 0, (guint8 *)&us_data, error)) { - g_prefix_error (error, "can't sector erase flash at offset %x", + g_prefix_error (error, "can't sector erase flash at offset %x: ", offset); return FALSE; } @@ -774,16 +787,14 @@ GError **error) { FuSynapticsMstDevice *self = FU_SYNAPTICS_MST_DEVICE (device); + g_autoptr(FuFirmware) firmware = fu_synaptics_mst_firmware_new (); /* check firmware and board ID match */ - if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0 && + if (!fu_firmware_parse (firmware, fw, flags, error)) + return NULL; + if ((flags & FWUPD_INSTALL_FLAG_IGNORE_VID_PID) == 0 && !fu_device_has_custom_flag (device, "ignore-board-id")) { - const guint8 *buf; - gsize len; - guint16 board_id; - - buf = g_bytes_get_data (fw, &len); - board_id = fu_common_read_uint16 (buf + ADDR_CUSTOMER_ID, G_BIG_ENDIAN); + guint16 board_id = fu_synaptics_mst_firmware_get_board_id (FU_SYNAPTICS_MST_FIRMWARE (firmware)); if (board_id != self->board_id) { g_set_error (error, G_IO_ERROR, @@ -859,7 +870,10 @@ return FALSE; } } + + /* wait for flash clear to settle */ fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + fu_device_sleep_with_progress (device, 2); return TRUE; } @@ -987,20 +1001,17 @@ fu_synaptics_mst_device_rescan (FuDevice *device, GError **error) { FuSynapticsMstDevice *self = FU_SYNAPTICS_MST_DEVICE (device); - FuQuirks *quirks; guint8 buf_vid[4]; g_autoptr(FuSynapticsMstConnection) connection = NULL; g_autoptr(FuDeviceLocker) locker = NULL; g_autofree gchar *version = NULL; + g_autofree gchar *guid0 = NULL; g_autofree gchar *guid1 = NULL; g_autofree gchar *guid2 = NULL; g_autofree gchar *guid3 = NULL; - g_autofree gchar *group = NULL; g_autofree gchar *name = NULL; - const gchar *guid_template; const gchar *name_parent; const gchar *name_family; - const gchar *plugin; guint8 buf_ver[16]; /* read vendor ID */ @@ -1081,10 +1092,10 @@ if (!fu_synaptics_mst_device_scan_cascade (self, 0, error)) return FALSE; - /* set up the device name via quirks */ - group = g_strdup_printf ("SynapticsMSTBoardID=%u", self->board_id); - quirks = fu_device_get_quirks (FU_DEVICE (self)); - name_parent = fu_quirks_lookup_by_id (quirks, group, FU_QUIRKS_NAME); + /* set up the device name and kind via quirks */ + guid0 = g_strdup_printf ("MST-%u", self->board_id); + fu_device_add_instance_id (FU_DEVICE (self), guid0); + name_parent = fu_device_get_name (FU_DEVICE (self)); if (name_parent != NULL) { name = g_strdup_printf ("VMM%04x inside %s", self->chip_id, name_parent); @@ -1093,20 +1104,9 @@ } fu_device_set_name (FU_DEVICE (self), name); - plugin = fu_quirks_lookup_by_id (quirks, group, FU_QUIRKS_PLUGIN); - if (plugin != NULL && g_strcmp0 (plugin, "synaptics_mst") != 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "%s is only supported by %s", - name, plugin); - return FALSE; - } - /* this is a host system, use system ID */ - guid_template = fu_quirks_lookup_by_id (quirks, group, "DeviceKind"); name_family = fu_synaptics_mst_family_to_string (self->family); - if (g_strcmp0 (guid_template, "system") == 0) { + if (g_strcmp0 (self->device_kind, "system") == 0) { g_autofree gchar *guid = NULL; guid = g_strdup_printf ("MST-%s-%s-%u", name_family, @@ -1115,9 +1115,9 @@ fu_device_add_instance_id (FU_DEVICE (self), guid); /* docks or something else */ - } else if (guid_template != NULL) { + } else if (self->device_kind != NULL) { g_auto(GStrv) templates = NULL; - templates = g_strsplit (guid_template, ",", -1); + templates = g_strsplit (self->device_kind, ",", -1); for (guint i = 0; templates[i] != NULL; i++) { g_autofree gchar *dock_id1 = NULL; g_autofree gchar *dock_id2 = NULL; @@ -1166,20 +1166,44 @@ guid3 = g_strdup_printf ("MST-%s", name_family); fu_device_add_instance_id (FU_DEVICE (self), guid3); - /* success */ + /* this is not a valid customer ID */ + if ((self->board_id >> 8) == 0x0) { + fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_set_update_error (device, "cannot update as CustomerID is unset"); + } else { + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + } return TRUE; } +static gboolean +fu_synaptics_mst_device_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + FuSynapticsMstDevice *self = FU_SYNAPTICS_MST_DEVICE (device); + if (g_strcmp0 (key, "SynapticsMstDeviceKind") == 0) { + self->device_kind = g_strdup (value); + return TRUE; + } + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; +} + static void fu_synaptics_mst_device_class_init (FuSynapticsMstDeviceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - FuUdevDeviceClass *klass_udev_device = FU_UDEV_DEVICE_CLASS (klass); object_class->finalize = fu_synaptics_mst_device_finalize; klass_device->to_string = fu_synaptics_mst_device_to_string; + klass_device->set_quirk_kv = fu_synaptics_mst_device_set_quirk_kv; klass_device->rescan = fu_synaptics_mst_device_rescan; klass_device->write_firmware = fu_synaptics_mst_device_write_firmware; klass_device->prepare_firmware = fu_synaptics_mst_device_prepare_firmware; - klass_udev_device->probe = fu_synaptics_mst_device_probe; + klass_device->probe = fu_synaptics_mst_device_probe; } diff -Nru fwupd-1.4.5/plugins/synaptics-mst/fu-synaptics-mst-firmware.c fwupd-1.5.8/plugins/synaptics-mst/fu-synaptics-mst-firmware.c --- fwupd-1.4.5/plugins/synaptics-mst/fu-synaptics-mst-firmware.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-mst/fu-synaptics-mst-firmware.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2021 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-common.h" + +#include "fu-synaptics-mst-connection.h" +#include "fu-synaptics-mst-firmware.h" + +struct _FuSynapticsMstFirmware { + FuFirmwareClass parent_instance; + guint16 board_id; +}; + +G_DEFINE_TYPE (FuSynapticsMstFirmware, fu_synaptics_mst_firmware, FU_TYPE_FIRMWARE) + +guint16 +fu_synaptics_mst_firmware_get_board_id (FuSynapticsMstFirmware *self) +{ + g_return_val_if_fail (FU_IS_SYNAPTICS_MST_FIRMWARE (self), 0); + return self->board_id; +} + +static void +fu_synaptics_mst_firmware_to_string (FuFirmware *firmware, guint idt, GString *str) +{ + FuSynapticsMstFirmware *self = FU_SYNAPTICS_MST_FIRMWARE (firmware); + fu_common_string_append_kx (str, idt, "BoardId", self->board_id); +} + +static gboolean +fu_synaptics_mst_firmware_parse (FuFirmware *firmware, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error) +{ + FuSynapticsMstFirmware *self = FU_SYNAPTICS_MST_FIRMWARE (firmware); + const guint8 *buf; + gsize bufsz; + g_autoptr(FuFirmwareImage) img = fu_firmware_image_new (fw); + buf = g_bytes_get_data (fw, &bufsz); + if (!fu_common_read_uint16_safe (buf, bufsz, ADDR_CUSTOMER_ID, + &self->board_id, G_BIG_ENDIAN, + error)) + return FALSE; + fu_firmware_add_image (firmware, img); + return TRUE; +} + +static void +fu_synaptics_mst_firmware_init (FuSynapticsMstFirmware *self) +{ +} + +static void +fu_synaptics_mst_firmware_class_init (FuSynapticsMstFirmwareClass *klass) +{ + FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); + klass_firmware->parse = fu_synaptics_mst_firmware_parse; + klass_firmware->to_string = fu_synaptics_mst_firmware_to_string; +} + +FuFirmware * +fu_synaptics_mst_firmware_new (void) +{ + return FU_FIRMWARE (g_object_new (FU_TYPE_SYNAPTICS_MST_FIRMWARE, NULL)); +} diff -Nru fwupd-1.4.5/plugins/synaptics-mst/fu-synaptics-mst-firmware.h fwupd-1.5.8/plugins/synaptics-mst/fu-synaptics-mst-firmware.h --- fwupd-1.4.5/plugins/synaptics-mst/fu-synaptics-mst-firmware.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-mst/fu-synaptics-mst-firmware.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2021 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-firmware.h" + +#define FU_TYPE_SYNAPTICS_MST_FIRMWARE (fu_synaptics_mst_firmware_get_type ()) +G_DECLARE_FINAL_TYPE (FuSynapticsMstFirmware, fu_synaptics_mst_firmware, FU, SYNAPTICS_MST_FIRMWARE, FuFirmware) + +FuFirmware *fu_synaptics_mst_firmware_new (void); +guint16 fu_synaptics_mst_firmware_get_board_id (FuSynapticsMstFirmware *self); diff -Nru fwupd-1.4.5/plugins/synaptics-mst/meson.build fwupd-1.5.8/plugins/synaptics-mst/meson.build --- fwupd-1.4.5/plugins/synaptics-mst/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-mst/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,7 @@ +if get_option('plugin_synaptics_mst') +if not get_option('gudev') + error('gudev is required for plugin_synaptics_mst') +endif cargs = ['-DG_LOG_DOMAIN="FuPluginSynapticsMST"'] install_data(['synaptics-mst.quirk'], @@ -11,6 +15,7 @@ 'fu-synaptics-mst-common.c', 'fu-synaptics-mst-connection.c', 'fu-synaptics-mst-device.c', + 'fu-synaptics-mst-firmware.c', # fuzzing ], include_directories : [ root_incdir, @@ -32,8 +37,10 @@ ) if get_option('tests') - cargs += '-DPLUGINBUILDDIR="' + meson.current_build_dir() + '"' - cargs += '-DSOURCEDIR="' + meson.current_source_dir() + '"' + testdatadirs = environment() + testdatadirs.set('G_TEST_SRCDIR', meson.current_source_dir()) + testdatadirs.set('G_TEST_BUILDDIR', meson.current_build_dir()) + testdatadirs.set('FWUPD_LOCALSTATEDIR', '/tmp/fwupd-self-test/var') e = executable( 'synaptics-mst-self-test', fu_hash, @@ -42,6 +49,7 @@ 'fu-synaptics-mst-common.c', 'fu-synaptics-mst-connection.c', 'fu-synaptics-mst-device.c', + 'fu-synaptics-mst-firmware.c', ], include_directories : [ root_incdir, @@ -60,7 +68,9 @@ c_args : [ cargs, ], + install : true, + install_dir : installed_test_bindir, ) - test('synaptics-mst-self-test', e, - env: ['FWUPD_LOCALSTATEDIR=/tmp/fwupd-self-test/var']) + test('synaptics-mst-self-test', e, env: testdatadirs) +endif endif diff -Nru fwupd-1.4.5/plugins/synaptics-mst/README.md fwupd-1.5.8/plugins/synaptics-mst/README.md --- fwupd-1.4.5/plugins/synaptics-mst/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-mst/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -18,6 +18,7 @@ These devices use custom GUID values, e.g. + * `MST-$(board-ID)` * `MST-$(device_kind)-$(chip-ID)-$(board-ID)` * `MST-$(device_kind)-$(board-ID)` * `MST-$(device_kind)` @@ -25,6 +26,13 @@ Please refer to the plugin source for more details about how the GUID is constructed for specific hardware. +Update Behavior +--------------- + +The firmware is deployed when the device is in normal runtime mode, and the +device will reset when the new firmware has been written. On some hardware the +MST device may not enumerate if there is no monitor actually plugged in. + Vendor ID Security ------------------ @@ -84,3 +92,7 @@ * Latitude Rugged 5414 * Latitude Rugged 7214 * Latitude Rugged 7414 + +External interface access +------------------------- +This plugin requires read/write access to `/dev/drm_dp_aux*`. diff -Nru fwupd-1.4.5/plugins/synaptics-mst/synaptics-mst-evb.quirk fwupd-1.5.8/plugins/synaptics-mst/synaptics-mst-evb.quirk --- fwupd-1.4.5/plugins/synaptics-mst/synaptics-mst-evb.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-mst/synaptics-mst-evb.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -10,9 +10,9 @@ # during flashing. This shouldn't be used in practice for production boards. # -[SynapticsMSTBoardID=2] +[MST-2] Name = Synaptics EVB development board -DeviceKind = panamera_evb +SynapticsMstDeviceKind = panamera_evb -[Guid=MST-panamera_evb-vmm5331-2] +[MST-panamera_evb-vmm5331-2] Flags = ignore-board-id diff -Nru fwupd-1.4.5/plugins/synaptics-mst/synaptics-mst.quirk fwupd-1.5.8/plugins/synaptics-mst/synaptics-mst.quirk --- fwupd-1.4.5/plugins/synaptics-mst/synaptics-mst.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-mst/synaptics-mst.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,17 +1,17 @@ # match all devices with this udev subsystem -[DeviceInstanceId=DRM_DP_AUX_DEV] +[DRM_DP_AUX_DEV] Plugin = synaptics_mst # GUID generation for Synaptics MST plugin # -# SynapticsMSTBoardID is the 16 bit board ID which contains: +# SYNAPTICSMST\BID is the 16 bit board ID which contains: # * Customer ID in first byte # * Board ID in the second byte # -# DeviceKind = system +# SynapticsMstDeviceKind = system # * Will map to a GUID containing HwID product SKU # * These GUIDs will look like MST-${PRODUCTSKU}-${BOARDID} -# DeviceKind != system +# SynapticsMstDeviceKind != system # * Will map to a GUID containing each comma delimited substring # * These GUIDs will look like MST-${DEVICEKIND}-${CHIPID}-${BOARDID} # @@ -19,33 +19,36 @@ # To override this behavior add FWUPD_DEVICE_FLAG_SKIPS_RESTART # -[SynapticsMSTBoardID=272] +[MST-272] Name = Dell X6 Platform -DeviceKind = system +SynapticsMstDeviceKind = system -[SynapticsMSTBoardID=273] +[MST-273] Name = Dell X7 Platform -DeviceKind = system +SynapticsMstDeviceKind = system -[SynapticsMSTBoardID=274] +[MST-274] Name = Dell WD15/TB16/TB18 wired Dock -DeviceKind = wd15,tb16,tb18 +SynapticsMstDeviceKind = wd15,tb16,tb18 -[SynapticsMSTBoardID=275] +[MST-275] Name = Dell WLD15 Wireless Dock -DeviceKind = wld15 +SynapticsMstDeviceKind = wld15 -[SynapticsMSTBoardID=277] +[MST-277] Name = Dell Rugged Platform -DeviceKind = system +SynapticsMstDeviceKind = system # ThinkPad Workstation Dock -[DeviceInstanceId=MST-tesla-vmm2322-513] +[MST-tesla-vmm2322-513] ParentGuid = USB\VID_17EF&PID_305A # ThinkPad Thunderbolt 3 Workstation Dock -[DeviceInstanceId=MST-panamera-vmm5322-595] +[MST-panamera-vmm5322-595] ParentGuid = TBT-01081720 -[SynapticsMSTBoardID=596] +[MST-596] +Name = ThinkPad USB-C Dock Gen2 + +[MST-596] Name = ThinkPad USB-C Dock Gen2 Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/synaptics-mst/tests/no_devices/drm_dp_aux0 and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/synaptics-mst/tests/no_devices/drm_dp_aux0 differ Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/synaptics-mst/tests/tb16_dock/drm_dp_aux0 and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/synaptics-mst/tests/tb16_dock/drm_dp_aux0 differ Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/synaptics-mst/tests/tb16_dock/drm_dp_aux1 and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/synaptics-mst/tests/tb16_dock/drm_dp_aux1 differ Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/synaptics-mst/tests/tb16_dock/drm_dp_aux2 and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/synaptics-mst/tests/tb16_dock/drm_dp_aux2 differ Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/synaptics-mst/tests/tb16_dock/remote/drm_dp_aux0 and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/synaptics-mst/tests/tb16_dock/remote/drm_dp_aux0 differ Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/synaptics-mst/tests/tb16_dock/remote/drm_dp_aux1 and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/synaptics-mst/tests/tb16_dock/remote/drm_dp_aux1 differ diff -Nru fwupd-1.4.5/plugins/synaptics-mst/tests/tb16_dock/remote/drm_dp_aux1_eeprom fwupd-1.5.8/plugins/synaptics-mst/tests/tb16_dock/remote/drm_dp_aux1_eeprom --- fwupd-1.4.5/plugins/synaptics-mst/tests/tb16_dock/remote/drm_dp_aux1_eeprom 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-mst/tests/tb16_dock/remote/drm_dp_aux1_eeprom 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ - \ No newline at end of file Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/synaptics-mst/tests/tb16_dock/remote/drm_dp_aux2 and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/synaptics-mst/tests/tb16_dock/remote/drm_dp_aux2 differ diff -Nru fwupd-1.4.5/plugins/synaptics-mst/tests/tb16_dock/remote/drm_dp_aux2_eeprom fwupd-1.5.8/plugins/synaptics-mst/tests/tb16_dock/remote/drm_dp_aux2_eeprom --- fwupd-1.4.5/plugins/synaptics-mst/tests/tb16_dock/remote/drm_dp_aux2_eeprom 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-mst/tests/tb16_dock/remote/drm_dp_aux2_eeprom 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ - \ No newline at end of file Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/synaptics-prometheus/data/test.pkg and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/synaptics-prometheus/data/test.pkg differ diff -Nru fwupd-1.4.5/plugins/synaptics-prometheus/fu-dump.c fwupd-1.5.8/plugins/synaptics-prometheus/fu-dump.c --- fwupd-1.4.5/plugins/synaptics-prometheus/fu-dump.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-prometheus/fu-dump.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2019 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include "fu-synaprom-firmware.h" - -static gboolean -fu_dump_parse (const gchar *filename, GError **error) -{ - gchar *data = NULL; - gsize len = 0; - g_autoptr(GBytes) blob = NULL; - g_autoptr(FuFirmware) firmware = fu_synaprom_firmware_new (); - if (!g_file_get_contents (filename, &data, &len, error)) - return FALSE; - blob = g_bytes_new_take (data, len); - return fu_firmware_parse (firmware, blob, 0, error); -} - -static gboolean -fu_dump_generate (const gchar *filename, GError **error) -{ - const gchar *data; - gsize len = 0; - g_autoptr(GBytes) blob = NULL; - g_autoptr(FuFirmware) firmware = fu_synaprom_firmware_new (); - blob = fu_firmware_write (firmware, error); - if (blob == NULL) - return FALSE; - data = g_bytes_get_data (blob, &len); - return g_file_set_contents (filename, data, len, error); -} - -int -main (int argc, char **argv) -{ - g_autoptr(GError) error = NULL; - if (argc == 2) { - if (!fu_dump_parse (argv[1], &error)) { - g_printerr ("parse failed: %s\n", error->message); - return 1; - } - } else if (argc == 3 && g_strcmp0 (argv[2], "gen") == 0) { - if (!fu_dump_generate (argv[1], &error)) { - g_printerr ("generate failed: %s\n", error->message); - return 1; - } - } else { - g_printerr ("firmware filename required\n"); - return 2; - } - g_print ("OK!\n"); - return 0; -} diff -Nru fwupd-1.4.5/plugins/synaptics-prometheus/fu-plugin-synaptics-prometheus.c fwupd-1.5.8/plugins/synaptics-prometheus/fu-plugin-synaptics-prometheus.c --- fwupd-1.4.5/plugins/synaptics-prometheus/fu-plugin-synaptics-prometheus.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-prometheus/fu-plugin-synaptics-prometheus.c 2021-03-31 20:08:32.000000000 +0000 @@ -10,12 +10,11 @@ #include "fu-synaprom-firmware.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" void fu_plugin_init (FuPlugin *plugin) { fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_set_device_gtype (plugin, FU_TYPE_SYNAPROM_DEVICE); - fu_plugin_add_firmware_gtype (plugin, "synaprom", FU_TYPE_SYNAPROM_FIRMWARE); + fu_plugin_add_firmware_gtype (plugin, NULL, FU_TYPE_SYNAPROM_FIRMWARE); } diff -Nru fwupd-1.4.5/plugins/synaptics-prometheus/fu-self-test.c fwupd-1.5.8/plugins/synaptics-prometheus/fu-self-test.c --- fwupd-1.4.5/plugins/synaptics-prometheus/fu-self-test.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-prometheus/fu-self-test.c 2021-03-31 20:08:32.000000000 +0000 @@ -16,6 +16,7 @@ static void fu_test_synaprom_firmware_func (void) { + const gchar *ci = g_getenv ("CI_NETWORK"); const guint8 *buf; gboolean ret; gsize sz = 0; @@ -28,7 +29,11 @@ g_autoptr(FuFirmware) firmware2 = NULL; g_autoptr(FuFirmware) firmware = fu_synaprom_firmware_new (); - filename = g_build_filename (TESTDATADIR, "test.pkg", NULL); + filename = g_test_build_filename (G_TEST_DIST, "tests", "test.pkg", NULL); + if (!g_file_test (filename, G_FILE_TEST_EXISTS) && ci == NULL) { + g_test_skip ("Missing test.pkg"); + return; + } fw = fu_common_get_contents_bytes (filename, &error); g_assert_no_error (error); g_assert_nonnull (fw); diff -Nru fwupd-1.4.5/plugins/synaptics-prometheus/fu-synaprom-common.c fwupd-1.5.8/plugins/synaptics-prometheus/fu-synaprom-common.c --- fwupd-1.4.5/plugins/synaptics-prometheus/fu-synaprom-common.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-prometheus/fu-synaprom-common.c 2021-03-31 20:08:32.000000000 +0000 @@ -41,7 +41,7 @@ fu_synaprom_reply_new (gsize cmdlen) { GByteArray *blob = g_byte_array_new (); - g_byte_array_set_size (blob, cmdlen); + fu_byte_array_set_size (blob, cmdlen); return blob; } diff -Nru fwupd-1.4.5/plugins/synaptics-prometheus/fu-synaprom-config.c fwupd-1.5.8/plugins/synaptics-prometheus/fu-synaprom-config.c --- fwupd-1.4.5/plugins/synaptics-prometheus/fu-synaprom-config.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-prometheus/fu-synaprom-config.c 2021-03-31 20:08:32.000000000 +0000 @@ -48,6 +48,15 @@ guint16 unused[3]; } FuSynapromIotaConfigVersion; +/* le */ +typedef struct __attribute__((packed)) { + guint32 product; + guint32 id1; /* verification ID */ + guint32 id2; /* verification ID */ + guint16 version; /* config version */ + guint8 unused[2]; +} FuSynapromFirmwareCfgHeader; + #define FU_SYNAPROM_CMD_IOTA_FIND_FLAGS_ALLIOTAS 0x0001 /* itype ignored*/ #define FU_SYNAPROM_CMD_IOTA_FIND_FLAGS_READMAX 0x0002 /* nbytes ignored */ #define FU_SYNAPROM_MAX_IOTA_READ_SIZE (64 * 1024) /* max size of iota data returned */ @@ -67,6 +76,7 @@ g_autofree gchar *version = NULL; g_autoptr(GByteArray) reply = NULL; g_autoptr(GByteArray) request = NULL; + g_autofree gchar *devid = NULL; /* get IOTA */ cmd.itype = GUINT16_TO_LE((guint16)FU_SYNAPROM_IOTA_ITYPE_CONFIG_VERSION); @@ -103,6 +113,13 @@ self->configid1, self->configid2, GUINT16_FROM_LE(cfg.version)); + /* append the configid to the generated GUID */ + devid = g_strdup_printf ("USB\\VID_%04X&PID_%04X&CFG1_%u&CFG2_%u", + fu_usb_device_get_vid (FU_USB_DEVICE (parent)), + fu_usb_device_get_pid (FU_USB_DEVICE (parent)), + self->configid1, self->configid2); + fu_device_add_instance_id (FU_DEVICE (self), devid); + /* no downgrades are allowed */ version = g_strdup_printf ("%04u", GUINT16_FROM_LE(cfg.version)); fu_device_set_version (FU_DEVICE (self), version); @@ -122,9 +139,9 @@ g_autoptr(FuFirmware) firmware = fu_synaprom_firmware_new (); guint32 product; guint32 id1; + guint32 id2; /* parse the firmware */ - fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); if (!fu_firmware_parse (firmware, fw, flags, error)) return NULL; @@ -142,7 +159,7 @@ memcpy (&hdr, g_bytes_get_data (blob, NULL), sizeof(hdr)); product = GUINT32_FROM_LE(hdr.product); if (product != FU_SYNAPROM_PRODUCT_PROMETHEUS) { - if (flags & FWUPD_INSTALL_FLAG_FORCE) { + if (flags & FWUPD_INSTALL_FLAG_IGNORE_VID_PID) { g_warning ("CFG metadata not compatible, " "got 0x%02x expected 0x%02x", product, (guint) FU_SYNAPROM_PRODUCT_PROMETHEUS); @@ -157,18 +174,19 @@ } } id1 = GUINT32_FROM_LE(hdr.id1); - if (id1 != self->configid1) { - if (flags & FWUPD_INSTALL_FLAG_FORCE) { + id2 = GUINT32_FROM_LE(hdr.id2); + if (id1 != self->configid1 || id2 != self->configid2) { + if (flags & FWUPD_INSTALL_FLAG_IGNORE_VID_PID) { g_warning ("CFG version not compatible, " - "got %u expected %u", - id1, self->configid1); + "got %u:%u expected %u:%u", + id1, id2, self->configid1, self->configid2); } else { g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "CFG version not compatible, " - "got %u expected %u", - id1, self->configid1); + "got %u:%u expected %u:%u", + id1, id2, self->configid1, self->configid2); return NULL; } } @@ -198,7 +216,7 @@ static void fu_synaprom_config_init (FuSynapromConfig *self) { - fu_device_set_protocol (FU_DEVICE (self), "com.synaptics.prometheus.config"); + fu_device_add_protocol (FU_DEVICE (self), "com.synaptics.prometheus.config"); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_PLAIN); fu_device_set_logical_id (FU_DEVICE (self), "cfg"); diff -Nru fwupd-1.4.5/plugins/synaptics-prometheus/fu-synaprom-device.c fwupd-1.5.8/plugins/synaptics-prometheus/fu-synaprom-device.c --- fwupd-1.4.5/plugins/synaptics-prometheus/fu-synaprom-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-prometheus/fu-synaprom-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -64,9 +64,14 @@ G_DEFINE_TYPE (FuSynapromDevice, fu_synaprom_device, FU_TYPE_USB_DEVICE) static gboolean -fu_synaprom_device_open (FuUsbDevice *device, GError **error) +fu_synaprom_device_open (FuDevice *device, GError **error) { - GUsbDevice *usb_device = fu_usb_device_get_dev (device); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + + /* FuUsbDevice->open */ + if (!FU_DEVICE_CLASS (fu_synaprom_device_parent_class)->open (device, error)) + return FALSE; + if (!g_usb_device_claim_interface (usb_device, 0x0, G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, error)) { @@ -252,7 +257,6 @@ g_autoptr(FuFirmware) firmware = fu_synaprom_firmware_new (); /* parse the firmware */ - fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); if (!fu_firmware_parse (firmware, fw, flags, error)) return NULL; @@ -270,7 +274,7 @@ memcpy (&hdr, g_bytes_get_data (blob, NULL), sizeof(hdr)); product = GUINT32_FROM_LE(hdr.product); if (product != FU_SYNAPROM_PRODUCT_PROMETHEUS) { - if (flags & FWUPD_INSTALL_FLAG_FORCE) { + if (flags & FWUPD_INSTALL_FLAG_IGNORE_VID_PID) { g_warning ("MFW metadata not compatible, " "got 0x%02x expected 0x%02x", product, (guint) FU_SYNAPROM_PRODUCT_PROMETHEUS); @@ -441,8 +445,9 @@ { fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_CAN_VERIFY); + fu_device_add_internal_flag (FU_DEVICE (self), FU_DEVICE_INTERNAL_FLAG_RETRY_OPEN); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_TRIPLET); - fu_device_set_protocol (FU_DEVICE (self), "com.synaptics.prometheus"); + fu_device_add_protocol (FU_DEVICE (self), "com.synaptics.prometheus"); fu_device_set_remove_delay (FU_DEVICE (self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); fu_device_set_name (FU_DEVICE (self), "Prometheus"); fu_device_set_summary (FU_DEVICE (self), "Fingerprint reader"); @@ -454,14 +459,13 @@ fu_synaprom_device_class_init (FuSynapromDeviceClass *klass) { FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); klass_device->write_firmware = fu_synaprom_device_write_firmware; klass_device->prepare_firmware = fu_synaprom_device_prepare_fw; klass_device->setup = fu_synaprom_device_setup; klass_device->reload = fu_synaprom_device_setup; klass_device->attach = fu_synaprom_device_attach; klass_device->detach = fu_synaprom_device_detach; - klass_usb_device->open = fu_synaprom_device_open; + klass_device->open = fu_synaprom_device_open; } FuSynapromDevice * diff -Nru fwupd-1.4.5/plugins/synaptics-prometheus/fu-synaprom-firmware.c fwupd-1.5.8/plugins/synaptics-prometheus/fu-synaprom-firmware.c --- fwupd-1.4.5/plugins/synaptics-prometheus/fu-synaprom-firmware.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-prometheus/fu-synaprom-firmware.c 2021-03-31 20:08:32.000000000 +0000 @@ -7,6 +7,7 @@ #include "config.h" +#include #include #include "fu-common.h" @@ -14,10 +15,16 @@ struct _FuSynapromFirmware { FuFirmware parent_instance; + guint32 product_id; }; G_DEFINE_TYPE (FuSynapromFirmware, fu_synaprom_firmware, FU_TYPE_FIRMWARE) +#define FU_SYNAPROM_FIRMWARE_TAG_MFW_HEADER 0x0001 +#define FU_SYNAPROM_FIRMWARE_TAG_MFW_PAYLOAD 0x0002 +#define FU_SYNAPROM_FIRMWARE_TAG_CFG_HEADER 0x0003 +#define FU_SYNAPROM_FIRMWARE_TAG_CFG_PAYLOAD 0x0004 + typedef struct __attribute__((packed)) { guint16 tag; guint32 bufsz; @@ -27,6 +34,8 @@ #define FU_SYNAPROM_FIRMWARE_TAG_MAX 0xfff0 #define FU_SYNAPROM_FIRMWARE_SIGSIZE 0x0100 +#define FU_SYNAPROM_FIRMWARE_IMAGE_COUNT_MAX 64 + static const gchar * fu_synaprom_firmware_tag_to_string (guint16 tag) { @@ -41,6 +50,13 @@ return NULL; } +static void +fu_synaprom_firmware_to_string (FuFirmware *firmware, guint idt, GString *str) +{ + FuSynapromFirmware *self = FU_SYNAPROM_FIRMWARE (firmware); + fu_common_string_append_kx (str, idt, "ProductId", self->product_id); +} + static gboolean fu_synaprom_firmware_parse (FuFirmware *firmware, GBytes *fw, @@ -52,6 +68,7 @@ const guint8 *buf; gsize bufsz = 0; gsize offset = 0; + guint img_cnt = 0; g_return_val_if_fail (fw != NULL, FALSE); @@ -87,6 +104,14 @@ return FALSE; } hdrsz = GUINT32_FROM_LE(header.bufsz); + if (hdrsz == 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "empty header for tag 0x%04x", + tag); + return FALSE; + } offset += sizeof(header) + hdrsz; if (offset > bufsz) { g_set_error (error, @@ -109,6 +134,17 @@ fu_firmware_image_set_id (img, fu_synaprom_firmware_tag_to_string (tag)); fu_firmware_add_image (firmware, img); + /* sanity check */ + if (img_cnt++ > FU_SYNAPROM_FIRMWARE_IMAGE_COUNT_MAX) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "maximum number of images exceeded, " + "maximum is 0x%02x", + (guint) FU_SYNAPROM_FIRMWARE_IMAGE_COUNT_MAX); + return FALSE; + } + /* next item */ buf += hdrsz; } @@ -116,12 +152,13 @@ } static GBytes * -fu_synaprom_firmware_write (FuFirmware *self, GError **error) +fu_synaprom_firmware_write (FuFirmware *firmware, GError **error) { + FuSynapromFirmware *self = FU_SYNAPROM_FIRMWARE (firmware); GByteArray *blob = g_byte_array_new (); - const guint8 data[] = { 'R', 'H' }; + g_autoptr(GBytes) payload = NULL; FuSynapromFirmwareMfwHeader hdr = { - .product = GUINT32_TO_LE(0x41), + .product = GUINT32_TO_LE(self->product_id), .id = GUINT32_TO_LE(0xff), .buildtime = GUINT32_TO_LE(0xff), .buildnum = GUINT32_TO_LE(0xff), @@ -130,14 +167,27 @@ }; /* add header */ - fu_byte_array_append_uint16 (blob, FU_SYNAPROM_FIRMWARE_TAG_MFW_HEADER, G_LITTLE_ENDIAN); - fu_byte_array_append_uint32 (blob, sizeof(hdr), G_LITTLE_ENDIAN); + fu_byte_array_append_uint16 (blob, + FU_SYNAPROM_FIRMWARE_TAG_MFW_HEADER, + G_LITTLE_ENDIAN); + fu_byte_array_append_uint32 (blob, + sizeof(hdr), + G_LITTLE_ENDIAN); g_byte_array_append (blob, (const guint8 *) &hdr, sizeof(hdr)); /* add payload */ - fu_byte_array_append_uint16 (blob, FU_SYNAPROM_FIRMWARE_TAG_MFW_PAYLOAD, G_LITTLE_ENDIAN); - fu_byte_array_append_uint32 (blob, sizeof(data), G_LITTLE_ENDIAN); - g_byte_array_append (blob, data, sizeof(data)); + payload = fu_firmware_get_image_default_bytes (firmware, error); + if (payload == NULL) + return NULL; + fu_byte_array_append_uint16 (blob, + FU_SYNAPROM_FIRMWARE_TAG_MFW_PAYLOAD, + G_LITTLE_ENDIAN); + fu_byte_array_append_uint32 (blob, + g_bytes_get_size (payload), + G_LITTLE_ENDIAN); + g_byte_array_append (blob, + g_bytes_get_data (payload, NULL), + g_bytes_get_size (payload)); /* add signature */ for (guint i = 0; i < FU_SYNAPROM_FIRMWARE_SIGSIZE; i++) @@ -145,9 +195,25 @@ return g_byte_array_free_to_bytes (blob); } +static gboolean +fu_synaprom_firmware_build (FuFirmware *firmware, XbNode *n, GError **error) +{ + FuSynapromFirmware *self = FU_SYNAPROM_FIRMWARE (firmware); + guint64 tmp; + + /* simple properties */ + tmp = xb_node_query_text_as_uint (n, "product_id", NULL); + if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT32) + self->product_id = tmp; + + /* success */ + return TRUE; +} + static void fu_synaprom_firmware_init (FuSynapromFirmware *self) { + fu_firmware_add_flag (FU_FIRMWARE (self), FU_FIRMWARE_FLAG_HAS_VID_PID); } static void @@ -156,6 +222,8 @@ FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); klass_firmware->parse = fu_synaprom_firmware_parse; klass_firmware->write = fu_synaprom_firmware_write; + klass_firmware->to_string = fu_synaprom_firmware_to_string; + klass_firmware->build = fu_synaprom_firmware_build; } FuFirmware * diff -Nru fwupd-1.4.5/plugins/synaptics-prometheus/fu-synaprom-firmware.h fwupd-1.5.8/plugins/synaptics-prometheus/fu-synaprom-firmware.h --- fwupd-1.4.5/plugins/synaptics-prometheus/fu-synaprom-firmware.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-prometheus/fu-synaprom-firmware.h 2021-03-31 20:08:32.000000000 +0000 @@ -8,16 +8,10 @@ #pragma once #include "fu-firmware.h" -#include "fu-synaprom-firmware.h" #define FU_TYPE_SYNAPROM_FIRMWARE (fu_synaprom_firmware_get_type ()) G_DECLARE_FINAL_TYPE (FuSynapromFirmware, fu_synaprom_firmware, FU, SYNAPROM_FIRMWARE, FuFirmware) -#define FU_SYNAPROM_FIRMWARE_TAG_MFW_HEADER 0x0001 -#define FU_SYNAPROM_FIRMWARE_TAG_MFW_PAYLOAD 0x0002 -#define FU_SYNAPROM_FIRMWARE_TAG_CFG_HEADER 0x0003 -#define FU_SYNAPROM_FIRMWARE_TAG_CFG_PAYLOAD 0x0004 - /* le */ typedef struct __attribute__((packed)) { guint32 product; @@ -29,13 +23,4 @@ guint8 unused[6]; } FuSynapromFirmwareMfwHeader; -/* le */ -typedef struct __attribute__((packed)) { - guint32 product; - guint32 id1; /* verification ID */ - guint32 id2; /* verification ID */ - guint16 version; /* config version */ - guint8 unused[2]; -} FuSynapromFirmwareCfgHeader; - FuFirmware *fu_synaprom_firmware_new (void); diff -Nru fwupd-1.4.5/plugins/synaptics-prometheus/meson.build fwupd-1.5.8/plugins/synaptics-prometheus/meson.build --- fwupd-1.4.5/plugins/synaptics-prometheus/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-prometheus/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,4 @@ +if get_option('gusb') cargs = ['-DG_LOG_DOMAIN="FuPluginSynapticsPrometheus"'] install_data(['synaptics-prometheus.quirk'], @@ -11,7 +12,7 @@ 'fu-synaprom-common.c', 'fu-synaprom-config.c', 'fu-synaprom-device.c', - 'fu-synaprom-firmware.c', + 'fu-synaprom-firmware.c', # fuzzing ], include_directories : [ root_incdir, @@ -31,8 +32,9 @@ ) if get_option('tests') - testdatadir = join_paths(meson.current_source_dir(), 'data') - cargs += '-DTESTDATADIR="' + testdatadir + '"' + testdatadirs = environment() + testdatadirs.set('G_TEST_SRCDIR', meson.current_source_dir()) + testdatadirs.set('G_TEST_BUILDDIR', meson.current_build_dir()) e = executable( 'synaptics-prometheus-self-test', fu_hash, @@ -55,29 +57,10 @@ fwupd, fwupdplugin, ], - c_args : cargs - ) - test('synaptics-prometheus-self-test', e) - - # for fuzzing - executable( - 'synaptics-prometheus-dump', - sources : [ - 'fu-dump.c', - 'fu-synaprom-firmware.c', - ], - include_directories : [ - root_incdir, - fwupd_incdir, - fwupdplugin_incdir, - ], - dependencies : [ - gio, - ], - link_with : [ - fwupd, - fwupdplugin, - ], - c_args : cargs + c_args : cargs, + install : true, + install_dir : installed_test_bindir, ) + test('synaptics-prometheus-self-test', e, env : testdatadirs) # added to installed-tests +endif endif diff -Nru fwupd-1.4.5/plugins/synaptics-prometheus/README.md fwupd-1.5.8/plugins/synaptics-prometheus/README.md --- fwupd-1.4.5/plugins/synaptics-prometheus/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-prometheus/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -24,8 +24,21 @@ * `USB\VID_06CB&PID_00A9&REV_0001` * `USB\VID_06CB&PID_00A9` + * `USB\VID_06CB&PID_00A9-cfg` + * `USB\VID_06CB&PID_00A9&CFG1_3483&CFG2_500` + +Update Behavior +--------------- + +The device usually presents in runtime mode, but on detach re-enumerates with +the same USB PID in an unlocked mode. On attach the device again re-enumerates +back to the runtime locked mode. Vendor ID Security ------------------ The vendor ID is set from the USB vendor, in this instance set to `USB:0x06CB` + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff -Nru fwupd-1.4.5/plugins/synaptics-prometheus/synaptics-prometheus.quirk fwupd-1.5.8/plugins/synaptics-prometheus/synaptics-prometheus.quirk --- fwupd-1.4.5/plugins/synaptics-prometheus/synaptics-prometheus.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-prometheus/synaptics-prometheus.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,7 +1,28 @@ -[DeviceInstanceId=USB\VID_06CB&PID_00A9] +[USB\VID_06CB&PID_00A9] Plugin = synaptics_prometheus InstallDuration = 2 -[DeviceInstanceId=USB\VID_06CB&PID_00BD] +[USB\VID_06CB&PID_00BD] Plugin = synaptics_prometheus InstallDuration = 2 + +[USB\VID_06CB&PID_00DF] +Plugin = synaptics_prometheus +InstallDuration = 2 + +[USB\VID_06CB&PID_00E9] +Plugin = synaptics_prometheus +InstallDuration = 2 + +[USB\VID_06CB&PID_00C2] +Plugin = synaptics_prometheus +InstallDuration = 2 + +[USB\VID_06CB&PID_00F9] +Plugin = synaptics_prometheus +InstallDuration = 2 + +[USB\VID_06CB&PID_00FC] +Plugin = synaptics_prometheus +InstallDuration = 2 + diff -Nru fwupd-1.4.5/plugins/synaptics-rmi/fu-dump.c fwupd-1.5.8/plugins/synaptics-rmi/fu-dump.c --- fwupd-1.4.5/plugins/synaptics-rmi/fu-dump.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-rmi/fu-dump.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2019 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include "fu-synaptics-rmi-firmware.h" - -static gboolean -fu_dump_parse (const gchar *filename, GError **error) -{ - gchar *data = NULL; - gsize len = 0; - g_autoptr(GBytes) blob = NULL; - g_autoptr(FuFirmware) firmware = fu_synaptics_rmi_firmware_new (); - g_autofree gchar *str = NULL; - if (!g_file_get_contents (filename, &data, &len, error)) - return FALSE; - blob = g_bytes_new_take (data, len); - if (!fu_firmware_parse (firmware, blob, FWUPD_INSTALL_FLAG_FORCE, error)) - return FALSE; - str = fu_firmware_to_string (firmware); - g_print ("%s", str); - return TRUE; -} - -static gboolean -fu_dump_generate_v0x (const gchar *filename, GError **error) -{ - const gchar *data; - gsize len = 0; - g_autoptr(GBytes) blob = NULL; - g_autoptr(GBytes) fw = fu_synaptics_rmi_firmware_generate_v0x (); - g_autoptr(FuFirmware) firmware = fu_synaptics_rmi_firmware_new (); - g_autoptr(FuFirmwareImage) image = fu_firmware_image_new (fw); - fu_firmware_add_image (firmware, image); - blob = fu_firmware_write (firmware, error); - if (blob == NULL) - return FALSE; - data = g_bytes_get_data (blob, &len); - return g_file_set_contents (filename, data, len, error); -} - -static gboolean -fu_dump_generate_v10 (const gchar *filename, GError **error) -{ - const gchar *data; - gsize len = 0; - g_autoptr(GBytes) blob = NULL; - g_autoptr(GBytes) fw = fu_synaptics_rmi_firmware_generate_v10 (); - g_autoptr(FuFirmware) firmware = fu_synaptics_rmi_firmware_new (); - g_autoptr(FuFirmwareImage) image = fu_firmware_image_new (fw); - fu_firmware_add_image (firmware, image); - blob = fu_firmware_write (firmware, error); - if (blob == NULL) - return FALSE; - data = g_bytes_get_data (blob, &len); - return g_file_set_contents (filename, data, len, error); -} - -int -main (int argc, char **argv) -{ - gint rc = 0; - - /* no args */ - if (argc <= 1) { - g_printerr ("firmware filename required\n"); - return 2; - } - - /* tool gen fn */ - if (argc == 3 && g_strcmp0 (argv[1], "gen0x") == 0) { - g_autoptr(GError) error = NULL; - if (!fu_dump_generate_v0x (argv[2], &error)) { - g_printerr ("generate failed: %s\n", error->message); - return 1; - } - return 0; - } - if (argc == 3 && g_strcmp0 (argv[1], "gen10") == 0) { - g_autoptr(GError) error = NULL; - if (!fu_dump_generate_v10 (argv[2], &error)) { - g_printerr ("generate failed: %s\n", error->message); - return 1; - } - return 0; - } - - /* tool fn [fn2] [fn3] */ - for (gint i = 1; i < argc; i++) { - g_autoptr(GError) error = NULL; - if (!fu_dump_parse (argv[i], &error)) { - g_printerr ("parse failed: %s\n", error->message); - rc = 1; - } - if (rc != 0) - return rc; - } - - /* success */ - g_print ("OK!\n"); - return rc; -} diff -Nru fwupd-1.4.5/plugins/synaptics-rmi/fu-plugin-synaptics-rmi.c fwupd-1.5.8/plugins/synaptics-rmi/fu-plugin-synaptics-rmi.c --- fwupd-1.4.5/plugins/synaptics-rmi/fu-plugin-synaptics-rmi.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-rmi/fu-plugin-synaptics-rmi.c 2021-03-31 20:08:32.000000000 +0000 @@ -7,9 +7,9 @@ #include "config.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" -#include "fu-synaptics-rmi-device.h" +#include "fu-synaptics-rmi-hid-device.h" +#include "fu-synaptics-rmi-ps2-device.h" #include "fu-synaptics-rmi-firmware.h" void @@ -17,6 +17,8 @@ { fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_udev_subsystem (plugin, "hidraw"); - fu_plugin_set_device_gtype (plugin, FU_TYPE_SYNAPTICS_RMI_DEVICE); - fu_plugin_add_firmware_gtype (plugin, "rmi", FU_TYPE_SYNAPTICS_RMI_FIRMWARE); + fu_plugin_add_udev_subsystem (plugin, "serio"); + g_type_ensure (FU_TYPE_SYNAPTICS_RMI_HID_DEVICE); + g_type_ensure (FU_TYPE_SYNAPTICS_RMI_PS2_DEVICE); + fu_plugin_add_firmware_gtype (plugin, NULL, FU_TYPE_SYNAPTICS_RMI_FIRMWARE); } diff -Nru fwupd-1.4.5/plugins/synaptics-rmi/fu-synaptics-rmi-common.c fwupd-1.5.8/plugins/synaptics-rmi/fu-synaptics-rmi-common.c --- fwupd-1.4.5/plugins/synaptics-rmi/fu-synaptics-rmi-common.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-rmi/fu-synaptics-rmi-common.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,6 +1,6 @@ /* - * Copyright (C) 2012-2014 Andrew Duggan - * Copyright (C) 2012-2019 Synaptics Inc. + * Copyright (C) 2012 Andrew Duggan + * Copyright (C) 2012 Synaptics Inc. * Copyright (C) 2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ @@ -14,6 +14,11 @@ #include +#ifdef HAVE_GNUTLS +#include +#include +#endif + #include "fu-common.h" #include "fu-io-channel.h" #include "fu-synaptics-rmi-common.h" @@ -30,6 +35,15 @@ #define RMI_FUNCTION_VERSION_MASK 0x60 #define RMI_FUNCTION_INTERRUPT_SOURCES_MASK 0x7 +#ifdef HAVE_GNUTLS +typedef guchar gnutls_data_t; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +G_DEFINE_AUTOPTR_CLEANUP_FUNC(gnutls_data_t, gnutls_free) +G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gnutls_pubkey_t, gnutls_pubkey_deinit, NULL) +#pragma clang diagnostic pop +#endif + guint32 fu_synaptics_rmi_generate_checksum (const guint8 *data, gsize len) { @@ -100,3 +114,68 @@ return fu_io_channel_write_raw (io, (const guint8 *) buf, strlen (buf), 1000, FU_IO_CHANNEL_FLAG_NONE, error); } + +gboolean +fu_synaptics_verify_sha256_signature (GBytes *payload, + GBytes *pubkey, + GBytes *signature, + GError **error) +{ +#ifdef HAVE_GNUTLS + gnutls_datum_t hash; + gnutls_datum_t m; + gnutls_datum_t e; + gnutls_datum_t sig; + gnutls_hash_hd_t sha2; + g_auto(gnutls_pubkey_t) pub = NULL; + gint ec; + guint8 exponent[] = { 1, 0, 1 }; + guint hash_length = gnutls_hash_get_len (GNUTLS_DIG_SHA256); + g_autoptr(gnutls_data_t) hash_data = NULL; + + /* hash firmware data */ + hash_data = gnutls_malloc (hash_length); + gnutls_hash_init (&sha2, GNUTLS_DIG_SHA256); + gnutls_hash (sha2, g_bytes_get_data (payload, NULL), g_bytes_get_size (payload)); + gnutls_hash_deinit (sha2, hash_data); + + /* hash */ + hash.size = hash_length; + hash.data = hash_data; + + /* modulus */ + m.size = g_bytes_get_size (pubkey); + m.data = (guint8 *) g_bytes_get_data (pubkey, NULL); + + /* exponent */ + e.size = sizeof(exponent); + e.data = exponent; + + /* signature */ + sig.size = g_bytes_get_size (signature); + sig.data = (guint8 *) g_bytes_get_data (signature, NULL); + + gnutls_pubkey_init (&pub); + ec = gnutls_pubkey_import_rsa_raw (pub, &m, &e); + if (ec < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to import RSA key: %s", + gnutls_strerror (ec)); + return FALSE; + } + ec = gnutls_pubkey_verify_hash2 (pub, GNUTLS_SIGN_RSA_SHA256, + 0, &hash, &sig); + if (ec < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to verify firmware: %s", + gnutls_strerror (ec)); + return FALSE; + } +#endif + /* success */ + return TRUE; +} diff -Nru fwupd-1.4.5/plugins/synaptics-rmi/fu-synaptics-rmi-common.h fwupd-1.5.8/plugins/synaptics-rmi/fu-synaptics-rmi-common.h --- fwupd-1.4.5/plugins/synaptics-rmi/fu-synaptics-rmi-common.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-rmi/fu-synaptics-rmi-common.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,6 +1,6 @@ /* - * Copyright (C) 2012-2014 Andrew Duggan - * Copyright (C) 2012-2019 Synaptics Inc. + * Copyright (C) 2012 Andrew Duggan + * Copyright (C) 2012 Synaptics Inc. * Copyright (C) 2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ @@ -34,3 +34,7 @@ gboolean fu_synaptics_rmi_device_writeln (const gchar *fn, const gchar *buf, GError **error); +gboolean fu_synaptics_verify_sha256_signature (GBytes *payload, + GBytes *pubkey, + GBytes *signature, + GError **error); diff -Nru fwupd-1.4.5/plugins/synaptics-rmi/fu-synaptics-rmi-device.c fwupd-1.5.8/plugins/synaptics-rmi/fu-synaptics-rmi-device.c --- fwupd-1.4.5/plugins/synaptics-rmi/fu-synaptics-rmi-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-rmi/fu-synaptics-rmi-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,6 +1,6 @@ /* - * Copyright (C) 2012-2014 Andrew Duggan - * Copyright (C) 2012-2019 Synaptics Inc. + * Copyright (C) 2012 Andrew Duggan + * Copyright (C) 2012 Synaptics Inc. * Copyright (C) 2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ @@ -8,39 +8,13 @@ #include "config.h" -#include -#include - -#include "fu-io-channel.h" - #include "fu-synaptics-rmi-common.h" #include "fu-synaptics-rmi-firmware.h" +#include "fu-synaptics-rmi-ps2-device.h" #include "fu-synaptics-rmi-v5-device.h" #include "fu-synaptics-rmi-v6-device.h" #include "fu-synaptics-rmi-v7-device.h" -#define RMI_WRITE_REPORT_ID 0x9 /* output report */ -#define RMI_READ_ADDR_REPORT_ID 0xa /* output report */ -#define RMI_READ_DATA_REPORT_ID 0xb /* input report */ -#define RMI_ATTN_REPORT_ID 0xc /* input report */ -#define RMI_SET_RMI_MODE_REPORT_ID 0xf /* feature report */ - -#define RMI_DEVICE_DEFAULT_TIMEOUT 2000 - -#define HID_RMI4_REPORT_ID 0 -#define HID_RMI4_READ_INPUT_COUNT 1 -#define HID_RMI4_READ_INPUT_DATA 2 -#define HID_RMI4_READ_OUTPUT_ADDR 2 -#define HID_RMI4_READ_OUTPUT_COUNT 4 -#define HID_RMI4_WRITE_OUTPUT_COUNT 1 -#define HID_RMI4_WRITE_OUTPUT_ADDR 2 -#define HID_RMI4_WRITE_OUTPUT_DATA 4 -#define HID_RMI4_FEATURE_MODE 1 -#define HID_RMI4_ATTN_INTERUPT_SOURCES 1 -#define HID_RMI4_ATTN_DATA 2 - -#define RMI_DEVICE_PAGE_SELECT_REGISTER 0xff -#define RMI_DEVICE_MAX_PAGE 0xff #define RMI_DEVICE_PAGE_SIZE 0x100 #define RMI_DEVICE_PAGE_SCAN_START 0x00e9 #define RMI_DEVICE_PAGE_SCAN_END 0x0005 @@ -68,28 +42,16 @@ #define RMI_F01_CMD_DEVICE_RESET 1 #define RMI_F01_DEFAULT_RESET_DELAY_MS 100 -/* - * msleep mode controls power management on the device and affects all - * functions of the device. - */ -#define RMI_F01_CTRL0_SLEEP_MODE_MASK 0x03 - -#define RMI_SLEEP_MODE_NORMAL 0x00 -#define RMI_SLEEP_MODE_SENSOR_SLEEP 0x01 - -/* - * This bit disables whatever sleep mode may be selected by the sleep_mode - * field and forces the device to run at full power without sleeping. - */ -#define RMI_F01_CRTL0_NOSLEEP_BIT (1 << 2) - typedef struct { FuSynapticsRmiFlash flash; GPtrArray *functions; - FuIOChannel *io_channel; FuSynapticsRmiFunction *f01; FuSynapticsRmiFunction *f34; + guint8 current_page; + guint16 sig_size; /* 0x0 for non-secure update */ + guint8 max_page; + gboolean in_iep_mode; } FuSynapticsRmiDevicePrivate; G_DEFINE_TYPE_WITH_PRIVATE (FuSynapticsRmiDevice, fu_synaptics_rmi_device, FU_TYPE_UDEV_DEVICE) @@ -125,7 +87,18 @@ { FuSynapticsRmiDevice *self = FU_SYNAPTICS_RMI_DEVICE (device); FuSynapticsRmiDevicePrivate *priv = GET_PRIVATE (self); - fu_common_string_append_kx (str, idt, "BlVer", priv->f34->function_version + 0x5); + + /* FuUdevDevice->to_string */ + FU_DEVICE_CLASS (fu_synaptics_rmi_device_parent_class)->to_string (device, idt, str); + + fu_common_string_append_kx (str, idt, "CurrentPage", priv->current_page); + fu_common_string_append_kx (str, idt, "InIepMode", priv->in_iep_mode); + fu_common_string_append_kx (str, idt, "MaxPage", priv->max_page); + fu_common_string_append_kx (str, idt, "SigSize", priv->sig_size); + if (priv->f34 != NULL) { + fu_common_string_append_kx (str, idt, "BlVer", + priv->f34->function_version + 0x5); + } fu_synaptics_rmi_flash_to_string (&priv->flash, idt, str); } @@ -156,167 +129,70 @@ } GByteArray * -fu_synaptics_rmi_device_read (FuSynapticsRmiDevice *self, guint16 addr, gsize req_sz, GError **error) +fu_synaptics_rmi_device_read (FuSynapticsRmiDevice *self, + guint16 addr, + gsize req_sz, + GError **error) { - FuSynapticsRmiDevicePrivate *priv = GET_PRIVATE (self); - g_autoptr(GByteArray) buf = g_byte_array_new (); - g_autoptr(GByteArray) req = g_byte_array_new (); + FuSynapticsRmiDeviceClass *klass_rmi = FU_SYNAPTICS_RMI_DEVICE_GET_CLASS (self); + return klass_rmi->read (self, addr, req_sz, error); +} - /* maximum size */ - if (req_sz > 0xffff) { +GByteArray * +fu_synaptics_rmi_device_read_packet_register (FuSynapticsRmiDevice *self, + guint16 addr, + gsize req_sz, + GError **error) +{ + FuSynapticsRmiDeviceClass *klass_rmi = FU_SYNAPTICS_RMI_DEVICE_GET_CLASS (self); + if (klass_rmi->read_packet_register == NULL) { g_set_error_literal (error, FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "data to read was too long"); - return NULL; - } - - /* report then old 1 byte read count */ - fu_byte_array_append_uint8 (req, RMI_READ_ADDR_REPORT_ID); - fu_byte_array_append_uint8 (req, 0x0); - - /* address */ - fu_byte_array_append_uint16 (req, addr, G_LITTLE_ENDIAN); - - /* read output count */ - fu_byte_array_append_uint16 (req, req_sz, G_LITTLE_ENDIAN); - - /* request */ - for (guint j = req->len; j < 21; j++) - fu_byte_array_append_uint8 (req, 0x0); - if (g_getenv ("FWUPD_SYNAPTICS_RMI_VERBOSE") != NULL) { - fu_common_dump_full (G_LOG_DOMAIN, "ReportWrite", - req->data, req->len, - 80, FU_DUMP_FLAGS_NONE); - } - if (!fu_io_channel_write_byte_array (priv->io_channel, req, RMI_DEVICE_DEFAULT_TIMEOUT, - FU_IO_CHANNEL_FLAG_SINGLE_SHOT | - FU_IO_CHANNEL_FLAG_USE_BLOCKING_IO, error)) + FWUPD_ERROR_NOT_SUPPORTED, + "packet register reads not supported"); return NULL; - - /* keep reading responses until we get enough data */ - while (buf->len < req_sz) { - guint8 input_count_sz = 0; - g_autoptr(GByteArray) res = NULL; - res = fu_io_channel_read_byte_array (priv->io_channel, req_sz, - RMI_DEVICE_DEFAULT_TIMEOUT, - FU_IO_CHANNEL_FLAG_SINGLE_SHOT, - error); - if (res == NULL) - return NULL; - if (res->len == 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "response zero sized"); - return NULL; - } - if (g_getenv ("FWUPD_SYNAPTICS_RMI_VERBOSE") != NULL) { - fu_common_dump_full (G_LOG_DOMAIN, "ReportRead", - res->data, res->len, - 80, FU_DUMP_FLAGS_NONE); - } - - /* ignore non data report events */ - if (res->data[HID_RMI4_REPORT_ID] != RMI_READ_DATA_REPORT_ID) { - g_debug ("ignoring report with ID 0x%02x", - res->data[HID_RMI4_REPORT_ID]); - continue; - } - if (res->len < HID_RMI4_READ_INPUT_DATA) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "response too small: 0x%02x", - res->len); - return NULL; - } - input_count_sz = res->data[HID_RMI4_READ_INPUT_COUNT]; - if (input_count_sz == 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "input count zero"); - return NULL; - } - if (input_count_sz + (guint) HID_RMI4_READ_INPUT_DATA > res->len) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "underflow 0x%02x from expected 0x%02x", - res->len, (guint) input_count_sz + HID_RMI4_READ_INPUT_DATA); - return NULL; - } - g_byte_array_append (buf, - res->data + HID_RMI4_READ_INPUT_DATA, - input_count_sz); - - } - if (g_getenv ("FWUPD_SYNAPTICS_RMI_VERBOSE") != NULL) { - fu_common_dump_full (G_LOG_DOMAIN, "DeviceRead", buf->data, buf->len, - 80, FU_DUMP_FLAGS_NONE); } + return klass_rmi->read_packet_register (self, addr, req_sz, error); +} - return g_steal_pointer (&buf); +gboolean +fu_synaptics_rmi_device_write (FuSynapticsRmiDevice *self, + guint16 addr, + GByteArray *req, + FuSynapticsRmiDeviceFlags flags, + GError **error) +{ + FuSynapticsRmiDeviceClass *klass_rmi = FU_SYNAPTICS_RMI_DEVICE_GET_CLASS (self); + return klass_rmi->write (self, addr, req, flags, error); } gboolean -fu_synaptics_rmi_device_write (FuSynapticsRmiDevice *self, guint16 addr, GByteArray *req, GError **error) +fu_synaptics_rmi_device_set_page (FuSynapticsRmiDevice *self, guint8 page, GError **error) { FuSynapticsRmiDevicePrivate *priv = GET_PRIVATE (self); - guint8 len = 0x0; - g_autoptr(GByteArray) buf = g_byte_array_new (); - - /* check size */ - if (req != NULL) { - if (req->len > 0xff) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "data to write was too long"); - return FALSE; - } - len = req->len; - } - - /* report */ - fu_byte_array_append_uint8 (buf, RMI_WRITE_REPORT_ID); - - /* length */ - fu_byte_array_append_uint8 (buf, len); - - /* address */ - fu_byte_array_append_uint16 (buf, addr, G_LITTLE_ENDIAN); - - /* optional data */ - if (req != NULL) - g_byte_array_append (buf, req->data, req->len); - - /* pad out to 21 bytes for some reason */ - for (guint i = buf->len; i < 21; i++) - fu_byte_array_append_uint8 (buf, 0x0); - if (g_getenv ("FWUPD_SYNAPTICS_RMI_VERBOSE") != NULL) { - fu_common_dump_full (G_LOG_DOMAIN, "DeviceWrite", buf->data, buf->len, - 80, FU_DUMP_FLAGS_NONE); - } - - return fu_io_channel_write_byte_array (priv->io_channel, buf, RMI_DEVICE_DEFAULT_TIMEOUT, - FU_IO_CHANNEL_FLAG_SINGLE_SHOT | - FU_IO_CHANNEL_FLAG_USE_BLOCKING_IO, - error); + FuSynapticsRmiDeviceClass *klass_rmi = FU_SYNAPTICS_RMI_DEVICE_GET_CLASS (self); + if (priv->current_page == page) + return TRUE; + if (!klass_rmi->set_page (self, page, error)) + return FALSE; + priv->current_page = page; + return TRUE; } -static gboolean -fu_synaptics_rmi_device_set_rma_page (FuSynapticsRmiDevice *self, guint8 page, GError **error) +void +fu_synaptics_rmi_device_set_iepmode (FuSynapticsRmiDevice *self, gboolean iepmode) { - g_autoptr(GByteArray) req = g_byte_array_new (); + FuSynapticsRmiDevicePrivate *priv = GET_PRIVATE (self); + priv->in_iep_mode = iepmode; +} - fu_byte_array_append_uint8 (req, page); - if (!fu_synaptics_rmi_device_write (self, RMI_DEVICE_PAGE_SELECT_REGISTER, req, error)) { - g_prefix_error (error, "failed to set RMA page 0x%x", page); - return FALSE; - } - return TRUE; +gboolean +fu_synaptics_rmi_device_write_bus_select (FuSynapticsRmiDevice *self, guint8 bus, GError **error) +{ + FuSynapticsRmiDeviceClass *klass_rmi = FU_SYNAPTICS_RMI_DEVICE_GET_CLASS (self); + if (klass_rmi->write_bus_select == NULL) + return TRUE; + return klass_rmi->write_bus_select (self, bus, error); } gboolean @@ -326,7 +202,9 @@ g_autoptr(GByteArray) req = g_byte_array_new (); fu_byte_array_append_uint8 (req, RMI_F01_CMD_DEVICE_RESET); - if (!fu_synaptics_rmi_device_write (self, priv->f01->command_base, req, error)) + if (!fu_synaptics_rmi_device_write (self, priv->f01->command_base, req, + FU_SYNAPTICS_RMI_DEVICE_FLAG_ALLOW_FAILURE, + error)) return FALSE; g_usleep (1000 * RMI_F01_DEFAULT_RESET_DELAY_MS); return TRUE; @@ -342,14 +220,14 @@ g_ptr_array_set_size (priv->functions, 0); /* scan pages */ - for (guint page = 0; page < RMI_DEVICE_MAX_PAGE; page++) { + for (guint page = 0; page < priv->max_page; page++) { gboolean found = FALSE; guint32 page_start = RMI_DEVICE_PAGE_SIZE * page; guint32 pdt_start = page_start + RMI_DEVICE_PAGE_SCAN_START; guint32 pdt_end = page_start + RMI_DEVICE_PAGE_SCAN_END; /* set page */ - if (!fu_synaptics_rmi_device_set_rma_page (self, page, error)) + if (!fu_synaptics_rmi_device_set_page (self, page, error)) return FALSE; /* read out functions */ @@ -358,7 +236,9 @@ g_autoptr(GByteArray) res = NULL; res = fu_synaptics_rmi_device_read (self, addr, RMI_DEVICE_PDT_ENTRY_SIZE, error); if (res == NULL) { - g_prefix_error (error, "failed to read PDT entry @ 0x%04x: ", addr); + g_prefix_error (error, + "failed to read page %u PDT entry @ 0x%04x: ", + page, addr); return FALSE; } func = fu_synaptics_rmi_function_parse (res, page_start, interrupt_count, error); @@ -393,23 +273,34 @@ return TRUE; } -typedef enum { - HID_RMI4_MODE_MOUSE = 0, - HID_RMI4_MODE_ATTN_REPORTS = 1, - HID_RMI4_MODE_NO_PACKED_ATTN_REPORTS = 2, -} FuSynapticsRmiHidMode; +void +fu_synaptics_rmi_device_set_sig_size (FuSynapticsRmiDevice *self, + guint16 sig_size) +{ + FuSynapticsRmiDevicePrivate *priv = GET_PRIVATE (self); + priv->sig_size = sig_size; +} -static gboolean -fu_synaptics_rmi_device_set_mode (FuSynapticsRmiDevice *self, - FuSynapticsRmiHidMode mode, - GError **error) -{ - const guint8 data[] = { 0x0f, mode }; - if (g_getenv ("FWUPD_SYNAPTICS_RMI_VERBOSE") != NULL) - fu_common_dump_raw (G_LOG_DOMAIN, "SetMode", data, sizeof(data)); - return fu_udev_device_ioctl (FU_UDEV_DEVICE (self), - HIDIOCSFEATURE(sizeof(data)), (guint8 *) data, - NULL, error); +guint16 +fu_synaptics_rmi_device_get_sig_size (FuSynapticsRmiDevice *self) +{ + FuSynapticsRmiDevicePrivate *priv = GET_PRIVATE (self); + return priv->sig_size; +} + +void +fu_synaptics_rmi_device_set_max_page (FuSynapticsRmiDevice *self, + guint8 max_page) +{ + FuSynapticsRmiDevicePrivate *priv = GET_PRIVATE (self); + priv->max_page = max_page; +} + +guint8 +fu_synaptics_rmi_device_get_max_page (FuSynapticsRmiDevice *self) +{ + FuSynapticsRmiDevicePrivate *priv = GET_PRIVATE (self); + return priv->max_page; } static void @@ -431,15 +322,43 @@ } static gboolean +fu_synaptics_rmi_device_query_status (FuSynapticsRmiDevice *self, GError **error) +{ + FuSynapticsRmiDeviceClass *klass_rmi = FU_SYNAPTICS_RMI_DEVICE_GET_CLASS (self); + return klass_rmi->query_status (self, error); +} + +static gboolean +fu_synaptics_rmi_device_query_build_id (FuSynapticsRmiDevice *self, + guint32 *build_id, + GError **error) +{ + FuSynapticsRmiDeviceClass *klass_rmi = FU_SYNAPTICS_RMI_DEVICE_GET_CLASS (self); + if (klass_rmi->query_build_id == NULL) + return TRUE; + return klass_rmi->query_build_id (self, build_id, error); +} + +static gboolean +fu_synaptics_rmi_device_query_product_sub_id (FuSynapticsRmiDevice *self, + guint8 *product_sub_id, + GError **error) +{ + FuSynapticsRmiDeviceClass *klass_rmi = FU_SYNAPTICS_RMI_DEVICE_GET_CLASS (self); + if (klass_rmi->query_product_sub_id == NULL) + return TRUE; + return klass_rmi->query_product_sub_id (self, product_sub_id, error); +} + +static gboolean fu_synaptics_rmi_device_setup (FuDevice *device, GError **error) { - FuDeviceClass *klass_device = FU_DEVICE_GET_CLASS (device); - FuSynapticsRmiDeviceClass *klass_rmi = FU_SYNAPTICS_RMI_DEVICE_GET_CLASS (device); FuSynapticsRmiDevice *self = FU_SYNAPTICS_RMI_DEVICE (device); FuSynapticsRmiDevicePrivate *priv = GET_PRIVATE (self); guint16 addr; guint16 prod_info_addr; guint8 ds4_query_length = 0; + guint8 product_sub_id = 0; gboolean has_build_id_query = FALSE; gboolean has_dds4_queries = FALSE; gboolean has_lts; @@ -453,6 +372,9 @@ g_autoptr(GByteArray) f01_product_id = NULL; g_autoptr(GByteArray) f01_ds4 = NULL; + /* assume reset */ + priv->in_iep_mode = FALSE; + /* read PDT */ if (!fu_synaptics_rmi_device_scan_pdt (self, error)) return FALSE; @@ -460,6 +382,13 @@ if (priv->f01 == NULL) return FALSE; addr = priv->f01->query_base; + + /* set page */ + if (!fu_synaptics_rmi_device_set_page (self, 0, error)) + return FALSE; + if (!fu_synaptics_rmi_device_enter_iep_mode (self, error)) + return FALSE; + f01_basic = fu_synaptics_rmi_device_read (self, addr, RMI_DEVICE_F01_BASIC_QUERY_LEN, error); if (f01_basic == NULL) { g_prefix_error (error, "failed to read the basic query: "); @@ -476,7 +405,19 @@ g_prefix_error (error, "failed to read the product id: "); return FALSE; } - product_id = g_strndup ((const gchar *) f01_product_id->data, f01_product_id->len); + if (!fu_synaptics_rmi_device_query_product_sub_id (self, &product_sub_id, error)) { + g_prefix_error (error, "failed to query product sub id: "); + return FALSE; + } + if (product_sub_id == 0) { + /* HID */ + product_id = g_strndup ((const gchar *) f01_product_id->data, + f01_product_id->len); + } else { + /* PS/2 */ + g_autofree gchar *tmp = g_strndup ((const gchar *) f01_product_id->data, 6); + product_id = g_strdup_printf ("%s-%03d", tmp, product_sub_id); + } if (product_id != NULL) fu_synaptics_rmi_device_set_product_id (self, product_id); @@ -531,29 +472,39 @@ f01_tmp->data, f01_tmp->len, 0x0, /* src */ f01_tmp->len, error)) return FALSE; - priv->flash.build_id = fu_common_read_uint32 (buf32, G_LITTLE_ENDIAN); + if (!fu_common_read_uint32_safe (buf32, sizeof(buf32), 0x0, + &priv->flash.build_id, + G_LITTLE_ENDIAN, error)) + return FALSE; + } + + /* read build ID, typically only for PS/2 */ + if (!fu_synaptics_rmi_device_query_build_id (self, + &priv->flash.build_id, + error)) { + g_prefix_error (error, "failed to query build id: "); + return FALSE; } + /* get Function34_Query0,1 */ priv->f34 = fu_synaptics_rmi_device_get_function (self, 0x34, error); if (priv->f34 == NULL) return FALSE; - - /* set up vfuncs for each bootloader protocol version */ if (priv->f34->function_version == 0x0) { - klass_rmi->setup = fu_synaptics_rmi_v5_device_setup; - klass_rmi->query_status = fu_synaptics_rmi_v5_device_query_status; - klass_device->detach = fu_synaptics_rmi_v5_device_detach; - klass_device->write_firmware = fu_synaptics_rmi_v5_device_write_firmware; + if (!fu_synaptics_rmi_v5_device_setup (self, error)) { + g_prefix_error (error, "failed to do v5 setup: "); + return FALSE; + } } else if (priv->f34->function_version == 0x1) { - klass_rmi->setup = fu_synaptics_rmi_v6_device_setup; - klass_rmi->query_status = fu_synaptics_rmi_v5_device_query_status; - klass_device->detach = fu_synaptics_rmi_v5_device_detach; - klass_device->write_firmware = fu_synaptics_rmi_v5_device_write_firmware; + if (!fu_synaptics_rmi_v6_device_setup (self, error)) { + g_prefix_error (error, "failed to do v6 setup: "); + return FALSE; + } } else if (priv->f34->function_version == 0x2) { - klass_rmi->setup = fu_synaptics_rmi_v7_device_setup; - klass_rmi->query_status = fu_synaptics_rmi_v7_device_query_status; - klass_device->detach = fu_synaptics_rmi_v7_device_detach; - klass_device->write_firmware = fu_synaptics_rmi_v7_device_write_firmware; + if (!fu_synaptics_rmi_v7_device_setup (self, error)) { + g_prefix_error (error, "failed to do v7 setup: "); + return FALSE; + } } else { g_set_error (error, FWUPD_ERROR, @@ -562,13 +513,7 @@ priv->f34->function_version); return FALSE; } - - /* get Function34_Query0,1 */ - if (!klass_rmi->setup (self, error)) { - g_prefix_error (error, "failed to read f34 queries: "); - return FALSE; - } - if (!klass_rmi->query_status (self, error)) { + if (!fu_synaptics_rmi_device_query_status (self, error)) { g_prefix_error (error, "failed to read bootloader status: "); return FALSE; } @@ -586,51 +531,6 @@ return TRUE; } -static gboolean -fu_synaptics_rmi_device_open (FuUdevDevice *device, GError **error) -{ - FuSynapticsRmiDevice *self = FU_SYNAPTICS_RMI_DEVICE (device); - FuSynapticsRmiDevicePrivate *priv = GET_PRIVATE (self); - - /* set up touchpad so we can query it */ - priv->io_channel = fu_io_channel_unix_new (fu_udev_device_get_fd (device)); - if (!fu_synaptics_rmi_device_set_mode (self, HID_RMI4_MODE_ATTN_REPORTS, error)) - return FALSE; - - /* success */ - return TRUE; -} - -static gboolean -fu_synaptics_rmi_device_close (FuUdevDevice *device, GError **error) -{ - FuSynapticsRmiDevice *self = FU_SYNAPTICS_RMI_DEVICE (device); - FuSynapticsRmiDevicePrivate *priv = GET_PRIVATE (self); - g_autoptr(GError) error_local = NULL; - - /* turn it back to mouse mode */ - if (!fu_synaptics_rmi_device_set_mode (self, HID_RMI4_MODE_MOUSE, &error_local)) { - /* if just detached for replug, swallow error */ - if (!g_error_matches (error_local, - FWUPD_ERROR, - FWUPD_ERROR_PERMISSION_DENIED)) { - g_propagate_error (error, g_steal_pointer (&error_local)); - return FALSE; - } - g_debug ("ignoring: %s", error_local->message); - } - - fu_udev_device_set_fd (device, -1); - g_clear_object (&priv->io_channel); - return TRUE; -} - -static gboolean -fu_synaptics_rmi_device_probe (FuUdevDevice *device, GError **error) -{ - return fu_udev_device_set_physical_id (device, "hid", error); -} - static FuFirmware * fu_synaptics_rmi_device_prepare_firmware (FuDevice *device, GBytes *fw, @@ -651,7 +551,8 @@ bytes_bin = fu_firmware_get_image_by_id_bytes (firmware, "ui", error); if (bytes_bin == NULL) return NULL; - size_expected = (gsize) priv->flash.block_count_fw * (gsize) priv->flash.block_size; + size_expected = ((gsize) priv->flash.block_count_fw * (gsize) priv->flash.block_size) + + fu_synaptics_rmi_firmware_get_sig_size (FU_SYNAPTICS_RMI_FIRMWARE (firmware)); if (g_bytes_get_size (bytes_bin) != size_expected) { g_set_error (error, FWUPD_ERROR, @@ -728,56 +629,28 @@ guint timeout_ms, GError **error) { + FuSynapticsRmiDeviceClass *klass_rmi = FU_SYNAPTICS_RMI_DEVICE_GET_CLASS (self); + return klass_rmi->wait_for_attr (self, source_mask, timeout_ms, error); +} + +gboolean +fu_synaptics_rmi_device_enter_iep_mode (FuSynapticsRmiDevice *self, GError **error) +{ + FuSynapticsRmiDeviceClass *klass_rmi = FU_SYNAPTICS_RMI_DEVICE_GET_CLASS (self); FuSynapticsRmiDevicePrivate *priv = GET_PRIVATE (self); - g_autoptr(GTimer) timer = g_timer_new (); - /* wait for event from hardware */ - while (g_timer_elapsed (timer, NULL) * 1000.f < timeout_ms) { - g_autoptr(GByteArray) res = NULL; - g_autoptr(GError) error_local = NULL; - - /* read from fd */ - res = fu_io_channel_read_byte_array (priv->io_channel, - HID_RMI4_ATTN_INTERUPT_SOURCES + 1, - timeout_ms, - FU_IO_CHANNEL_FLAG_NONE, - &error_local); - if (res == NULL) { - if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) - break; - g_propagate_error (error, g_steal_pointer (&error_local)); + /* already set */ + if (priv->in_iep_mode) + return TRUE; + if (klass_rmi->enter_iep_mode != NULL) { + g_debug ("enabling RMI iep_mode"); + if (!klass_rmi->enter_iep_mode (self, error)) { + g_prefix_error (error, "failed to enable RMI iep_mode: "); return FALSE; } - if (g_getenv ("FWUPD_SYNAPTICS_RMI_VERBOSE") != NULL) { - fu_common_dump_full (G_LOG_DOMAIN, "ReportRead", - res->data, res->len, - 80, FU_DUMP_FLAGS_NONE); - } - if (res->len < HID_RMI4_ATTN_INTERUPT_SOURCES + 1) { - g_debug ("attr: ignoring small read of %u", res->len); - continue; - } - if (res->data[HID_RMI4_REPORT_ID] != RMI_ATTN_REPORT_ID) { - g_debug ("attr: ignoring invalid report ID 0x%x", - res->data[HID_RMI4_REPORT_ID]); - continue; - } - - /* success */ - if (source_mask & res->data[HID_RMI4_ATTN_INTERUPT_SOURCES]) - return TRUE; - - /* wrong mask */ - g_debug ("source mask did not match: 0x%x", - res->data[HID_RMI4_ATTN_INTERUPT_SOURCES]); } - - /* urgh */ - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "no attr report, timed out"); - return FALSE; + priv->in_iep_mode = TRUE; + return TRUE; } gboolean @@ -830,6 +703,14 @@ f34_enabled = !!(res->data[0] & RMI_F34_ENABLED_MASK); } + /* PS/2 */ + if (FU_IS_SYNAPTICS_RMI_PS2_DEVICE (self)) { + if (f34_command == 0) { + g_debug ("F34 zero as PS/2"); + return TRUE; + } + } + /* is idle */ if (f34_status == 0x0 && f34_command == 0x0) { if (f34_enabled == 0x0) { @@ -854,87 +735,10 @@ gboolean fu_synaptics_rmi_device_disable_sleep (FuSynapticsRmiDevice *self, GError **error) { - FuSynapticsRmiDevicePrivate *priv = GET_PRIVATE (self); - g_autoptr(GByteArray) f01_control0 = NULL; - - f01_control0 = fu_synaptics_rmi_device_read (self, priv->f01->control_base, 0x1, error); - if (f01_control0 == NULL) { - g_prefix_error (error, "failed to write get f01_control0: "); - return FALSE; - } - f01_control0->data[0] |= RMI_F01_CRTL0_NOSLEEP_BIT; - f01_control0->data[0] = (f01_control0->data[0] & ~RMI_F01_CTRL0_SLEEP_MODE_MASK) | RMI_SLEEP_MODE_NORMAL; - if (!fu_synaptics_rmi_device_write (self, - priv->f01->control_base, - f01_control0, - error)) { - g_prefix_error (error, "failed to write f01_control0: "); - return FALSE; - } - - /* success */ - return TRUE; -} - -gboolean -fu_synaptics_rmi_device_rebind_driver (FuSynapticsRmiDevice *self, GError **error) -{ - GUdevDevice *udev_device = fu_udev_device_get_dev (FU_UDEV_DEVICE (self)); - const gchar *hid_id; - const gchar *driver; - const gchar *subsystem; - g_autofree gchar *fn_rebind = NULL; - g_autofree gchar *fn_unbind = NULL; - g_autoptr(GUdevDevice) parent_hid = NULL; - g_autoptr(GUdevDevice) parent_i2c = NULL; - - /* get actual HID node */ - parent_hid = g_udev_device_get_parent_with_subsystem (udev_device, "hid", NULL); - if (parent_hid == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "no HID parent device for %s", - g_udev_device_get_sysfs_path (udev_device)); - return FALSE; - } - - /* find the physical ID to use for the rebind */ - hid_id = g_udev_device_get_property (parent_hid, "HID_PHYS"); - if (hid_id == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "no HID_PHYS in %s", - g_udev_device_get_sysfs_path (parent_hid)); - return FALSE; - } - g_debug ("HID_PHYS: %s", hid_id); - - /* build paths */ - parent_i2c = g_udev_device_get_parent_with_subsystem (udev_device, "i2c", NULL); - if (parent_i2c == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "no I2C parent device for %s", - g_udev_device_get_sysfs_path (udev_device)); - return FALSE; - } - driver = g_udev_device_get_driver (parent_i2c); - subsystem = g_udev_device_get_subsystem (parent_i2c); - fn_rebind = g_build_filename ("/sys/bus/", subsystem, "drivers", driver, "bind", NULL); - fn_unbind = g_build_filename ("/sys/bus/", subsystem, "drivers", driver, "unbind", NULL); - - /* unbind hidraw, then bind it again to get a replug */ - fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); - if (!fu_synaptics_rmi_device_writeln (fn_unbind, hid_id, error)) - return FALSE; - if (!fu_synaptics_rmi_device_writeln (fn_rebind, hid_id, error)) - return FALSE; - - /* success */ - return TRUE; + FuSynapticsRmiDeviceClass *klass_rmi = FU_SYNAPTICS_RMI_DEVICE_GET_CLASS (self); + if (klass_rmi->disable_sleep == NULL) + return TRUE; + return klass_rmi->disable_sleep (self, error); } gboolean @@ -951,7 +755,9 @@ g_byte_array_append (bootloader_id_req, priv->flash.bootloader_id, sizeof(priv->flash.bootloader_id)); if (!fu_synaptics_rmi_device_write (self, priv->f34->data_base + block_data_offset, - bootloader_id_req, error)) { + bootloader_id_req, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, + error)) { g_prefix_error (error, "failed to write bootloader_id: "); return FALSE; } @@ -971,6 +777,7 @@ if (!fu_synaptics_rmi_device_write (self, priv->f01->control_base + 1, interrupt_disable_req, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, error)) { g_prefix_error (error, "failed to disable interrupts: "); return FALSE; @@ -979,34 +786,42 @@ } static gboolean -fu_synaptics_rmi_device_attach (FuDevice *device, GError **error) +fu_synaptics_rmi_device_write_firmware (FuDevice *device, + FuFirmware *firmware, + FwupdInstallFlags flags, + GError **error) { FuSynapticsRmiDevice *self = FU_SYNAPTICS_RMI_DEVICE (device); - - /* sanity check */ - if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { - g_debug ("already in runtime mode, skipping"); - return TRUE; + FuSynapticsRmiDevicePrivate *priv = GET_PRIVATE (self); + if (priv->f34->function_version == 0x0 || + priv->f34->function_version == 0x1) { + return fu_synaptics_rmi_v5_device_write_firmware (device, + firmware, + flags, + error); + } + if (priv->f34->function_version == 0x2) { + return fu_synaptics_rmi_v7_device_write_firmware (device, + firmware, + flags, + error); } - - /* reset device */ - if (!fu_synaptics_rmi_device_reset (self, error)) - return FALSE; - - /* rebind to rescan PDT with new firmware running */ - fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); - return fu_synaptics_rmi_device_rebind_driver (self, error); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "f34 function version 0x%02x unsupported", + priv->f34->function_version); + return FALSE; } static void fu_synaptics_rmi_device_init (FuSynapticsRmiDevice *self) { FuSynapticsRmiDevicePrivate *priv = GET_PRIVATE (self); - fu_device_set_protocol (FU_DEVICE (self), "com.synaptics.rmi"); + fu_device_add_protocol (FU_DEVICE (self), "com.synaptics.rmi"); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); - fu_device_set_name (FU_DEVICE (self), "Touchpad"); - fu_device_set_remove_delay (FU_DEVICE (self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_TRIPLET); + priv->current_page = 0xfe; priv->functions = g_ptr_array_new_with_free_func (g_free); } @@ -1024,13 +839,9 @@ { GObjectClass *object_class = G_OBJECT_CLASS (klass); FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - FuUdevDeviceClass *klass_device_udev = FU_UDEV_DEVICE_CLASS (klass); object_class->finalize = fu_synaptics_rmi_device_finalize; klass_device->to_string = fu_synaptics_rmi_device_to_string; klass_device->prepare_firmware = fu_synaptics_rmi_device_prepare_firmware; - klass_device->attach = fu_synaptics_rmi_device_attach; klass_device->setup = fu_synaptics_rmi_device_setup; - klass_device_udev->probe = fu_synaptics_rmi_device_probe; - klass_device_udev->open = fu_synaptics_rmi_device_open; - klass_device_udev->close = fu_synaptics_rmi_device_close; + klass_device->write_firmware = fu_synaptics_rmi_device_write_firmware; } diff -Nru fwupd-1.4.5/plugins/synaptics-rmi/fu-synaptics-rmi-device.h fwupd-1.5.8/plugins/synaptics-rmi/fu-synaptics-rmi-device.h --- fwupd-1.4.5/plugins/synaptics-rmi/fu-synaptics-rmi-device.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-rmi/fu-synaptics-rmi-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -12,6 +12,11 @@ #define FU_TYPE_SYNAPTICS_RMI_DEVICE (fu_synaptics_rmi_device_get_type ()) G_DECLARE_DERIVABLE_TYPE (FuSynapticsRmiDevice, fu_synaptics_rmi_device, FU, SYNAPTICS_RMI_DEVICE, FuUdevDevice) +typedef enum { + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE = 0, + FU_SYNAPTICS_RMI_DEVICE_FLAG_ALLOW_FAILURE = 1 << 0, +} FuSynapticsRmiDeviceFlags; + struct _FuSynapticsRmiDeviceClass { FuUdevDeviceClass parent_class; @@ -19,6 +24,39 @@ GError **error); gboolean (*query_status) (FuSynapticsRmiDevice *self, GError **error); + gboolean (*write) (FuSynapticsRmiDevice *self, + guint16 addr, + GByteArray *req, + FuSynapticsRmiDeviceFlags flags, + GError **error); + GByteArray *(*read) (FuSynapticsRmiDevice *self, + guint16 addr, + gsize req_sz, + GError **error); + GByteArray *(*read_packet_register) (FuSynapticsRmiDevice *self, + guint16 addr, + gsize req_sz, + GError **error); + gboolean (*wait_for_attr) (FuSynapticsRmiDevice *self, + guint8 source_mask, + guint timeout_ms, + GError **error); + gboolean (*set_page) (FuSynapticsRmiDevice *self, + guint8 page, + GError **error); + gboolean (*disable_sleep) (FuSynapticsRmiDevice *self, + GError **error); + gboolean (*write_bus_select) (FuSynapticsRmiDevice *self, + guint8 bus, + GError **error); + gboolean (*query_build_id) (FuSynapticsRmiDevice *self, + guint32 *build_id, + GError **error); + gboolean (*query_product_sub_id) (FuSynapticsRmiDevice *self, + guint8 *product_sub_id, + GError **error); + gboolean (*enter_iep_mode) (FuSynapticsRmiDevice *self, + GError **error); }; typedef struct { @@ -41,11 +79,19 @@ #define RMI_F34_ENABLE_WAIT_MS 300 /* ms */ #define RMI_F34_IDLE_WAIT_MS 500 /* ms */ +#define RMI_DEVICE_PAGE_SELECT_REGISTER 0xff +#define RMI_DEVICE_BUS_SELECT_REGISTER 0xfe + typedef enum { RMI_DEVICE_WAIT_FOR_IDLE_FLAG_NONE = 0, RMI_DEVICE_WAIT_FOR_IDLE_FLAG_REFRESH_F34 = (1 << 0), } RmiDeviceWaitForIdleFlags; +void fu_synaptics_rmi_device_set_iepmode (FuSynapticsRmiDevice *self, + gboolean iepmode); +gboolean fu_synaptics_rmi_device_set_page (FuSynapticsRmiDevice *self, + guint8 page, + GError **error); gboolean fu_synaptics_rmi_device_write_bootloader_id (FuSynapticsRmiDevice *self, GError **error); gboolean fu_synaptics_rmi_device_disable_irqs (FuSynapticsRmiDevice *self, @@ -54,9 +100,14 @@ guint16 addr, gsize req_sz, GError **error); +GByteArray *fu_synaptics_rmi_device_read_packet_register (FuSynapticsRmiDevice *self, + guint16 addr, + gsize req_sz, + GError **error); gboolean fu_synaptics_rmi_device_write (FuSynapticsRmiDevice *self, guint16 addr, GByteArray *req, + FuSynapticsRmiDeviceFlags flags, GError **error); gboolean fu_synaptics_rmi_device_reset (FuSynapticsRmiDevice *self, GError **error); @@ -70,7 +121,16 @@ FuSynapticsRmiFunction *fu_synaptics_rmi_device_get_function (FuSynapticsRmiDevice *self, guint8 function_number, GError **error); -gboolean fu_synaptics_rmi_device_rebind_driver (FuSynapticsRmiDevice *self, - GError **error); gboolean fu_synaptics_rmi_device_poll_wait (FuSynapticsRmiDevice *self, GError **error); +void fu_synaptics_rmi_device_set_sig_size (FuSynapticsRmiDevice *self, + guint16 sig_size); +guint16 fu_synaptics_rmi_device_get_sig_size (FuSynapticsRmiDevice *self); +void fu_synaptics_rmi_device_set_max_page (FuSynapticsRmiDevice *self, + guint8 max_page); +guint8 fu_synaptics_rmi_device_get_max_page (FuSynapticsRmiDevice *self); +gboolean fu_synaptics_rmi_device_enter_iep_mode (FuSynapticsRmiDevice *self, + GError **error); +gboolean fu_synaptics_rmi_device_write_bus_select (FuSynapticsRmiDevice *self, + guint8 bus, + GError **error); diff -Nru fwupd-1.4.5/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.c fwupd-1.5.8/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.c --- fwupd-1.4.5/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,6 +1,6 @@ /* - * Copyright (C) 2012-2014 Andrew Duggan - * Copyright (C) 2012-2019 Synaptics Inc. + * Copyright (C) 2012 Andrew Duggan + * Copyright (C) 2012 Synaptics Inc. * Copyright (C) 2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ @@ -14,15 +14,24 @@ #include "fu-synaptics-rmi-common.h" #include "fu-synaptics-rmi-firmware.h" +typedef enum { + RMI_FIRMWARE_KIND_UNKNOWN = 0x00, + RMI_FIRMWARE_KIND_0X = 0x01, + RMI_FIRMWARE_KIND_10 = 0x10, + RMI_FIRMWARE_KIND_LAST, +} RmiFirmwareKind; + struct _FuSynapticsRmiFirmware { FuFirmware parent_instance; + RmiFirmwareKind kind; guint32 checksum; guint8 io; guint8 bootloader_version; guint32 build_id; - guint16 package_id; + guint32 package_id; guint16 product_info; gchar *product_id; + guint32 sig_size; }; G_DEFINE_TYPE (FuSynapticsRmiFirmware, fu_synaptics_rmi_firmware, FU_TYPE_FIRMWARE) @@ -34,11 +43,13 @@ #define RMI_IMG_CONFIG_SIZE_OFFSET 0x0c #define RMI_IMG_PACKAGE_ID_OFFSET 0x1a #define RMI_IMG_FW_BUILD_ID_OFFSET 0x50 +#define RMI_IMG_SIGNATURE_SIZE_OFFSET 0x54 #define RMI_IMG_PRODUCT_ID_OFFSET 0x10 #define RMI_IMG_PRODUCT_INFO_OFFSET 0x1e #define RMI_IMG_FW_OFFSET 0x100 #define RMI_IMG_V10_CNTR_ADDR_OFFSET 0x0c +#define RMI_IMG_MAX_CONTAINERS 1024 typedef struct __attribute__((packed)) { guint32 content_checksum; @@ -137,20 +148,28 @@ return NULL; } -static void +static gboolean fu_synaptics_rmi_firmware_add_image (FuFirmware *firmware, const gchar *id, - const guint8 *data, gsize sz) + GBytes *fw, gsize offset, gsize sz, + GError **error) { - g_autoptr(GBytes) bytes = g_bytes_new (data, sz); - g_autoptr(FuFirmwareImage) img = fu_firmware_image_new (bytes); + g_autoptr(GBytes) bytes = NULL; + g_autoptr(FuFirmwareImage) img = NULL; + + bytes = fu_common_bytes_new_offset (fw, offset, sz, error); + if (bytes == NULL) + return FALSE; + img = fu_firmware_image_new (bytes); fu_firmware_image_set_id (img, id); fu_firmware_add_image (firmware, img); + return TRUE; } static void fu_synaptics_rmi_firmware_to_string (FuFirmware *firmware, guint idt, GString *str) { FuSynapticsRmiFirmware *self = FU_SYNAPTICS_RMI_FIRMWARE (firmware); + fu_common_string_append_kx (str, idt, "Kind", self->kind); fu_common_string_append_kv (str, idt, "ProductId", self->product_id); fu_common_string_append_kx (str, idt, "BootloaderVersion", self->bootloader_version); fu_common_string_append_kx (str, idt, "IO", self->io); @@ -158,6 +177,7 @@ fu_common_string_append_kx (str, idt, "BuildId", self->build_id); fu_common_string_append_kx (str, idt, "PackageId", self->package_id); fu_common_string_append_kx (str, idt, "ProductInfo", self->product_info); + fu_common_string_append_kx (str, idt, "SigSize", self->sig_size); } static gboolean @@ -169,10 +189,15 @@ guint32 cntrs_len; guint32 offset; guint32 cntr_addr; + guint8 product_id[RMI_PRODUCT_ID_LENGTH] = { 0x0 }; gsize sz = 0; const guint8 *data = g_bytes_get_data (fw, &sz); - cntr_addr = fu_common_read_uint32 (data + RMI_IMG_V10_CNTR_ADDR_OFFSET, G_LITTLE_ENDIAN); + if (!fu_common_read_uint32_safe (data, sz, + RMI_IMG_V10_CNTR_ADDR_OFFSET, + &cntr_addr, G_LITTLE_ENDIAN, + error)) + return FALSE; g_debug ("v10 RmiFirmwareContainerDescriptor at 0x%x", cntr_addr); if (!fu_memcpy_safe ((guint8 *) &desc, sizeof(desc), 0x0, /* dst */ data, sz, cntr_addr, /* src */ @@ -200,12 +225,23 @@ return FALSE; } cntrs_len = GUINT32_FROM_LE(desc.content_length) / 4; + if (cntrs_len > RMI_IMG_MAX_CONTAINERS) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "too many containers in file [%u], maximum is %u", + cntrs_len, (guint) RMI_IMG_MAX_CONTAINERS); + return FALSE; + } g_debug ("offset=0x%x (cntrs_len=%u)", offset, cntrs_len); for (guint32 i = 0; i < cntrs_len; i++) { guint32 content_addr; - guint32 addr = fu_common_read_uint32 (data + offset, G_LITTLE_ENDIAN); + guint32 addr; guint32 length; + if (!fu_common_read_uint32_safe (data, sz, offset, &addr, + G_LITTLE_ENDIAN, error)) + return FALSE; g_debug ("parsing RmiFirmwareContainerDescriptor at 0x%x", addr); if (!fu_memcpy_safe ((guint8 *) &desc, sizeof(desc), 0x0, /* dst */ data, sz, addr, /* src */ @@ -216,7 +252,7 @@ length = GUINT32_FROM_LE(desc.content_length); g_debug ("RmiFirmwareContainerDescriptor 0x%02x @ 0x%x (len 0x%x)", container_id, content_addr, length); - if (length > sz) { + if (length == 0 || length > sz) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, @@ -234,21 +270,30 @@ } switch (container_id) { case RMI_FIRMWARE_CONTAINER_ID_BL: - self->bootloader_version = data[content_addr]; + if (!fu_common_read_uint8_safe (data, sz, content_addr, + &self->bootloader_version, + error)) + return FALSE; break; case RMI_FIRMWARE_CONTAINER_ID_UI: case RMI_FIRMWARE_CONTAINER_ID_CORE_CODE: - fu_synaptics_rmi_firmware_add_image (firmware, "ui", - data + content_addr, length); + if (!fu_synaptics_rmi_firmware_add_image (firmware, "ui", fw, + content_addr, + length, error)) + return FALSE; break; case RMI_FIRMWARE_CONTAINER_ID_FLASH_CONFIG: - fu_synaptics_rmi_firmware_add_image (firmware, "flash-config", - data + content_addr, length); + if (!fu_synaptics_rmi_firmware_add_image (firmware, "flash-config", fw, + content_addr, + length, error)) + return FALSE; break; case RMI_FIRMWARE_CONTAINER_ID_UI_CONFIG: case RMI_FIRMWARE_CONTAINER_ID_CORE_CONFIG: - fu_synaptics_rmi_firmware_add_image (firmware, "config", - data + content_addr, length); + if (!fu_synaptics_rmi_firmware_add_image (firmware, "config", fw, + content_addr, + length, error)) + return FALSE; break; case RMI_FIRMWARE_CONTAINER_ID_GENERAL_INFORMATION: if (length < 0x18 + RMI_PRODUCT_ID_LENGTH) { @@ -259,10 +304,24 @@ content_addr, (guint) length); return FALSE; } + g_clear_pointer (&self->product_id, g_free); self->io = 1; - self->package_id = fu_common_read_uint32 (data + content_addr, G_LITTLE_ENDIAN); - self->build_id = fu_common_read_uint32 (data + content_addr + 4, G_LITTLE_ENDIAN); - self->product_id = g_strndup ((const gchar *) data + content_addr + 0x18, RMI_PRODUCT_ID_LENGTH); + if (!fu_common_read_uint32_safe (data, sz, + content_addr, + &self->package_id, + G_LITTLE_ENDIAN, + error)) + return FALSE; + if (!fu_common_read_uint32_safe (data, sz, + content_addr + 0x04, + &self->build_id, + G_LITTLE_ENDIAN, + error)) + return FALSE; + if (!fu_memcpy_safe (product_id, sizeof(product_id), 0x0, /* dst */ + data, sz, content_addr + 0x18, /* src */ + sizeof(product_id), error)) + return FALSE; break; default: g_debug ("unsupported container %s [0x%02x]", @@ -272,47 +331,57 @@ } offset += 4; } + if (product_id[0] != '\0') { + g_free (self->product_id); + self->product_id = g_strndup ((const gchar *) product_id, + sizeof(product_id)); + } return TRUE; } static gboolean fu_synaptics_rmi_firmware_parse_v0x (FuFirmware *firmware, GBytes *fw, GError **error) { + FuSynapticsRmiFirmware *self = FU_SYNAPTICS_RMI_FIRMWARE (firmware); guint32 cfg_sz; - guint32 img_sz; + guint32 img_sz = 0; gsize sz = 0; const guint8 *data = g_bytes_get_data (fw, &sz); /* main firmware */ - img_sz = fu_common_read_uint32 (data + RMI_IMG_IMAGE_SIZE_OFFSET, G_LITTLE_ENDIAN); + if (!fu_common_read_uint32_safe (data, sz, + RMI_IMG_IMAGE_SIZE_OFFSET, + &img_sz, + G_LITTLE_ENDIAN, + error)) + return FALSE; if (img_sz > 0) { - if (img_sz > sz - RMI_IMG_FW_OFFSET) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "img_sz offset invalid, got 0x%x, size 0x%x", - (guint) img_sz, (guint) sz - RMI_IMG_FW_OFFSET); - return FALSE; + /* payload, then signature appended */ + if (self->sig_size > 0) { + img_sz -= self->sig_size; + if (!fu_synaptics_rmi_firmware_add_image (firmware, "sig", fw, + RMI_IMG_FW_OFFSET + img_sz, + self->sig_size, + error)) + return FALSE; } - fu_synaptics_rmi_firmware_add_image (firmware, "ui", - data + RMI_IMG_FW_OFFSET, - img_sz); + if (!fu_synaptics_rmi_firmware_add_image (firmware, "ui", fw, + RMI_IMG_FW_OFFSET, + img_sz, error)) + return FALSE; } /* config */ - cfg_sz = fu_common_read_uint32 (data + RMI_IMG_CONFIG_SIZE_OFFSET, G_LITTLE_ENDIAN); + if (!fu_common_read_uint32_safe (data, sz, + RMI_IMG_CONFIG_SIZE_OFFSET, + &cfg_sz, G_LITTLE_ENDIAN, + error)) + return FALSE; if (cfg_sz > 0) { - if (cfg_sz > sz - RMI_IMG_FW_OFFSET) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "cfg_sz offset invalid, got 0x%x, size 0x%x", - (guint) cfg_sz, (guint) sz - RMI_IMG_FW_OFFSET); + if (!fu_synaptics_rmi_firmware_add_image (firmware, "config", fw, + RMI_IMG_FW_OFFSET + img_sz, + cfg_sz, error)) return FALSE; - } - fu_synaptics_rmi_firmware_add_image (firmware, "config", - data + RMI_IMG_FW_OFFSET + img_sz, - cfg_sz); } return TRUE; } @@ -328,6 +397,7 @@ FuSynapticsRmiFirmware *self = FU_SYNAPTICS_RMI_FIRMWARE (firmware); gsize sz = 0; guint32 checksum_calculated; + guint32 firmware_size = 0; const guint8 *data = g_bytes_get_data (fw, &sz); /* check minimum size */ @@ -347,9 +417,14 @@ } /* verify checksum */ - self->checksum = fu_common_read_uint32 (data + RMI_IMG_CHECKSUM_OFFSET, G_LITTLE_ENDIAN); + if (!fu_common_read_uint32_safe (data, sz, + RMI_IMG_CHECKSUM_OFFSET, + &self->checksum, + G_LITTLE_ENDIAN, + error)) + return FALSE; checksum_calculated = fu_synaptics_rmi_generate_checksum (data + 4, sz - 4); - if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + if ((flags & FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM) == 0) { if (self->checksum != checksum_calculated) { g_set_error (error, FWUPD_ERROR, @@ -361,14 +436,36 @@ } /* parse legacy image */ + g_clear_pointer (&self->product_id, g_free); self->io = data[RMI_IMG_IO_OFFSET]; self->bootloader_version = data[RMI_IMG_BOOTLOADER_VERSION_OFFSET]; if (self->io == 1) { - self->build_id = fu_common_read_uint32 (data + RMI_IMG_FW_BUILD_ID_OFFSET, G_LITTLE_ENDIAN); - self->package_id = fu_common_read_uint32 (data + RMI_IMG_PACKAGE_ID_OFFSET, G_LITTLE_ENDIAN); + if (!fu_common_read_uint32_safe (data, sz, + RMI_IMG_FW_BUILD_ID_OFFSET, + &self->build_id, + G_LITTLE_ENDIAN, + error)) + return FALSE; + if (!fu_common_read_uint32_safe (data, sz, + RMI_IMG_PACKAGE_ID_OFFSET, + &self->package_id, + G_LITTLE_ENDIAN, + error)) + return FALSE; } self->product_id = g_strndup ((const gchar *) data + RMI_IMG_PRODUCT_ID_OFFSET, RMI_PRODUCT_ID_LENGTH); - self->product_info = fu_common_read_uint16 (data + RMI_IMG_PRODUCT_INFO_OFFSET, G_LITTLE_ENDIAN); + if (!fu_common_read_uint16_safe (data, sz, + RMI_IMG_PRODUCT_INFO_OFFSET, + &self->product_info, + G_LITTLE_ENDIAN, + error)) + return FALSE; + if (!fu_common_read_uint32_safe (data, sz, + RMI_IMG_IMAGE_SIZE_OFFSET, + &firmware_size, + G_LITTLE_ENDIAN, + error)) + return FALSE; /* parse partitions, but ignore lockdown */ switch (self->bootloader_version) { @@ -377,12 +474,22 @@ case 4: case 5: case 6: + if ((self->io & 0x10) >> 1) { + if (!fu_common_read_uint32_safe (data, sz, + RMI_IMG_SIGNATURE_SIZE_OFFSET, + &self->sig_size, + G_LITTLE_ENDIAN, + error)) + return FALSE; + } if (!fu_synaptics_rmi_firmware_parse_v0x (firmware, fw, error)) return FALSE; + self->kind = RMI_FIRMWARE_KIND_0X; break; case 16: if (!fu_synaptics_rmi_firmware_parse_v10 (firmware, fw, error)) return FALSE; + self->kind = RMI_FIRMWARE_KIND_10; break; default: g_set_error (error, @@ -397,30 +504,58 @@ return TRUE; } -GBytes * -fu_synaptics_rmi_firmware_generate_v0x (void) +guint32 +fu_synaptics_rmi_firmware_get_sig_size (FuSynapticsRmiFirmware *self) +{ + return self->sig_size; +} + +static GBytes * +fu_synaptics_rmi_firmware_write_v0x (FuFirmware *firmware, GError **error) { + FuSynapticsRmiFirmware *self = FU_SYNAPTICS_RMI_FIRMWARE (firmware); GByteArray *buf = g_byte_array_new (); + gsize bufsz = 0; + g_autoptr(FuFirmwareImage) img = NULL; + g_autoptr(GBytes) buf_blob = NULL; + + /* default image */ + img = fu_firmware_get_image_default (firmware, error); + if (img == NULL) + return NULL; + buf_blob = fu_firmware_image_write (img, error); + if (buf_blob == NULL) + return NULL; + bufsz = g_bytes_get_size (buf_blob); /* create empty block */ - g_byte_array_set_size (buf, RMI_IMG_FW_OFFSET + 0x4 + 0x4); + fu_byte_array_set_size (buf, RMI_IMG_FW_OFFSET + 0x4 + bufsz); buf->data[RMI_IMG_IO_OFFSET] = 0x0; /* no build_id or package_id */ buf->data[RMI_IMG_BOOTLOADER_VERSION_OFFSET] = 0x2; /* not hierarchical */ - memcpy (buf->data + RMI_IMG_PRODUCT_ID_OFFSET, "Example", 7); + if (self->product_id != NULL) { + gsize product_id_sz = strlen (self->product_id); + if (!fu_memcpy_safe (buf->data, buf->len, RMI_IMG_PRODUCT_ID_OFFSET, /* dst */ + (const guint8 *) self->product_id, product_id_sz, 0x0, /* src */ + product_id_sz, error)) + return NULL; + } fu_common_write_uint16 (buf->data + RMI_IMG_PRODUCT_INFO_OFFSET, 0x1234, G_LITTLE_ENDIAN); - fu_common_write_uint32 (buf->data + RMI_IMG_IMAGE_SIZE_OFFSET, 0x4, G_LITTLE_ENDIAN); - fu_common_write_uint32 (buf->data + RMI_IMG_CONFIG_SIZE_OFFSET, 0x4, G_LITTLE_ENDIAN); - fu_common_write_uint32 (buf->data + RMI_IMG_FW_OFFSET + 0x0, 0xdead, G_LITTLE_ENDIAN); /* img */ - fu_common_write_uint32 (buf->data + RMI_IMG_FW_OFFSET + 0x4, 0xbeef, G_LITTLE_ENDIAN); /* config */ - fu_common_dump_full (G_LOG_DOMAIN, "v0x", buf->data, buf->len, - 0x20, FU_DUMP_FLAGS_SHOW_ADDRESSES); + fu_common_write_uint32 (buf->data + RMI_IMG_IMAGE_SIZE_OFFSET, bufsz, G_LITTLE_ENDIAN); + fu_common_write_uint32 (buf->data + RMI_IMG_CONFIG_SIZE_OFFSET, bufsz, G_LITTLE_ENDIAN); + fu_common_write_uint32 (buf->data + RMI_IMG_FW_OFFSET + 0x0, 0xdead, G_LITTLE_ENDIAN); /* img */ + fu_common_write_uint32 (buf->data + RMI_IMG_FW_OFFSET + bufsz, 0xbeef, G_LITTLE_ENDIAN); /* config */ return g_byte_array_free_to_bytes (buf); } -GBytes * -fu_synaptics_rmi_firmware_generate_v10 (void) +static GBytes * +fu_synaptics_rmi_firmware_write_v10 (FuFirmware *firmware, GError **error) { + FuSynapticsRmiFirmware *self = FU_SYNAPTICS_RMI_FIRMWARE (firmware); GByteArray *buf = g_byte_array_new (); + gsize bufsz = 0; + g_autoptr(FuFirmwareImage) img = NULL; + g_autoptr(GBytes) buf_blob = NULL; + /* header | desc_hdr | offset_table | desc | flash_config | * \0x0 \0x20 \0x24 \0x44 |0x48 */ RmiFirmwareContainerDescriptor desc_hdr = { @@ -431,20 +566,35 @@ guint32 offset_table[] = { RMI_IMG_FW_OFFSET + 0x24 }; /* offset to first RmiFirmwareContainerDescriptor */ RmiFirmwareContainerDescriptor desc = { .container_id = GUINT16_TO_LE(RMI_FIRMWARE_CONTAINER_ID_FLASH_CONFIG), - .content_length = GUINT32_TO_LE(0x4), + .content_length = GUINT32_TO_LE(bufsz), .content_address = GUINT32_TO_LE(RMI_IMG_FW_OFFSET + 0x44), }; + /* default image */ + img = fu_firmware_get_image_default (firmware, error); + if (img == NULL) + return NULL; + buf_blob = fu_firmware_image_write (img, error); + if (buf_blob == NULL) + return NULL; + bufsz = g_bytes_get_size (buf_blob); + /* create empty block */ - g_byte_array_set_size (buf, RMI_IMG_FW_OFFSET + 0x48); + fu_byte_array_set_size (buf, RMI_IMG_FW_OFFSET + 0x48); buf->data[RMI_IMG_IO_OFFSET] = 0x1; buf->data[RMI_IMG_BOOTLOADER_VERSION_OFFSET] = 16; /* hierarchical */ - memcpy (buf->data + RMI_IMG_PRODUCT_ID_OFFSET, "Example", 7); + if (self->product_id != NULL) { + gsize product_id_sz = strlen (self->product_id); + if (!fu_memcpy_safe (buf->data, buf->len, RMI_IMG_PRODUCT_ID_OFFSET, /* dst */ + (const guint8 *) self->product_id, product_id_sz, 0x0, /* src */ + product_id_sz, error)) + return NULL; + } fu_common_write_uint32 (buf->data + RMI_IMG_FW_BUILD_ID_OFFSET, 0x1234, G_LITTLE_ENDIAN); fu_common_write_uint32 (buf->data + RMI_IMG_PACKAGE_ID_OFFSET, 0x4321, G_LITTLE_ENDIAN); fu_common_write_uint16 (buf->data + RMI_IMG_PRODUCT_INFO_OFFSET, 0x3456, G_LITTLE_ENDIAN); - fu_common_write_uint32 (buf->data + RMI_IMG_IMAGE_SIZE_OFFSET, 0x4, G_LITTLE_ENDIAN); - fu_common_write_uint32 (buf->data + RMI_IMG_CONFIG_SIZE_OFFSET, 0x4, G_LITTLE_ENDIAN); + fu_common_write_uint32 (buf->data + RMI_IMG_IMAGE_SIZE_OFFSET, bufsz, G_LITTLE_ENDIAN); + fu_common_write_uint32 (buf->data + RMI_IMG_CONFIG_SIZE_OFFSET, bufsz, G_LITTLE_ENDIAN); fu_common_write_uint32 (buf->data + RMI_IMG_V10_CNTR_ADDR_OFFSET, RMI_IMG_FW_OFFSET, G_LITTLE_ENDIAN); /* hierarchical section */ @@ -452,22 +602,85 @@ memcpy (buf->data + RMI_IMG_FW_OFFSET + 0x20, offset_table, sizeof(offset_table)); memcpy (buf->data + RMI_IMG_FW_OFFSET + 0x24, &desc, sizeof(desc)); fu_common_write_uint32 (buf->data + RMI_IMG_FW_OFFSET + 0x44, 0xfeed, G_LITTLE_ENDIAN); /* flash_config */ - fu_common_dump_full (G_LOG_DOMAIN, "v10", buf->data, buf->len, - 0x20, FU_DUMP_FLAGS_SHOW_ADDRESSES); return g_byte_array_free_to_bytes (buf); } +static gboolean +fu_synaptics_rmi_firmware_build (FuFirmware *firmware, XbNode *n, GError **error) +{ + FuSynapticsRmiFirmware *self = FU_SYNAPTICS_RMI_FIRMWARE (firmware); + const gchar *product_id; + guint64 tmp; + + /* either 0x or 10 */ + tmp = xb_node_query_text_as_uint (n, "kind", NULL); + if (tmp != G_MAXUINT64) + self->kind = tmp; + + /* any string */ + product_id = xb_node_query_text (n, "product_id", NULL); + if (product_id != NULL) { + gsize product_id_sz = strlen (product_id); + if (product_id_sz > RMI_PRODUCT_ID_LENGTH) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "product_id not supported, %u of %u bytes", + (guint) product_id_sz, + (guint) RMI_PRODUCT_ID_LENGTH); + return FALSE; + } + g_free (self->product_id); + self->product_id = g_strdup (product_id); + } + + /* success */ + return TRUE; +} + +static GBytes * +fu_synaptics_rmi_firmware_write (FuFirmware *firmware, GError **error) +{ + FuSynapticsRmiFirmware *self = FU_SYNAPTICS_RMI_FIRMWARE (firmware); + + /* two supported container formats */ + if (self->kind == RMI_FIRMWARE_KIND_0X) + return fu_synaptics_rmi_firmware_write_v0x (firmware, error); + if (self->kind == RMI_FIRMWARE_KIND_10) + return fu_synaptics_rmi_firmware_write_v10 (firmware, error); + + /* not supported */ + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "kind not supported"); + return NULL; +} + static void fu_synaptics_rmi_firmware_init (FuSynapticsRmiFirmware *self) { + fu_firmware_add_flag (FU_FIRMWARE (self), FU_FIRMWARE_FLAG_HAS_CHECKSUM); +} + +static void +fu_synaptics_rmi_firmware_finalize (GObject *obj) +{ + FuSynapticsRmiFirmware *self = FU_SYNAPTICS_RMI_FIRMWARE (obj); + g_free (self->product_id); + G_OBJECT_CLASS (fu_synaptics_rmi_firmware_parent_class)->finalize (obj); } static void fu_synaptics_rmi_firmware_class_init (FuSynapticsRmiFirmwareClass *klass) { + GObjectClass *object_class = G_OBJECT_CLASS (klass); FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); + object_class->finalize = fu_synaptics_rmi_firmware_finalize; klass_firmware->parse = fu_synaptics_rmi_firmware_parse; klass_firmware->to_string = fu_synaptics_rmi_firmware_to_string; + klass_firmware->build = fu_synaptics_rmi_firmware_build; + klass_firmware->write = fu_synaptics_rmi_firmware_write; } FuFirmware * diff -Nru fwupd-1.4.5/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.h fwupd-1.5.8/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.h --- fwupd-1.4.5/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.h 2021-03-31 20:08:32.000000000 +0000 @@ -12,5 +12,4 @@ G_DECLARE_FINAL_TYPE (FuSynapticsRmiFirmware, fu_synaptics_rmi_firmware, FU, SYNAPTICS_RMI_FIRMWARE, FuFirmware) FuFirmware *fu_synaptics_rmi_firmware_new (void); -GBytes *fu_synaptics_rmi_firmware_generate_v0x (void); -GBytes *fu_synaptics_rmi_firmware_generate_v10 (void); +guint32 fu_synaptics_rmi_firmware_get_sig_size (FuSynapticsRmiFirmware *self); diff -Nru fwupd-1.4.5/plugins/synaptics-rmi/fu-synaptics-rmi-hid-device.c fwupd-1.5.8/plugins/synaptics-rmi/fu-synaptics-rmi-hid-device.c --- fwupd-1.4.5/plugins/synaptics-rmi/fu-synaptics-rmi-hid-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-rmi/fu-synaptics-rmi-hid-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,563 @@ +/* + * Copyright (C) 2020 Richard Hughes + * Copyright (c) 2020 Synaptics Incorporated. + * Copyright (C) 2012 Andrew Duggan + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include + +#include "fu-io-channel.h" + +#include "fu-synaptics-rmi-hid-device.h" +#include "fu-synaptics-rmi-v5-device.h" +#include "fu-synaptics-rmi-v7-device.h" + +struct _FuSynapticsRmiHidDevice { + FuSynapticsRmiDevice parent_instance; + FuIOChannel *io_channel; +}; + +G_DEFINE_TYPE (FuSynapticsRmiHidDevice, fu_synaptics_rmi_hid_device, FU_TYPE_SYNAPTICS_RMI_DEVICE) + +#define RMI_WRITE_REPORT_ID 0x9 /* output report */ +#define RMI_READ_ADDR_REPORT_ID 0xa /* output report */ +#define RMI_READ_DATA_REPORT_ID 0xb /* input report */ +#define RMI_ATTN_REPORT_ID 0xc /* input report */ +#define RMI_SET_RMI_MODE_REPORT_ID 0xf /* feature report */ + +#define RMI_DEVICE_DEFAULT_TIMEOUT 2000 + +#define HID_RMI4_REPORT_ID 0 +#define HID_RMI4_READ_INPUT_COUNT 1 +#define HID_RMI4_READ_INPUT_DATA 2 +#define HID_RMI4_READ_OUTPUT_ADDR 2 +#define HID_RMI4_READ_OUTPUT_COUNT 4 +#define HID_RMI4_WRITE_OUTPUT_COUNT 1 +#define HID_RMI4_WRITE_OUTPUT_ADDR 2 +#define HID_RMI4_WRITE_OUTPUT_DATA 4 +#define HID_RMI4_FEATURE_MODE 1 +#define HID_RMI4_ATTN_INTERUPT_SOURCES 1 +#define HID_RMI4_ATTN_DATA 2 + +/* + * This bit disables whatever sleep mode may be selected by the sleep_mode + * field and forces the device to run at full power without sleeping. + */ +#define RMI_F01_CRTL0_NOSLEEP_BIT (1 << 2) + +/* + * msleep mode controls power management on the device and affects all + * functions of the device. + */ +#define RMI_F01_CTRL0_SLEEP_MODE_MASK 0x03 + +#define RMI_SLEEP_MODE_NORMAL 0x00 +#define RMI_SLEEP_MODE_SENSOR_SLEEP 0x01 + +static GByteArray * +fu_synaptics_rmi_hid_device_read (FuSynapticsRmiDevice *rmi_device, + guint16 addr, + gsize req_sz, + GError **error) +{ + FuSynapticsRmiHidDevice *self = FU_SYNAPTICS_RMI_HID_DEVICE (rmi_device); + g_autoptr(GByteArray) buf = g_byte_array_new (); + g_autoptr(GByteArray) req = g_byte_array_new (); + + /* maximum size */ + if (req_sz > 0xffff) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "data to read was too long"); + return NULL; + } + + /* report then old 1 byte read count */ + fu_byte_array_append_uint8 (req, RMI_READ_ADDR_REPORT_ID); + fu_byte_array_append_uint8 (req, 0x0); + + /* address */ + fu_byte_array_append_uint16 (req, addr, G_LITTLE_ENDIAN); + + /* read output count */ + fu_byte_array_append_uint16 (req, req_sz, G_LITTLE_ENDIAN); + + /* request */ + for (guint j = req->len; j < 21; j++) + fu_byte_array_append_uint8 (req, 0x0); + if (g_getenv ("FWUPD_SYNAPTICS_RMI_VERBOSE") != NULL) { + fu_common_dump_full (G_LOG_DOMAIN, "ReportWrite", + req->data, req->len, + 80, FU_DUMP_FLAGS_NONE); + } + if (!fu_io_channel_write_byte_array (self->io_channel, req, RMI_DEVICE_DEFAULT_TIMEOUT, + FU_IO_CHANNEL_FLAG_SINGLE_SHOT | + FU_IO_CHANNEL_FLAG_USE_BLOCKING_IO, error)) + return NULL; + + /* keep reading responses until we get enough data */ + while (buf->len < req_sz) { + guint8 input_count_sz = 0; + g_autoptr(GByteArray) res = NULL; + res = fu_io_channel_read_byte_array (self->io_channel, req_sz, + RMI_DEVICE_DEFAULT_TIMEOUT, + FU_IO_CHANNEL_FLAG_SINGLE_SHOT, + error); + if (res == NULL) + return NULL; + if (res->len == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "response zero sized"); + return NULL; + } + if (g_getenv ("FWUPD_SYNAPTICS_RMI_VERBOSE") != NULL) { + fu_common_dump_full (G_LOG_DOMAIN, "ReportRead", + res->data, res->len, + 80, FU_DUMP_FLAGS_NONE); + } + + /* ignore non data report events */ + if (res->data[HID_RMI4_REPORT_ID] != RMI_READ_DATA_REPORT_ID) { + g_debug ("ignoring report with ID 0x%02x", + res->data[HID_RMI4_REPORT_ID]); + continue; + } + if (res->len < HID_RMI4_READ_INPUT_DATA) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "response too small: 0x%02x", + res->len); + return NULL; + } + input_count_sz = res->data[HID_RMI4_READ_INPUT_COUNT]; + if (input_count_sz == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "input count zero"); + return NULL; + } + if (input_count_sz + (guint) HID_RMI4_READ_INPUT_DATA > res->len) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "underflow 0x%02x from expected 0x%02x", + res->len, (guint) input_count_sz + HID_RMI4_READ_INPUT_DATA); + return NULL; + } + g_byte_array_append (buf, + res->data + HID_RMI4_READ_INPUT_DATA, + input_count_sz); + + } + if (g_getenv ("FWUPD_SYNAPTICS_RMI_VERBOSE") != NULL) { + fu_common_dump_full (G_LOG_DOMAIN, "DeviceRead", buf->data, buf->len, + 80, FU_DUMP_FLAGS_NONE); + } + + return g_steal_pointer (&buf); +} + +static GByteArray * +fu_synaptics_rmi_hid_device_read_packet_register (FuSynapticsRmiDevice *rmi_device, + guint16 addr, + gsize req_sz, + GError **error) +{ + return fu_synaptics_rmi_hid_device_read (rmi_device, addr, req_sz, error); +} + +static gboolean +fu_synaptics_rmi_hid_device_write (FuSynapticsRmiDevice *rmi_device, + guint16 addr, + GByteArray *req, + FuSynapticsRmiDeviceFlags flags, + GError **error) +{ + FuSynapticsRmiHidDevice *self = FU_SYNAPTICS_RMI_HID_DEVICE (rmi_device); + guint8 len = 0x0; + g_autoptr(GByteArray) buf = g_byte_array_new (); + + /* check size */ + if (req != NULL) { + if (req->len > 0xff) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "data to write was too long"); + return FALSE; + } + len = req->len; + } + + /* report */ + fu_byte_array_append_uint8 (buf, RMI_WRITE_REPORT_ID); + + /* length */ + fu_byte_array_append_uint8 (buf, len); + + /* address */ + fu_byte_array_append_uint16 (buf, addr, G_LITTLE_ENDIAN); + + /* optional data */ + if (req != NULL) + g_byte_array_append (buf, req->data, req->len); + + /* pad out to 21 bytes for some reason */ + for (guint i = buf->len; i < 21; i++) + fu_byte_array_append_uint8 (buf, 0x0); + if (g_getenv ("FWUPD_SYNAPTICS_RMI_VERBOSE") != NULL) { + fu_common_dump_full (G_LOG_DOMAIN, "DeviceWrite", buf->data, buf->len, + 80, FU_DUMP_FLAGS_NONE); + } + + return fu_io_channel_write_byte_array (self->io_channel, buf, + RMI_DEVICE_DEFAULT_TIMEOUT, + FU_IO_CHANNEL_FLAG_SINGLE_SHOT | + FU_IO_CHANNEL_FLAG_USE_BLOCKING_IO, + error); +} + +static gboolean +fu_synaptics_rmi_hid_device_wait_for_attr (FuSynapticsRmiDevice *rmi_device, + guint8 source_mask, + guint timeout_ms, + GError **error) +{ + FuSynapticsRmiHidDevice *self = FU_SYNAPTICS_RMI_HID_DEVICE (rmi_device); + g_autoptr(GTimer) timer = g_timer_new (); + + /* wait for event from hardware */ + while (g_timer_elapsed (timer, NULL) * 1000.f < timeout_ms) { + g_autoptr(GByteArray) res = NULL; + g_autoptr(GError) error_local = NULL; + + /* read from fd */ + res = fu_io_channel_read_byte_array (self->io_channel, + HID_RMI4_ATTN_INTERUPT_SOURCES + 1, + timeout_ms, + FU_IO_CHANNEL_FLAG_NONE, + &error_local); + if (res == NULL) { + if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) + break; + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; + } + if (g_getenv ("FWUPD_SYNAPTICS_RMI_VERBOSE") != NULL) { + fu_common_dump_full (G_LOG_DOMAIN, "ReportRead", + res->data, res->len, + 80, FU_DUMP_FLAGS_NONE); + } + if (res->len < HID_RMI4_ATTN_INTERUPT_SOURCES + 1) { + g_debug ("attr: ignoring small read of %u", res->len); + continue; + } + if (res->data[HID_RMI4_REPORT_ID] != RMI_ATTN_REPORT_ID) { + g_debug ("attr: ignoring invalid report ID 0x%x", + res->data[HID_RMI4_REPORT_ID]); + continue; + } + + /* success */ + if (source_mask & res->data[HID_RMI4_ATTN_INTERUPT_SOURCES]) + return TRUE; + + /* wrong mask */ + g_debug ("source mask did not match: 0x%x", + res->data[HID_RMI4_ATTN_INTERUPT_SOURCES]); + } + + /* urgh */ + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "no attr report, timed out"); + return FALSE; +} + +typedef enum { + HID_RMI4_MODE_MOUSE = 0, + HID_RMI4_MODE_ATTN_REPORTS = 1, + HID_RMI4_MODE_NO_PACKED_ATTN_REPORTS = 2, +} FuSynapticsRmiHidMode; + +static gboolean +fu_synaptics_rmi_hid_device_set_mode (FuSynapticsRmiHidDevice *self, + FuSynapticsRmiHidMode mode, + GError **error) +{ + const guint8 data[] = { 0x0f, mode }; + if (g_getenv ("FWUPD_SYNAPTICS_RMI_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "SetMode", data, sizeof(data)); + return fu_udev_device_ioctl (FU_UDEV_DEVICE (self), + HIDIOCSFEATURE(sizeof(data)), (guint8 *) data, + NULL, error); +} + +static gboolean +fu_synaptics_rmi_hid_device_open (FuDevice *device, GError **error) +{ + FuSynapticsRmiHidDevice *self = FU_SYNAPTICS_RMI_HID_DEVICE (device); + + /* FuUdevDevice->open */ + if (!FU_DEVICE_CLASS (fu_synaptics_rmi_hid_device_parent_class)->open (device, error)) + return FALSE; + + /* set up touchpad so we can query it */ + self->io_channel = fu_io_channel_unix_new (fu_udev_device_get_fd (FU_UDEV_DEVICE (device))); + if (!fu_synaptics_rmi_hid_device_set_mode (self, HID_RMI4_MODE_ATTN_REPORTS, error)) + return FALSE; + + /* success */ + return TRUE; +} + +static gboolean +fu_synaptics_rmi_hid_device_close (FuDevice *device, GError **error) +{ + FuSynapticsRmiHidDevice *self = FU_SYNAPTICS_RMI_HID_DEVICE (device); + g_autoptr(GError) error_local = NULL; + + /* turn it back to mouse mode */ + if (!fu_synaptics_rmi_hid_device_set_mode (self, HID_RMI4_MODE_MOUSE, &error_local)) { + /* if just detached for replug, swallow error */ + if (!g_error_matches (error_local, + FWUPD_ERROR, + FWUPD_ERROR_PERMISSION_DENIED)) { + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; + } + g_debug ("ignoring: %s", error_local->message); + } + + fu_udev_device_set_fd (FU_UDEV_DEVICE (device), -1); + g_clear_object (&self->io_channel); + + /* FuUdevDevice->close */ + return FU_DEVICE_CLASS (fu_synaptics_rmi_hid_device_parent_class)->close (device, error); +} + +static gboolean +fu_synaptics_rmi_hid_device_rebind_driver (FuSynapticsRmiDevice *self, GError **error) +{ + GUdevDevice *udev_device = fu_udev_device_get_dev (FU_UDEV_DEVICE (self)); + const gchar *hid_id; + const gchar *driver; + const gchar *subsystem; + g_autofree gchar *fn_rebind = NULL; + g_autofree gchar *fn_unbind = NULL; + g_autoptr(GUdevDevice) parent_hid = NULL; + g_autoptr(GUdevDevice) parent_i2c = NULL; + + /* get actual HID node */ + parent_hid = g_udev_device_get_parent_with_subsystem (udev_device, "hid", NULL); + if (parent_hid == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "no HID parent device for %s", + g_udev_device_get_sysfs_path (udev_device)); + return FALSE; + } + + /* find the physical ID to use for the rebind */ + hid_id = g_udev_device_get_property (parent_hid, "HID_PHYS"); + if (hid_id == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "no HID_PHYS in %s", + g_udev_device_get_sysfs_path (parent_hid)); + return FALSE; + } + g_debug ("HID_PHYS: %s", hid_id); + + /* build paths */ + parent_i2c = g_udev_device_get_parent_with_subsystem (udev_device, "i2c", NULL); + if (parent_i2c == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "no I2C parent device for %s", + g_udev_device_get_sysfs_path (udev_device)); + return FALSE; + } + driver = g_udev_device_get_driver (parent_i2c); + subsystem = g_udev_device_get_subsystem (parent_i2c); + fn_rebind = g_build_filename ("/sys/bus/", subsystem, "drivers", driver, "bind", NULL); + fn_unbind = g_build_filename ("/sys/bus/", subsystem, "drivers", driver, "unbind", NULL); + + /* unbind hidraw, then bind it again to get a replug */ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + if (!fu_synaptics_rmi_device_writeln (fn_unbind, hid_id, error)) + return FALSE; + if (!fu_synaptics_rmi_device_writeln (fn_rebind, hid_id, error)) + return FALSE; + + /* success */ + return TRUE; +} + +static gboolean +fu_synaptics_rmi_hid_device_detach (FuDevice *device, GError **error) +{ + FuSynapticsRmiDevice *self = FU_SYNAPTICS_RMI_DEVICE (device); + FuSynapticsRmiFunction *f34; + + f34 = fu_synaptics_rmi_device_get_function (self, 0x34, error); + if (f34 == NULL) + return FALSE; + if (f34->function_version == 0x0 || + f34->function_version == 0x1) { + if (!fu_synaptics_rmi_v5_device_detach (device, error)) + return FALSE; + } else if (f34->function_version == 0x2) { + if (!fu_synaptics_rmi_v7_device_detach (device, error)) + return FALSE; + } else { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "f34 function version 0x%02x unsupported", + f34->function_version); + return FALSE; + } + return fu_synaptics_rmi_hid_device_rebind_driver (self, error); +} + +static gboolean +fu_synaptics_rmi_hid_device_attach (FuDevice *device, GError **error) +{ + FuSynapticsRmiDevice *self = FU_SYNAPTICS_RMI_DEVICE (device); + + /* sanity check */ + if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { + g_debug ("already in runtime mode, skipping"); + return TRUE; + } + + /* reset device */ + if (!fu_synaptics_rmi_device_reset (self, error)) + return FALSE; + + /* rebind to rescan PDT with new firmware running */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + return fu_synaptics_rmi_hid_device_rebind_driver (self, error); +} + +static gboolean +fu_synaptics_rmi_hid_device_set_page (FuSynapticsRmiDevice *self, + guint8 page, + GError **error) +{ + g_autoptr(GByteArray) req = g_byte_array_new (); + fu_byte_array_append_uint8 (req, page); + if (!fu_synaptics_rmi_device_write (self, + RMI_DEVICE_PAGE_SELECT_REGISTER, + req, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, + error)) { + g_prefix_error (error, "failed to set RMA page 0x%x: ", page); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_synaptics_rmi_hid_device_probe (FuDevice *device, GError **error) +{ + /* FuUdevDevice->probe */ + if (!FU_DEVICE_CLASS (fu_synaptics_rmi_hid_device_parent_class)->probe (device, error)) + return FALSE; + return fu_udev_device_set_physical_id (FU_UDEV_DEVICE (device), "hid", error); +} + +static gboolean +fu_synaptics_rmi_hid_device_disable_sleep (FuSynapticsRmiDevice *rmi_device, + GError **error) +{ + FuSynapticsRmiFunction *f01; + g_autoptr(GByteArray) f01_control0 = NULL; + + f01 = fu_synaptics_rmi_device_get_function (rmi_device, 0x34, error); + if (f01 == NULL) + return FALSE; + f01_control0 = fu_synaptics_rmi_device_read (rmi_device, f01->control_base, 0x1, error); + if (f01_control0 == NULL) { + g_prefix_error (error, "failed to write get f01_control0: "); + return FALSE; + } + f01_control0->data[0] |= RMI_F01_CRTL0_NOSLEEP_BIT; + f01_control0->data[0] = (f01_control0->data[0] & ~RMI_F01_CTRL0_SLEEP_MODE_MASK) | RMI_SLEEP_MODE_NORMAL; + if (!fu_synaptics_rmi_device_write (rmi_device, + f01->control_base, + f01_control0, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, + error)) { + g_prefix_error (error, "failed to write f01_control0: "); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_synaptics_rmi_hid_device_query_status (FuSynapticsRmiDevice *rmi_device, + GError **error) +{ + FuSynapticsRmiFunction *f34; + f34 = fu_synaptics_rmi_device_get_function (rmi_device, 0x34, error); + if (f34 == NULL) + return FALSE; + if (f34->function_version == 0x0 || + f34->function_version == 0x1) { + return fu_synaptics_rmi_v5_device_query_status (rmi_device, error); + } + if (f34->function_version == 0x2) { + return fu_synaptics_rmi_v7_device_query_status (rmi_device, error); + } + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "f34 function version 0x%02x unsupported", + f34->function_version); + return FALSE; +} + +static void +fu_synaptics_rmi_hid_device_init (FuSynapticsRmiHidDevice *self) +{ + fu_device_set_name (FU_DEVICE (self), "Touchpad"); + fu_device_set_remove_delay (FU_DEVICE (self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); + fu_synaptics_rmi_device_set_max_page (FU_SYNAPTICS_RMI_DEVICE (self), 0xff); +} + +static void +fu_synaptics_rmi_hid_device_class_init (FuSynapticsRmiHidDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuSynapticsRmiDeviceClass *klass_rmi = FU_SYNAPTICS_RMI_DEVICE_CLASS (klass); + klass_device->attach = fu_synaptics_rmi_hid_device_attach; + klass_device->detach = fu_synaptics_rmi_hid_device_detach; + klass_device->probe = fu_synaptics_rmi_hid_device_probe; + klass_device->open = fu_synaptics_rmi_hid_device_open; + klass_device->close = fu_synaptics_rmi_hid_device_close; + klass_rmi->write = fu_synaptics_rmi_hid_device_write; + klass_rmi->read = fu_synaptics_rmi_hid_device_read; + klass_rmi->wait_for_attr = fu_synaptics_rmi_hid_device_wait_for_attr; + klass_rmi->set_page = fu_synaptics_rmi_hid_device_set_page; + klass_rmi->query_status = fu_synaptics_rmi_hid_device_query_status; + klass_rmi->read_packet_register = fu_synaptics_rmi_hid_device_read_packet_register; + klass_rmi->disable_sleep = fu_synaptics_rmi_hid_device_disable_sleep; +} diff -Nru fwupd-1.4.5/plugins/synaptics-rmi/fu-synaptics-rmi-hid-device.h fwupd-1.5.8/plugins/synaptics-rmi/fu-synaptics-rmi-hid-device.h --- fwupd-1.4.5/plugins/synaptics-rmi/fu-synaptics-rmi-hid-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-rmi/fu-synaptics-rmi-hid-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2019 Richard Hughes + * Copyright (c) 2012 Synaptics Incorporated. + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-synaptics-rmi-device.h" + +#define FU_TYPE_SYNAPTICS_RMI_HID_DEVICE (fu_synaptics_rmi_hid_device_get_type ()) +G_DECLARE_FINAL_TYPE(FuSynapticsRmiHidDevice, fu_synaptics_rmi_hid_device, FU, SYNAPTICS_RMI_HID_DEVICE, FuSynapticsRmiDevice) diff -Nru fwupd-1.4.5/plugins/synaptics-rmi/fu-synaptics-rmi-ps2-device.c fwupd-1.5.8/plugins/synaptics-rmi/fu-synaptics-rmi-ps2-device.c --- fwupd-1.4.5/plugins/synaptics-rmi/fu-synaptics-rmi-ps2-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-rmi/fu-synaptics-rmi-ps2-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,1006 @@ +/* + * Copyright (C) 2020 Richard Hughes + * Copyright (c) 2020 Synaptics Incorporated. + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-io-channel.h" + +#include "fu-synaptics-rmi-ps2-device.h" +#include "fu-synaptics-rmi-v5-device.h" +#include "fu-synaptics-rmi-v7-device.h" + +struct _FuSynapticsRmiPs2Device { + FuSynapticsRmiDevice parent_instance; + FuIOChannel *io_channel; +}; + +G_DEFINE_TYPE (FuSynapticsRmiPs2Device, fu_synaptics_rmi_ps2_device, FU_TYPE_SYNAPTICS_RMI_DEVICE) + +enum EPS2DataPortCommand { + edpAuxFullRMIBackDoor = 0x7F, + edpAuxAccessModeByte1 = 0xE0, + edpAuxAccessModeByte2 = 0xE1, + edpAuxIBMReadSecondaryID = 0xE1, + edpAuxSetScaling1To1 = 0xE6, + edpAuxSetScaling2To1 = 0xE7, + edpAuxSetResolution = 0xE8, + edpAuxStatusRequest = 0xE9, + edpAuxSetStreamMode = 0xEA, + edpAuxReadData = 0xEB, + edpAuxResetWrapMode = 0xEC, + edpAuxSetWrapMode = 0xEE, + edpAuxSetRemoteMode = 0xF0, + edpAuxReadDeviceType = 0xF2, + edpAuxSetSampleRate = 0xF3, + edpAuxEnable = 0xF4, + edpAuxDisable = 0xF5, + edpAuxSetDefault = 0xF6, + edpAuxResend = 0xFE, + edpAuxReset = 0xFF, +}; + +typedef enum { + esdrTouchPad = 0x47, + esdrStyk = 0x46, + esdrControlBar = 0x44, + esdrRGBControlBar = 0x43, +} ESynapticsDeviceResponse; + +enum EStatusRequestSequence { + esrIdentifySynaptics = 0x00, + esrReadTouchPadModes = 0x01, + esrReadModeByte = 0x01, + esrReadEdgeMargins = 0x02, + esrReadCapabilities = 0x02, + esrReadModelID = 0x03, + esrReadCompilationDate = 0x04, + esrReadSerialNumberPrefix = 0x06, + esrReadSerialNumberSuffix = 0x07, + esrReadResolutions = 0x08, + esrReadExtraCapabilities1 = 0x09, + esrReadExtraCapabilities2 = 0x0A, + esrReadExtraCapabilities3 = 0x0B, + esrReadExtraCapabilities4 = 0x0C, + esrReadExtraCapabilities5 = 0x0D, + esrReadCoordinates = 0x0D, + esrReadExtraCapabilities6 = 0x0E, + esrReadExtraCapabilities7 = 0x0F, +}; + +enum EPS2DataPortStatus { + edpsAcknowledge = 0xFA, + edpsError = 0xFC, + edpsResend = 0xFE, + edpsTimeOut = 0x100 +}; + +enum ESetSampleRateSequence { + essrSetModeByte1 = 0x0A, + essrSetModeByte2 = 0x14, + essrSetModeByte3 = 0x28, + essrSetModeByte4 = 0x3C, + essrSetDeluxeModeByte1 = 0x0A, + essrSetDeluxeModeByte2 = 0x3C, + essrSetDeluxeModeByte3 = 0xC8, + essrFastRecalibrate = 0x50, + essrPassThroughCommandTunnel = 0x28 +}; + +enum EDeviceType { + edtUnknown, + edtTouchPad, +}; + +enum EStickDeviceType { + esdtNone = 0, + esdtIBM, + esdtJYTSyna = 5, + esdtSynaptics = 6, + esdtUnknown = 0xFFFFFFFF +}; + +static gboolean +fu_synaptics_rmi_ps2_device_read_ack (FuSynapticsRmiPs2Device *self, + guint8 *pbuf, + GError **error) +{ + for(guint i = 0 ; i < 60; i++) { + g_autoptr(GError) error_local = NULL; + if (!fu_io_channel_read_raw (self->io_channel, pbuf, 0x1, + NULL, 10, + FU_IO_CHANNEL_FLAG_USE_BLOCKING_IO, + &error_local)) { + if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) { + g_warning ("read timed out: %u", i); + g_usleep (30); + continue; + } + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; + } + return TRUE; + } + g_set_error (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "read timed out"); + return FALSE; +} + +/* read a single byte from the touchpad */ +static gboolean +fu_synaptics_rmi_ps2_device_read_byte (FuSynapticsRmiPs2Device *self, + guint8 *pbuf, + guint timeout, + GError **error) +{ + g_return_val_if_fail (timeout > 0, FALSE); + return fu_io_channel_read_raw (self->io_channel, pbuf, 0x1, + NULL, timeout, + FU_IO_CHANNEL_FLAG_NONE, + error); +} + +/* write a single byte to the touchpad and the read the acknowledge */ +static gboolean +fu_synaptics_rmi_ps2_device_write_byte (FuSynapticsRmiPs2Device *self, + guint8 buf, + guint timeout, + FuSynapticsRmiDeviceFlags flags, + GError **error) +{ + gboolean do_write = TRUE; + g_return_val_if_fail (timeout > 0, FALSE); + for (guint i = 0; ; i++) { + guint8 res = 0; + g_autoptr(GError) error_local = NULL; + if (do_write) { + if (!fu_io_channel_write_raw (self->io_channel, + &buf, sizeof(buf), + timeout, + FU_IO_CHANNEL_FLAG_FLUSH_INPUT | + FU_IO_CHANNEL_FLAG_USE_BLOCKING_IO, + error)) + return FALSE; + } + do_write = FALSE; + + for (;;) { + /* attempt to read acknowledge... */ + if (!fu_synaptics_rmi_ps2_device_read_ack (self, &res, &error_local)) { + if (i > 3) { + g_propagate_prefixed_error (error, + g_steal_pointer (&error_local), + "read ack failed: "); + return FALSE; + } + g_warning ("read ack failed: %s, retrying", error_local->message); + break; + } + if (res == edpsAcknowledge) + return TRUE; + if (res == edpsResend) { + do_write = TRUE; + g_debug ("resend"); + g_usleep (G_USEC_PER_SEC); + break; + } + if (res == edpsError) { + do_write = TRUE; + g_debug ("error"); + g_usleep (1000 * 10); + break; + } + g_debug ("other response: 0x%x", res); + g_usleep (1000 * 10); + } + if (i >= 3) { + if (flags & FU_SYNAPTICS_RMI_DEVICE_FLAG_ALLOW_FAILURE) { + /* just break without error return because FW + * will not return ACK for commands like RESET */ + break; + } + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "cannot write byte after retries"); + return FALSE; + } + } + + /* success */ + return TRUE; +} + +static gboolean +fu_synaptics_rmi_ps2_device_set_resolution_sequence (FuSynapticsRmiPs2Device *self, + guint8 arg, + gboolean send_e6s, + GError **error) +{ + /* send set scaling twice if send_e6s */ + for (gint i = send_e6s ? 2 : 1; i > 0; --i) { + if (!fu_synaptics_rmi_ps2_device_write_byte (self, edpAuxSetScaling1To1, 50, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, + error)) + return FALSE; + } + for (gint i = 3; i >= 0; --i) { + guint8 ucTwoBitArg = (arg >> (i * 2)) & 0x3; + if (!fu_synaptics_rmi_ps2_device_write_byte (self, edpAuxSetResolution, 50, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, + error)) { + return FALSE; + } + if (!fu_synaptics_rmi_ps2_device_write_byte (self, ucTwoBitArg, 50, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, + error)) + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_synaptics_rmi_ps2_device_status_request_sequence (FuSynapticsRmiPs2Device *self, + guint8 ucArgument, + guint32 *buf, + GError **error) +{ + gboolean success = FALSE; + + /* allow 3 retries */ + for (guint i = 0; i < 3; ++i) { + g_autoptr(GError) error_local = NULL; + if (!fu_synaptics_rmi_ps2_device_set_resolution_sequence (self, + ucArgument, + FALSE, + &error_local)) { + g_debug ("failed set try #%u: %s", + i, error_local->message); + continue; + } + if (!fu_synaptics_rmi_ps2_device_write_byte (self, + edpAuxStatusRequest, + 10, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, + &error_local)) { + g_debug ("failed write try #%u: %s", + i, error_local->message); + continue; + } + success = TRUE; + break; + } + if (success == FALSE) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "failed"); + return FALSE; + } + + /* read the response from the status request */ + for (gint i = 0; i < 3; ++i) { + guint8 tmp = 0x0; + if (!fu_synaptics_rmi_ps2_device_read_byte (self, &tmp, 10, error)) { + g_prefix_error (error, "failed to read byte: "); + return FALSE; + } + *buf = ((*buf) << 8) | tmp; + } + + return TRUE; +} + +static gboolean +fu_synaptics_rmi_ps2_device_sample_rate_sequence (FuSynapticsRmiPs2Device *self, + guint8 param, + guint8 arg, + gboolean send_e6s, + GError **error) +{ + /* allow 3 retries */ + for (guint i = 0; ; i++) { + g_autoptr(GError) error_local = NULL; + if (i > 0) { + /* always send two E6s when retrying */ + send_e6s = TRUE; + } + if (!fu_synaptics_rmi_ps2_device_set_resolution_sequence (self, arg, send_e6s, &error_local) || + !fu_synaptics_rmi_ps2_device_write_byte (self, edpAuxSetSampleRate, 50, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, + &error_local) || + !fu_synaptics_rmi_ps2_device_write_byte (self, param, 50, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, + &error_local)) { + if (i > 3) { + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; + } + g_warning ("failed, will retry: %s", error_local->message); + continue; + } + break; + } + /* success */ + return TRUE; +} + +static gboolean +fu_synaptics_rmi_ps2_device_detect_synaptics_styk (FuSynapticsRmiPs2Device *self, + gboolean *result, + GError **error) +{ + guint8 buf; + if (!fu_synaptics_rmi_ps2_device_write_byte (self, edpAuxIBMReadSecondaryID, 10, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, + error)) { + g_prefix_error (error, "failed to write IBMReadSecondaryID(0xE1): "); + return FALSE; + } + if (!fu_synaptics_rmi_ps2_device_read_byte (self, &buf, 10, error)) { + g_prefix_error (error, "failed to receive IBMReadSecondaryID: "); + return FALSE; + } + if (buf == esdtJYTSyna || buf == esdtSynaptics) + *result = TRUE; + return TRUE; +} + +static gboolean +fu_synaptics_rmi_ps2_device_query_build_id (FuSynapticsRmiDevice *rmi_device, + guint32 *build_id, + GError **error) +{ + FuSynapticsRmiPs2Device *self = FU_SYNAPTICS_RMI_PS2_DEVICE (rmi_device); + guint32 buf = 0; + gboolean is_synaptics_styk = FALSE; + ESynapticsDeviceResponse esdr; + + if (!fu_synaptics_rmi_ps2_device_status_request_sequence (self, + esrIdentifySynaptics, + &buf, + error)) { + g_prefix_error (error, "failed to request IdentifySynaptics: "); + return FALSE; + } + g_debug ("identify Synaptics response = 0x%x", buf); + + esdr = (buf & 0xFF00) >> 8; + if (!fu_synaptics_rmi_ps2_device_detect_synaptics_styk (self, + &is_synaptics_styk, + error)) { + g_prefix_error (error, "failed to detect Synaptics styk: "); + return FALSE; + } + fu_synaptics_rmi_device_set_iepmode (rmi_device, FALSE); + if (esdr == esdrTouchPad || is_synaptics_styk) { + /* Get the firmware id from the Extra Capabilities 2 Byte + * The firmware id is located in bits 0 - 23 */ + if (!fu_synaptics_rmi_ps2_device_status_request_sequence (self, + esrReadExtraCapabilities2, + build_id, + error)) { + g_prefix_error (error, "failed to read extraCapabilities2: "); + return FALSE; + } + } + return TRUE; +} + +static gboolean +fu_synaptics_rmi_ps2_device_query_product_sub_id (FuSynapticsRmiDevice *rmi_device, + guint8 *sub_id, + GError **error) +{ + FuSynapticsRmiPs2Device *self = FU_SYNAPTICS_RMI_PS2_DEVICE (rmi_device); + guint32 buf = 0; + if (!fu_synaptics_rmi_ps2_device_status_request_sequence (self, esrReadCapabilities, &buf, error)) { + g_prefix_error (error, "failed to status_request_sequence read esrReadCapabilities: "); + return FALSE; + } + *sub_id = (buf >> 8) & 0xFF; + return TRUE; +} + +static gboolean +fu_synaptics_rmi_ps2_device_enter_iep_mode (FuSynapticsRmiDevice *rmi_device, + GError **error) +{ + FuSynapticsRmiPs2Device *self = FU_SYNAPTICS_RMI_PS2_DEVICE (rmi_device); + + /* disable stream */ + if (!fu_synaptics_rmi_ps2_device_write_byte (self, edpAuxDisable, 50, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, + error)) { + g_prefix_error (error, "failed to disable stream mode: "); + return FALSE; + } + + /* enable RMI mode */ + if (!fu_synaptics_rmi_ps2_device_sample_rate_sequence (self, + essrSetModeByte2, + edpAuxFullRMIBackDoor, + FALSE, + error)) { + g_prefix_error (error, "failed to enter RMI mode: "); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_synaptics_rmi_ps2_device_write_rmi_register (FuSynapticsRmiPs2Device *self, + guint8 addr, + const guint8 *buf, + guint8 buflen, + guint timeout, + FuSynapticsRmiDeviceFlags flags, + GError **error) +{ + g_return_val_if_fail (timeout > 0, FALSE); + + if (!fu_synaptics_rmi_device_enter_iep_mode (FU_SYNAPTICS_RMI_DEVICE (self), error)) + return FALSE; + if (!fu_synaptics_rmi_ps2_device_write_byte (self, + edpAuxSetScaling2To1, + timeout, + flags, + error)) { + g_prefix_error (error, "failed to edpAuxSetScaling2To1: "); + return FALSE; + } + if (!fu_synaptics_rmi_ps2_device_write_byte (self, + edpAuxSetSampleRate, + timeout, + flags, + error)) { + g_prefix_error (error, "failed to edpAuxSetSampleRate: "); + return FALSE; + } + if (!fu_synaptics_rmi_ps2_device_write_byte (self, + addr, + timeout, + flags, + error)) { + g_prefix_error (error, "failed to write address: "); + return FALSE; + } + for (guint8 i = 0; i < buflen; i++) { + if (!fu_synaptics_rmi_ps2_device_write_byte (self, + edpAuxSetSampleRate, + timeout, + flags, + error)) { + g_prefix_error (error, "failed to set byte %u: ", i); + return FALSE; + } + if (!fu_synaptics_rmi_ps2_device_write_byte (self, + buf[i], + timeout, + flags, + error)) { + g_prefix_error (error, "failed to write byte %u: ", i); + return FALSE; + } + } + + /* success */ + g_usleep (1000 * 20); + return TRUE; +} + +static gboolean +fu_synaptics_rmi_ps2_device_read_rmi_register (FuSynapticsRmiPs2Device *self, + guint8 addr, + guint8 *buf, + GError **error) +{ + g_return_val_if_fail (buf != NULL, FALSE); + + if (!fu_synaptics_rmi_device_enter_iep_mode (FU_SYNAPTICS_RMI_DEVICE (self), error)) + return FALSE; + for (guint retries = 0; ; retries++) { + g_autoptr(GError) error_local = NULL; + if (!fu_synaptics_rmi_ps2_device_write_byte (self, edpAuxSetScaling2To1, 50, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, + error) || + !fu_synaptics_rmi_ps2_device_write_byte (self, edpAuxSetSampleRate, 50, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, + error) || + !fu_synaptics_rmi_ps2_device_write_byte (self, addr, 50, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, + error) || + !fu_synaptics_rmi_ps2_device_write_byte (self, edpAuxStatusRequest, 50, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, + error)) { + g_prefix_error (error, "failed to write command in Read RMI register: "); + return FALSE; + } + if (!fu_synaptics_rmi_ps2_device_read_byte (self, buf, 10, &error_local)) { + if (retries++ > 2) { + g_propagate_prefixed_error (error, + g_steal_pointer (&error_local), + "failed to read byte @0x%x after %u retries: ", + addr, retries); + return FALSE; + } + g_debug ("failed to read byte @0x%x: %s", + addr, + error_local->message); + continue; + } + + /* success */ + break; + } + + /* success */ + g_usleep (1000 * 20); + return TRUE; +} + +static GByteArray * +fu_synaptics_rmi_ps2_device_read_rmi_packet_register (FuSynapticsRmiPs2Device *self, + guint8 addr, + guint req_sz, + GError **error) +{ + g_autoptr(GByteArray) buf = g_byte_array_new (); + + if (!fu_synaptics_rmi_ps2_device_enter_iep_mode (FU_SYNAPTICS_RMI_DEVICE (self), error)) + return NULL; + if (!fu_synaptics_rmi_ps2_device_write_byte (self, edpAuxSetScaling2To1, 50, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, + error) || + !fu_synaptics_rmi_ps2_device_write_byte (self, edpAuxSetSampleRate, 50, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, + error) || + !fu_synaptics_rmi_ps2_device_write_byte (self, addr, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, + FALSE, error) || + !fu_synaptics_rmi_ps2_device_write_byte (self, edpAuxStatusRequest, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, + FALSE, error)) { + g_prefix_error (error, "failed to write command in Read RMI Packet Register: "); + return NULL; + } + for (guint i = 0; i < req_sz; ++i) { + guint8 tmp = 0; + if (!fu_synaptics_rmi_ps2_device_read_byte (self, &tmp, 10, error)) { + g_prefix_error (error, "failed to read byte %u: ", i); + return NULL; + } + fu_byte_array_append_uint8 (buf, tmp); + } + + g_usleep (1000 * 20); + return g_steal_pointer (&buf); +} + +static gboolean +fu_synaptics_rmi_ps2_device_query_status (FuSynapticsRmiDevice *rmi_device, + GError **error) +{ + FuSynapticsRmiFunction *f34; + g_debug ("ps2 query status"); + f34 = fu_synaptics_rmi_device_get_function (rmi_device, 0x34, error); + if (f34 == NULL) + return FALSE; + if (f34->function_version == 0x0 || + f34->function_version == 0x1) { + return fu_synaptics_rmi_v5_device_query_status (rmi_device, error); + } + if (f34->function_version == 0x2) { + return fu_synaptics_rmi_v7_device_query_status (rmi_device, error); + } + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "f34 function version 0x%02x unsupported", + f34->function_version); + return FALSE; +} + +static gboolean +fu_synaptics_rmi_ps2_device_set_page (FuSynapticsRmiDevice *rmi_device, + guint8 page, + GError **error) +{ + FuSynapticsRmiPs2Device *self = FU_SYNAPTICS_RMI_PS2_DEVICE (rmi_device); + if (!fu_synaptics_rmi_ps2_device_write_rmi_register (self, + RMI_DEVICE_PAGE_SELECT_REGISTER, + &page, + 1, + 20, + FALSE, + error)) { + g_prefix_error (error, "failed to write page %u: ", page); + return FALSE; + } + return TRUE; +} + +static GByteArray * +fu_synaptics_rmi_ps2_device_read (FuSynapticsRmiDevice *rmi_device, + guint16 addr, + gsize req_sz, + GError **error) +{ + FuSynapticsRmiPs2Device *self = FU_SYNAPTICS_RMI_PS2_DEVICE (rmi_device); + g_autoptr(GByteArray) buf = NULL; + g_autofree gchar *dump = NULL; + + if (!fu_synaptics_rmi_device_set_page (rmi_device, + addr >> 8, + error)) { + g_prefix_error (error, "failed to set RMI page:"); + return NULL; + } + + for (guint retries = 0; ; retries++) { + buf = g_byte_array_new (); + for (guint i = 0; i < req_sz; i++) { + guint8 tmp = 0x0; + if (!fu_synaptics_rmi_ps2_device_read_rmi_register (self, + (guint8) ((addr & 0x00FF) + i), + &tmp, + error)) { + g_prefix_error (error, + "failed register read 0x%x: ", + addr + i); + return NULL; + } + fu_byte_array_append_uint8 (buf, tmp); + } + if (buf->len != req_sz) { + g_debug ("buf->len(%u) != req_sz(%u)", buf->len, (guint) req_sz); + if (retries++ > 2) { + g_set_error (error, + G_IO_ERROR, G_IO_ERROR_FAILED, + "buffer length did not match: %u vs %u", + buf->len, (guint) req_sz); + return NULL; + } + continue; + } + break; + } + dump = g_strdup_printf ("R %x", addr); + if (g_getenv ("FWUPD_SYNAPTICS_RMI_VERBOSE") != NULL) { + fu_common_dump_full (G_LOG_DOMAIN, dump, + buf->data, buf->len, + 80, FU_DUMP_FLAGS_NONE); + } + return g_steal_pointer (&buf); +} + +static GByteArray * +fu_synaptics_rmi_ps2_device_read_packet_register (FuSynapticsRmiDevice *rmi_device, + guint16 addr, + gsize req_sz, + GError **error) +{ + FuSynapticsRmiPs2Device *self = FU_SYNAPTICS_RMI_PS2_DEVICE (rmi_device); + g_autoptr(GByteArray) buf = NULL; + + if (!fu_synaptics_rmi_device_set_page (rmi_device, + addr >> 8, + error)) { + g_prefix_error (error, "failed to set RMI page:"); + return NULL; + } + + buf = fu_synaptics_rmi_ps2_device_read_rmi_packet_register (self, + addr, + req_sz, + error); + if (buf == NULL) { + g_prefix_error (error, + "failed packet register read %x: ", + addr); + return NULL; + } + + if (g_getenv ("FWUPD_SYNAPTICS_RMI_VERBOSE") != NULL) { + g_autofree gchar *dump = g_strdup_printf ("R %x", addr); + fu_common_dump_full (G_LOG_DOMAIN, dump, + buf->data, buf->len, + 80, FU_DUMP_FLAGS_NONE); + } + return g_steal_pointer (&buf); +} + +static gboolean +fu_synaptics_rmi_ps2_device_write (FuSynapticsRmiDevice *rmi_device, + guint16 addr, + GByteArray *req, + FuSynapticsRmiDeviceFlags flags, + GError **error) +{ + FuSynapticsRmiPs2Device *self = FU_SYNAPTICS_RMI_PS2_DEVICE (rmi_device); + if (!fu_synaptics_rmi_device_set_page (rmi_device, + addr >> 8, + error)) { + g_prefix_error (error, "failed to set RMI page: "); + return FALSE; + } + if (!fu_synaptics_rmi_ps2_device_write_rmi_register (self, + addr & 0x00FF, + req->data, + req->len, + 1000, /* timeout */ + flags, + error)) { + g_prefix_error (error, + "failed to write register %x: ", + addr); + return FALSE; + } + if (g_getenv ("FWUPD_SYNAPTICS_RMI_VERBOSE") != NULL) { + g_autofree gchar *str = g_strdup_printf ("W %x", addr); + fu_common_dump_full (G_LOG_DOMAIN, str, + req->data, req->len, + 80, FU_DUMP_FLAGS_NONE); + } + return TRUE; +} + +static gboolean +fu_synaptics_rmi_ps2_device_write_bus_select (FuSynapticsRmiDevice *rmi_device, + guint8 bus, + GError **error) +{ + g_autoptr(GByteArray) req = g_byte_array_new (); + fu_byte_array_append_uint8 (req, bus); + if (!fu_synaptics_rmi_ps2_device_write (rmi_device, + RMI_DEVICE_BUS_SELECT_REGISTER, + req, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, + error)) { + g_prefix_error (error, "failed to write rmi register %u: ", bus); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_synaptics_rmi_ps2_device_probe (FuDevice *device, GError **error) +{ + /* FuUdevDevice->probe */ + if (!FU_DEVICE_CLASS (fu_synaptics_rmi_ps2_device_parent_class)->probe (device, error)) + return FALSE; + + /* psmouse is the usual mode, but serio is needed for update */ + if (g_strcmp0 (fu_udev_device_get_driver (FU_UDEV_DEVICE (device)), "serio_raw") == 0) { + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + } else { + fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + } + + /* set the physical ID */ + return fu_udev_device_set_physical_id (FU_UDEV_DEVICE (device), "platform", error); +} + +static gboolean +fu_synaptics_rmi_ps2_device_open (FuDevice *device, GError **error) +{ + FuSynapticsRmiPs2Device *self = FU_SYNAPTICS_RMI_PS2_DEVICE (device); + guint8 buf[2] = { 0x0 }; + + /* FuUdevDevice->open */ + if (!FU_DEVICE_CLASS (fu_synaptics_rmi_ps2_device_parent_class)->open (device, error)) + return FALSE; + + /* create channel */ + self->io_channel = fu_io_channel_unix_new (fu_udev_device_get_fd (FU_UDEV_DEVICE (device))); + + /* in serio_raw mode */ + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { + + /* clear out any data in the serio_raw queue */ + for(guint i = 0; i < 0xffff; i++) { + guint8 tmp = 0; + if (!fu_synaptics_rmi_ps2_device_read_byte (self, &tmp, 20, NULL)) + break; + } + + /* send reset -- may take 300-500ms */ + if (!fu_synaptics_rmi_ps2_device_write_byte (self, edpAuxReset, 600, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, + error)) { + g_prefix_error (error, "failed to reset: "); + return FALSE; + } + + /* read the 0xAA 0x00 announcing the touchpad is ready */ + if (!fu_synaptics_rmi_ps2_device_read_byte(self, &buf[0], 500, error) || + !fu_synaptics_rmi_ps2_device_read_byte(self, &buf[1], 500, error)) { + g_prefix_error (error, "failed to read 0xAA00: "); + return FALSE; + } + if (buf[0] != 0xAA || buf[1] != 0x00) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "failed to read 0xAA00, got 0x%02X%02X: ", + buf[0], buf[1]); + return FALSE; + } + + /* disable the device so that it stops reporting finger data */ + if (!fu_synaptics_rmi_ps2_device_write_byte (self, edpAuxDisable, 50, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, + error)) { + g_prefix_error (error, "failed to disable stream mode: "); + return FALSE; + } + } + + /* success */ + return TRUE; +} + +static gboolean +fu_synaptics_rmi_ps2_device_close (FuDevice *device, GError **error) +{ + FuSynapticsRmiPs2Device *self = FU_SYNAPTICS_RMI_PS2_DEVICE (device); + fu_udev_device_set_fd (FU_UDEV_DEVICE (device), -1); + g_clear_object (&self->io_channel); + + /* FuUdevDevice->close */ + return FU_DEVICE_CLASS (fu_synaptics_rmi_ps2_device_parent_class)->close (device, error);} + +static gboolean +fu_synaptics_rmi_ps2_device_detach (FuDevice *device, GError **error) +{ + FuSynapticsRmiDevice *self = FU_SYNAPTICS_RMI_DEVICE (device); + FuSynapticsRmiFunction *f34; + + /* sanity check */ + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { + g_debug ("already in bootloader mode, skipping"); + return TRUE; + } + + /* put in serio_raw mode so that we can do register writes */ + if (!fu_udev_device_write_sysfs (FU_UDEV_DEVICE (device), + "drvctl", "serio_raw", error)) { + g_prefix_error (error, "failed to write to drvctl: "); + return FALSE; + } + + /* rescan device */ + if (!fu_device_close (device, error)) + return FALSE; + if (!fu_device_rescan (device, error)) + return FALSE; + if (!fu_device_open (device, error)) + return FALSE; + + f34 = fu_synaptics_rmi_device_get_function (self, 0x34, error); + if (f34 == NULL) + return FALSE; + if (f34->function_version == 0x0 || + f34->function_version == 0x1) { + if (!fu_synaptics_rmi_v5_device_detach (device, error)) + return FALSE; + } else if (f34->function_version == 0x2) { + if (!fu_synaptics_rmi_v7_device_detach (device, error)) + return FALSE; + } else { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "f34 function version 0x%02x unsupported", + f34->function_version); + return FALSE; + } + + if (!fu_synaptics_rmi_device_enter_iep_mode (self, error)) { + return FALSE; + } + + if (!fu_synaptics_rmi_ps2_device_query_status (self, error)) { + g_prefix_error (error, "failed to query status after detach: "); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_synaptics_rmi_ps2_device_setup (FuDevice *device, GError **error) +{ + /* we can only scan the PDT in serio_raw mode */ + if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) + return TRUE; + return FU_DEVICE_CLASS (fu_synaptics_rmi_ps2_device_parent_class)->setup (device, error); +} + +static gboolean +fu_synaptics_rmi_ps2_device_attach (FuDevice *device, GError **error) +{ + FuSynapticsRmiDevice *rmi_device = FU_SYNAPTICS_RMI_DEVICE (device); + + /* sanity check */ + if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { + g_debug ("already in runtime mode, skipping"); + return TRUE; + } + + /* Set iepmode before reset device forcibly because of FW requirement */ + fu_synaptics_rmi_device_set_iepmode (rmi_device, FALSE); + + /* delay after writing */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + fu_device_sleep_with_progress (device, 2); + + /* reset device */ + if (!fu_synaptics_rmi_device_enter_iep_mode (rmi_device, error)) + return FALSE; + if (!fu_synaptics_rmi_device_reset (rmi_device, error)) { + g_prefix_error (error, "failed to reset device: "); + return FALSE; + } + + /* delay after reset */ + fu_device_sleep_with_progress (device, 5); + + /* back to psmouse */ + if (!fu_udev_device_write_sysfs (FU_UDEV_DEVICE (device), + "drvctl", "psmouse", error)) { + g_prefix_error (error, "failed to write to drvctl: "); + return FALSE; + } + + /* rescan device */ + return fu_device_rescan (device, error); +} + +static void +fu_synaptics_rmi_ps2_device_init (FuSynapticsRmiPs2Device *self) +{ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL); + fu_device_set_name (FU_DEVICE (self), "TouchStyk"); + fu_device_set_vendor (FU_DEVICE (self), "Synaptics"); + fu_device_add_vendor_id (FU_DEVICE (self), "HIDRAW:0x06CB"); + fu_synaptics_rmi_device_set_max_page (FU_SYNAPTICS_RMI_DEVICE (self), 0x1); + fu_udev_device_set_flags (FU_UDEV_DEVICE (self), + FU_UDEV_DEVICE_FLAG_OPEN_READ | + FU_UDEV_DEVICE_FLAG_OPEN_WRITE); +} + +static gboolean +fu_synaptics_rmi_ps2_device_wait_for_attr (FuSynapticsRmiDevice *rmi_device, + guint8 source_mask, + guint timeout_ms, + GError **error) +{ + g_usleep (1000 * timeout_ms); + return TRUE; +} + +static void +fu_synaptics_rmi_ps2_device_class_init (FuSynapticsRmiPs2DeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuSynapticsRmiDeviceClass *klass_rmi = FU_SYNAPTICS_RMI_DEVICE_CLASS (klass); + klass_device->attach = fu_synaptics_rmi_ps2_device_attach; + klass_device->detach = fu_synaptics_rmi_ps2_device_detach; + klass_device->setup = fu_synaptics_rmi_ps2_device_setup; + klass_device->probe = fu_synaptics_rmi_ps2_device_probe; + klass_device->open = fu_synaptics_rmi_ps2_device_open; + klass_device->close = fu_synaptics_rmi_ps2_device_close; + klass_rmi->read = fu_synaptics_rmi_ps2_device_read; + klass_rmi->write = fu_synaptics_rmi_ps2_device_write; + klass_rmi->set_page = fu_synaptics_rmi_ps2_device_set_page; + klass_rmi->query_status = fu_synaptics_rmi_ps2_device_query_status; + klass_rmi->query_build_id = fu_synaptics_rmi_ps2_device_query_build_id; + klass_rmi->query_product_sub_id = fu_synaptics_rmi_ps2_device_query_product_sub_id; + klass_rmi->wait_for_attr = fu_synaptics_rmi_ps2_device_wait_for_attr; + klass_rmi->enter_iep_mode = fu_synaptics_rmi_ps2_device_enter_iep_mode; + klass_rmi->write_bus_select = fu_synaptics_rmi_ps2_device_write_bus_select; + klass_rmi->read_packet_register = fu_synaptics_rmi_ps2_device_read_packet_register; +} diff -Nru fwupd-1.4.5/plugins/synaptics-rmi/fu-synaptics-rmi-ps2-device.h fwupd-1.5.8/plugins/synaptics-rmi/fu-synaptics-rmi-ps2-device.h --- fwupd-1.4.5/plugins/synaptics-rmi/fu-synaptics-rmi-ps2-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-rmi/fu-synaptics-rmi-ps2-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2020 Richard Hughes + * Copyright (c) 2020 Synaptics Incorporated. + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-synaptics-rmi-device.h" + +#define FU_TYPE_SYNAPTICS_RMI_PS2_DEVICE (fu_synaptics_rmi_ps2_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuSynapticsRmiPs2Device, fu_synaptics_rmi_ps2_device, FU, SYNAPTICS_RMI_PS2_DEVICE, FuSynapticsRmiDevice) + diff -Nru fwupd-1.4.5/plugins/synaptics-rmi/fu-synaptics-rmi-v5-device.c fwupd-1.5.8/plugins/synaptics-rmi/fu-synaptics-rmi-v5-device.c --- fwupd-1.4.5/plugins/synaptics-rmi/fu-synaptics-rmi-v5-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-rmi/fu-synaptics-rmi-v5-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,6 +1,6 @@ /* - * Copyright (C) 2012-2014 Andrew Duggan - * Copyright (C) 2012-2019 Synaptics Inc. + * Copyright (C) 2012 Andrew Duggan + * Copyright (C) 2012 Synaptics Inc. * Copyright (C) 2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ @@ -10,6 +10,7 @@ #include "fu-chunk.h" #include "fu-common.h" +#include "fu-synaptics-rmi-firmware.h" #include "fu-synaptics-rmi-v5-device.h" #include "fwupd-error.h" @@ -18,6 +19,7 @@ #define RMI_F34_ERASE_ALL 0x03 #define RMI_F34_WRITE_LOCKDOWN_BLOCK 0x04 #define RMI_F34_WRITE_CONFIG_BLOCK 0x06 +#define RMI_F34_WRITE_SIGNATURE 0x0b #define RMI_F34_ENABLE_FLASH_PROG 0x0f #define RMI_F34_BLOCK_SIZE_OFFSET 1 @@ -34,14 +36,18 @@ g_autoptr(GByteArray) enable_req = g_byte_array_new (); /* sanity check */ - if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { - g_debug ("already in runtime mode, skipping"); + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { + g_debug ("already in bootloader mode, skipping"); return TRUE; } /* disable interrupts */ if (!fu_synaptics_rmi_device_disable_irqs (self, error)) return FALSE; + if (!fu_synaptics_rmi_device_write_bus_select (self, 0, error)) { + g_prefix_error (error, "failed to write bus select: "); + return FALSE; + } /* unlock bootloader and rebind kernel driver */ if (!fu_synaptics_rmi_device_write_bootloader_id (self, error)) @@ -50,6 +56,7 @@ if (!fu_synaptics_rmi_device_write (self, flash->status_addr, enable_req, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, error)) { g_prefix_error (error, "failed to enable programming: "); return FALSE; @@ -57,7 +64,7 @@ fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); g_usleep (1000 * RMI_F34_ENABLE_WAIT_MS); - return fu_synaptics_rmi_device_rebind_driver (self, error); + return TRUE; } static gboolean @@ -77,11 +84,14 @@ if (!fu_synaptics_rmi_device_write (self, flash->status_addr, erase_cmd, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, error)) { g_prefix_error (error, "failed to erase core config: "); return FALSE; } - g_usleep (1000 * RMI_F34_ENABLE_WAIT_MS); + g_usleep (1000 * RMI_F34_ERASE_WAIT_MS); + if (!fu_synaptics_rmi_device_enter_iep_mode (self, error)) + return FALSE; if (!fu_synaptics_rmi_device_wait_for_idle (self, RMI_F34_ERASE_WAIT_MS, RMI_DEVICE_WAIT_FOR_IDLE_FLAG_REFRESH_F34, @@ -104,7 +114,9 @@ g_byte_array_append (req, data, datasz); fu_byte_array_append_uint8 (req, cmd); - if (!fu_synaptics_rmi_device_write (self, address, req, error)) { + if (!fu_synaptics_rmi_device_write (self, address, req, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, + error)) { g_prefix_error (error, "failed to write block @0x%x: ", address); return FALSE; } @@ -118,19 +130,112 @@ return TRUE; } +static gboolean +fu_synaptics_rmi_v5_device_secure_check (FuDevice *device, + GBytes *payload, + GBytes *signature, + GError **error) +{ + FuSynapticsRmiDevice *self = FU_SYNAPTICS_RMI_DEVICE (device); + FuSynapticsRmiFunction *f34; + guint16 rsa_pubkey_len = fu_synaptics_rmi_device_get_sig_size (self) / 8; + guint16 rsa_block_cnt = rsa_pubkey_len / 3; + guint16 rsa_block_remain = rsa_pubkey_len % 3; + g_autoptr(GByteArray) pubkey_buf = g_byte_array_new (); + g_autoptr(GBytes) pubkey = NULL; + + if (g_getenv ("FWUPD_SYNAPTICS_RMI_VERBOSE") != NULL) + fu_common_dump_bytes (G_LOG_DOMAIN, "Signature", signature); + + f34 = fu_synaptics_rmi_device_get_function (self, 0x34, error); + if (f34 == NULL) + return FALSE; + + /* parse RSA public key modulus */ + if (rsa_block_remain > 0) + rsa_block_cnt += 1; + for (guint retries = 0; ; retries++) { + /* need read another register to reset the offset of packet register */ + if (!fu_synaptics_rmi_v5_device_query_status (self, error)) { + g_prefix_error (error, "failed to read status: "); + return FALSE; + } + if (!fu_synaptics_rmi_device_enter_iep_mode (self, error)) + return FALSE; + for (guint16 block_num = 0; block_num < rsa_block_cnt; block_num++) { + g_autoptr(GByteArray) res = NULL; + res = fu_synaptics_rmi_device_read_packet_register (self, + f34->query_base + 14, /* addr of flash properties + 5 */ + 0x3, + error); + if (res == NULL) + return FALSE; + if (res->len != 0x3) + g_debug ("read %u bytes in return", res->len); + if (rsa_block_remain && block_num + 1 == rsa_block_cnt) { + g_byte_array_remove_range (res, + rsa_block_remain, + res->len - rsa_block_remain); + } + for (guint i = 0 ; i < res->len / 2 ; i++) { + guint8 tmp = res->data[i]; + res->data[i] = res->data[res->len - i - 1]; + res->data[res->len - i - 1] = tmp; + } + if (rsa_block_remain && block_num + 1 == rsa_block_cnt) { + g_byte_array_prepend (pubkey_buf, res->data, rsa_block_remain); + } else { + g_byte_array_prepend (pubkey_buf, res->data, res->len); + } + } + if (rsa_pubkey_len != pubkey_buf->len) { + if (retries++ > 2) { + g_set_error (error, + G_IO_ERROR, G_IO_ERROR_FAILED, + "RSA public key length not matched %u: after %u retries: ", + pubkey_buf->len, retries); + return FALSE; + } + g_byte_array_set_size (pubkey_buf, 0); + continue; + } + + /* success */ + break; + } + if (g_getenv ("FWUPD_SYNAPTICS_RMI_VERBOSE") != NULL) { + fu_common_dump_full (G_LOG_DOMAIN, "RSA public key", + pubkey_buf->data, pubkey_buf->len, + 16, FU_DUMP_FLAGS_NONE); + } + + /* sanity check size */ + if (rsa_pubkey_len != pubkey_buf->len) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "RSA public key length did not match: %u != %u: ", + rsa_pubkey_len, pubkey_buf->len); + return FALSE; + } + pubkey = g_bytes_new (pubkey_buf->data, pubkey_buf->len); + return fu_synaptics_verify_sha256_signature (payload, pubkey, signature, error); +} + gboolean fu_synaptics_rmi_v5_device_write_firmware (FuDevice *device, FuFirmware *firmware, FwupdInstallFlags flags, GError **error) { - FuSynapticsRmiDevice *self = FU_SYNAPTICS_RMI_DEVICE (device); FuSynapticsRmiFlash *flash = fu_synaptics_rmi_device_get_flash (self); FuSynapticsRmiFunction *f34; + FuSynapticsRmiFirmware *rmi_firmware = FU_SYNAPTICS_RMI_FIRMWARE (firmware); guint32 address; g_autoptr(GBytes) bytes_bin = NULL; g_autoptr(GBytes) bytes_cfg = NULL; + g_autoptr(GBytes) signature_bin = NULL; g_autoptr(GPtrArray) chunks_bin = NULL; g_autoptr(GPtrArray) chunks_cfg = NULL; g_autoptr(GByteArray) req_addr = g_byte_array_new (); @@ -143,6 +248,8 @@ "not bootloader, perhaps need detach?!"); return FALSE; } + if (!fu_synaptics_rmi_device_enter_iep_mode (self, error)) + return FALSE; /* check is idle */ if (!fu_synaptics_rmi_device_wait_for_idle (self, 0, @@ -151,6 +258,22 @@ g_prefix_error (error, "not idle: "); return FALSE; } + if (fu_synaptics_rmi_firmware_get_sig_size (rmi_firmware) == 0 && + fu_synaptics_rmi_device_get_sig_size (self) != 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "device secure but firmware not secure"); + return FALSE; + } + if (fu_synaptics_rmi_firmware_get_sig_size (rmi_firmware) != 0 && + fu_synaptics_rmi_device_get_sig_size (self) == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "device not secure but firmware secure"); + return FALSE; + } /* f34 */ f34 = fu_synaptics_rmi_device_get_function (self, 0x34, error); @@ -165,6 +288,18 @@ if (bytes_cfg == NULL) return FALSE; + /* verify signature if set */ + signature_bin = fu_firmware_get_image_by_id_bytes (firmware, "sig", NULL); + if (signature_bin != NULL) { + if (!fu_synaptics_rmi_v5_device_secure_check (device, + bytes_bin, + signature_bin, + error)) { + g_prefix_error (error, "secure check failed: "); + return FALSE; + } + } + /* disable powersaving */ if (!fu_synaptics_rmi_device_disable_sleep (self, error)) { g_prefix_error (error, "failed to disable sleep: "); @@ -187,7 +322,9 @@ /* write initial address */ fu_byte_array_append_uint16 (req_addr, 0x0, G_LITTLE_ENDIAN); fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); - if (!fu_synaptics_rmi_device_write (self, f34->data_base, req_addr, error)) { + if (!fu_synaptics_rmi_device_write (self, f34->data_base, req_addr, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, + error)) { g_prefix_error (error, "failed to write 1st address zero: "); return FALSE; } @@ -210,18 +347,53 @@ if (!fu_synaptics_rmi_v5_device_write_block (self, RMI_F34_WRITE_FW_BLOCK, address, - chk->data, - chk->data_sz, + fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk), error)) { - g_prefix_error (error, "failed to write bin block %u: ", chk->idx); + g_prefix_error (error, "failed to write bin block %u: ", fu_chunk_get_idx (chk)); return FALSE; } fu_device_set_progress_full (device, (gsize) i, (gsize) chunks_bin->len + chunks_cfg->len); } + /* payload signature */ + if (signature_bin != NULL && + fu_synaptics_rmi_device_get_sig_size (self) != 0) { + g_autoptr(GPtrArray) chunks_sig = NULL; + chunks_sig = fu_chunk_array_new_from_bytes (signature_bin, + 0x00, /* start addr */ + 0x00, /* page_sz */ + flash->block_size); + if (!fu_synaptics_rmi_device_write (self, f34->data_base, req_addr, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, + error)) { + g_prefix_error (error, "failed to write 1st address zero: "); + return FALSE; + } + for (guint i = 0; i < chunks_sig->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks_sig, i); + if (!fu_synaptics_rmi_v5_device_write_block (self, + RMI_F34_WRITE_SIGNATURE, + address, + fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk), + error)) { + g_prefix_error (error, "failed to write bin block %u: ", fu_chunk_get_idx (chk)); + return FALSE; + } + fu_device_set_progress_full (device, (gsize) i, + (gsize) chunks_bin->len + chunks_cfg->len); + } + g_usleep (1000 * 1000); + } + if (!fu_synaptics_rmi_device_enter_iep_mode (self, error)) + return FALSE; + /* program the configuration image */ - if (!fu_synaptics_rmi_device_write (self, f34->data_base, req_addr, error)) { + if (!fu_synaptics_rmi_device_write (self, f34->data_base, req_addr, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, + error)) { g_prefix_error (error, "failed to 2nd write address zero: "); return FALSE; } @@ -230,10 +402,10 @@ if (!fu_synaptics_rmi_v5_device_write_block (self, RMI_F34_WRITE_CONFIG_BLOCK, address, - chk->data, - chk->data_sz, + fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk), error)) { - g_prefix_error (error, "failed to write cfg block %u: ", chk->idx); + g_prefix_error (error, "failed to write cfg block %u: ", fu_chunk_get_idx (chk)); return FALSE; } fu_device_set_progress_full (device, @@ -250,8 +422,10 @@ { FuSynapticsRmiFunction *f34; FuSynapticsRmiFlash *flash = fu_synaptics_rmi_device_get_flash (self); + guint8 flash_properties2 = 0; g_autoptr(GByteArray) f34_data0 = NULL; g_autoptr(GByteArray) f34_data2 = NULL; + g_autoptr(GByteArray) buf_flash_properties2 = NULL; /* f34 */ f34 = fu_synaptics_rmi_device_get_function (self, 0x34, error); @@ -268,12 +442,57 @@ flash->bootloader_id[1] = f34_data0->data[1]; /* get flash properties */ + buf_flash_properties2 = fu_synaptics_rmi_device_read (self, f34->query_base + 0x9, 1, error); + if (buf_flash_properties2 == NULL) { + g_prefix_error (error, "failed to read Flash Properties 2: "); + return FALSE; + } + if (!fu_common_read_uint8_safe (buf_flash_properties2->data, + buf_flash_properties2->len, + 0x0, /* offset */ + &flash_properties2, + error)) { + g_prefix_error (error, "failed to parse Flash Properties 2: "); + return FALSE; + } + if (flash_properties2 & 0x01) { + guint16 sig_size = 0; + g_autoptr(GByteArray) buf_rsa_key = NULL; + buf_rsa_key = fu_synaptics_rmi_device_read (self, + f34->query_base + 0x9 + 0x1, + 2, + error); + if (buf_rsa_key == NULL) { + g_prefix_error (error, "failed to read RSA key length: "); + return FALSE; + } + if (!fu_common_read_uint16_safe (buf_rsa_key->data, + buf_rsa_key->len, + 0x0, /* offset */ + &sig_size, + G_LITTLE_ENDIAN, + error)) { + g_prefix_error (error, "failed to parse RSA key length: "); + return FALSE; + } + fu_synaptics_rmi_device_set_sig_size (self, sig_size); + } else { + fu_synaptics_rmi_device_set_sig_size (self, 0); + } + + /* get flash properties */ f34_data2 = fu_synaptics_rmi_device_read (self, f34->query_base + 0x2, 0x7, error); if (f34_data2 == NULL) return FALSE; - flash->block_size = fu_common_read_uint16 (f34_data2->data + RMI_F34_BLOCK_SIZE_OFFSET, G_LITTLE_ENDIAN); - flash->block_count_fw = fu_common_read_uint16 (f34_data2->data + RMI_F34_FW_BLOCKS_OFFSET, G_LITTLE_ENDIAN); - flash->block_count_cfg = fu_common_read_uint16 (f34_data2->data + RMI_F34_CONFIG_BLOCKS_OFFSET, G_LITTLE_ENDIAN); + if (!fu_common_read_uint16_safe (f34_data2->data, f34_data2->len, RMI_F34_BLOCK_SIZE_OFFSET, + &flash->block_size, G_LITTLE_ENDIAN, error)) + return FALSE; + if (!fu_common_read_uint16_safe (f34_data2->data, f34_data2->len, RMI_F34_FW_BLOCKS_OFFSET, + &flash->block_count_fw, G_LITTLE_ENDIAN, error)) + return FALSE; + if (!fu_common_read_uint16_safe (f34_data2->data, f34_data2->len, RMI_F34_CONFIG_BLOCKS_OFFSET, + &flash->block_count_cfg, G_LITTLE_ENDIAN, error)) + return FALSE; flash->status_addr = f34->data_base + RMI_F34_BLOCK_DATA_OFFSET + flash->block_size; return TRUE; } diff -Nru fwupd-1.4.5/plugins/synaptics-rmi/fu-synaptics-rmi-v6-device.c fwupd-1.5.8/plugins/synaptics-rmi/fu-synaptics-rmi-v6-device.c --- fwupd-1.4.5/plugins/synaptics-rmi/fu-synaptics-rmi-v6-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-rmi/fu-synaptics-rmi-v6-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,6 +1,6 @@ /* - * Copyright (C) 2012-2014 Andrew Duggan - * Copyright (C) 2012-2019 Synaptics Inc. + * Copyright (C) 2012 Andrew Duggan + * Copyright (C) 2012 Synaptics Inc. * Copyright (C) 2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ @@ -35,19 +35,31 @@ g_prefix_error (error, "failed to read bootloader ID: "); return FALSE; } - flash->bootloader_id[0] = f34_data0->data[0]; - flash->bootloader_id[1] = f34_data0->data[1]; + if (!fu_common_read_uint8_safe (f34_data0->data, f34_data0->len, 0x0, + &flash->bootloader_id[0], error)) + return FALSE; + if (!fu_common_read_uint8_safe (f34_data0->data, f34_data0->len, 0x1, + &flash->bootloader_id[1], error)) + return FALSE; /* get flash properties */ f34_data2 = fu_synaptics_rmi_device_read (self, f34->query_base + 0x02, 2, error); if (f34_data2 == NULL) return FALSE; - flash->block_size = fu_common_read_uint16 (f34_data2->data, G_LITTLE_ENDIAN); + + if (!fu_common_read_uint16_safe (f34_data2->data, f34_data2->len, 0x0, + &flash->block_size, G_LITTLE_ENDIAN, error)) + return FALSE; f34_data3 = fu_synaptics_rmi_device_read (self, f34->query_base + 0x03, 8, error); if (f34_data3 == NULL) return FALSE; - flash->block_count_fw = fu_common_read_uint16 (f34_data3->data, G_LITTLE_ENDIAN); - flash->block_count_cfg = fu_common_read_uint16 (f34_data3->data + RMI_F34_CONFIG_BLOCKS_OFFSET, G_LITTLE_ENDIAN); + if (!fu_common_read_uint16_safe (f34_data3->data, f34_data3->len, 0x0, + &flash->block_count_fw, G_LITTLE_ENDIAN, error)) + return FALSE; + if (!fu_common_read_uint16_safe (f34_data3->data, f34_data3->len, + RMI_F34_CONFIG_BLOCKS_OFFSET, + &flash->block_count_cfg, G_LITTLE_ENDIAN, error)) + return FALSE; flash->status_addr = f34->data_base + 2; return TRUE; } diff -Nru fwupd-1.4.5/plugins/synaptics-rmi/fu-synaptics-rmi-v7-device.c fwupd-1.5.8/plugins/synaptics-rmi/fu-synaptics-rmi-v7-device.c --- fwupd-1.4.5/plugins/synaptics-rmi/fu-synaptics-rmi-v7-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-rmi/fu-synaptics-rmi-v7-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,6 +1,6 @@ /* - * Copyright (C) 2012-2014 Andrew Duggan - * Copyright (C) 2012-2019 Synaptics Inc. + * Copyright (C) 2012 Andrew Duggan + * Copyright (C) 2012 Synaptics Inc. * Copyright (C) 2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ @@ -100,6 +100,7 @@ if (!fu_synaptics_rmi_device_write (self, f34->data_base + 1, enable_req, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, error)) { g_prefix_error (error, "failed to enable programming: "); return FALSE; @@ -114,7 +115,7 @@ return FALSE; fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); g_usleep (1000 * RMI_F34_ENABLE_WAIT_MS); - return fu_synaptics_rmi_device_rebind_driver (self, error); + return TRUE; } static gboolean @@ -147,6 +148,7 @@ if (!fu_synaptics_rmi_device_write (self, f34->data_base + 1, erase_cmd, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, error)) { g_prefix_error (error, "failed to unlock erasing: "); return FALSE; @@ -179,6 +181,7 @@ if (!fu_synaptics_rmi_device_write (self, f34->data_base + 1, erase_config_cmd, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, error)) { g_prefix_error (error, "failed to erase core config: "); return FALSE; @@ -219,9 +222,11 @@ for (guint i = 0; i < chunks->len; i++) { FuChunk *chk = g_ptr_array_index (chunks, i); g_autoptr(GByteArray) req = g_byte_array_new (); - g_byte_array_append (req, chk->data, chk->data_sz); - if (!fu_synaptics_rmi_device_write (self, address, req, error)) { - g_prefix_error (error, "failed to write block @0x%x:%x ", address, chk->address); + g_byte_array_append (req, fu_chunk_get_data (chk), fu_chunk_get_data_sz (chk)); + if (!fu_synaptics_rmi_device_write (self, address, req, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, + error)) { + g_prefix_error (error, "failed to write block @0x%x:%x: ", address, fu_chunk_get_address (chk)); return FALSE; } } @@ -263,6 +268,7 @@ if (!fu_synaptics_rmi_device_write (self, f34->data_base + 0x1, req_partition_id, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, error)) { g_prefix_error (error, "failed to write flash partition: "); return FALSE; @@ -271,6 +277,7 @@ if (!fu_synaptics_rmi_device_write (self, f34->data_base + 0x2, req_offset, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, error)) { g_prefix_error (error, "failed to write offset: "); return FALSE; @@ -287,11 +294,12 @@ g_autoptr(GByteArray) req_trans_sz = g_byte_array_new (); g_autoptr(GByteArray) req_cmd = g_byte_array_new (); fu_byte_array_append_uint16 (req_trans_sz, - chk->data_sz / flash->block_size, + fu_chunk_get_data_sz (chk) / flash->block_size, G_LITTLE_ENDIAN); if (!fu_synaptics_rmi_device_write (self, f34->data_base + 0x3, req_trans_sz, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, error)) { g_prefix_error (error, "failed to write transfer length: "); return FALSE; @@ -300,14 +308,15 @@ if (!fu_synaptics_rmi_device_write (self, f34->data_base + 0x4, req_cmd, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, error)) { g_prefix_error (error, "failed to flash command: "); return FALSE; } if (!fu_synaptics_rmi_v7_device_write_blocks (self, f34->data_base + 0x5, - chk->data, - chk->data_sz, + fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk), error)) return FALSE; fu_device_set_progress_full (FU_DEVICE (self), (gsize) i, (gsize) chunks->len); @@ -423,6 +432,7 @@ if (!fu_synaptics_rmi_device_write (self, f34->data_base + 0x1, req_partition_id, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, error)) { g_prefix_error (error, "failed to write flash partition id: "); return FALSE; @@ -431,6 +441,7 @@ if (!fu_synaptics_rmi_device_write (self, f34->data_base + 0x2, req_addr_zero, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, error)) { g_prefix_error (error, "failed to write flash config address: "); return FALSE; @@ -443,6 +454,7 @@ if (!fu_synaptics_rmi_device_write (self, f34->data_base + 0x3, req_transfer_length, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, error)) { g_prefix_error (error, "failed to set transfer length: "); return FALSE; @@ -453,6 +465,7 @@ if (!fu_synaptics_rmi_device_write (self, f34->data_base + 0x4, req_cmd, + FU_SYNAPTICS_RMI_DEVICE_FLAG_NONE, error)) { g_prefix_error (error, "failed to write command to read: "); return FALSE; @@ -527,12 +540,28 @@ f34_dataX = fu_synaptics_rmi_device_read (self, f34->query_base + offset, 21, error); if (f34_dataX == NULL) return FALSE; - flash->bootloader_id[0] = f34_dataX->data[0x0]; - flash->bootloader_id[1] = f34_dataX->data[0x1]; - flash->block_size = fu_common_read_uint16 (f34_dataX->data + 0x07, G_LITTLE_ENDIAN); - flash->config_length = fu_common_read_uint16 (f34_dataX->data + 0x0d, G_LITTLE_ENDIAN); - flash->payload_length = fu_common_read_uint16 (f34_dataX->data + 0x0f, G_LITTLE_ENDIAN); - flash->build_id = fu_common_read_uint32 (f34_dataX->data + 0x02, G_LITTLE_ENDIAN); + if (!fu_common_read_uint8_safe (f34_dataX->data, f34_dataX->len, 0x0, + &flash->bootloader_id[0], error)) + return FALSE; + if (!fu_common_read_uint8_safe (f34_dataX->data, f34_dataX->len, 0x1, + &flash->bootloader_id[1], error)) + return FALSE; + if (!fu_common_read_uint16_safe (f34_dataX->data, f34_dataX->len, 0x07, + &flash->block_size, + G_LITTLE_ENDIAN, error)) + return FALSE; + if (!fu_common_read_uint16_safe (f34_dataX->data, f34_dataX->len, 0x0d, + &flash->config_length, + G_LITTLE_ENDIAN, error)) + return FALSE; + if (!fu_common_read_uint16_safe (f34_dataX->data, f34_dataX->len, 0x0f, + &flash->payload_length, + G_LITTLE_ENDIAN, error)) + return FALSE; + if (!fu_common_read_uint32_safe (f34_dataX->data, f34_dataX->len, 0x02, + &flash->build_id, + G_LITTLE_ENDIAN, error)) + return FALSE; /* sanity check */ if ((guint32) flash->block_size * (guint32) flash->config_length > G_MAXUINT16) { diff -Nru fwupd-1.4.5/plugins/synaptics-rmi/fuzzing/meson.build fwupd-1.5.8/plugins/synaptics-rmi/fuzzing/meson.build --- fwupd-1.4.5/plugins/synaptics-rmi/fuzzing/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-rmi/fuzzing/meson.build 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -synaptics_example0x = custom_target('example0x.img', - output: 'example0x.img', - command: [synaptics_rmi_dump, 'gen0x', '@OUTPUT@'], -) -synaptics_example10 = custom_target('example10.img', - output: 'example10.img', - command: [synaptics_rmi_dump, 'gen10', '@OUTPUT@'], -) -run_target('fuzz-synaptics-rmi', - command: [ - join_paths(meson.source_root(), 'contrib/afl-fuzz.py'), - '-i', meson.current_build_dir(), - '-o', join_paths(meson.current_build_dir(), '..', 'findings'), - synaptics_rmi_dump, - ], - depends: [ - synaptics_example0x, - synaptics_example10, - ], -) diff -Nru fwupd-1.4.5/plugins/synaptics-rmi/meson.build fwupd-1.5.8/plugins/synaptics-rmi/meson.build --- fwupd-1.4.5/plugins/synaptics-rmi/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-rmi/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,7 @@ +if get_option('plugin_synaptics_rmi') +if not get_option('gudev') + error('gudev is required for plugin_synaptics_rmi') +endif cargs = ['-DG_LOG_DOMAIN="FuPluginSynapticsRmi"'] install_data(['synaptics-rmi.quirk'], @@ -8,12 +12,14 @@ fu_hash, sources : [ 'fu-plugin-synaptics-rmi.c', - 'fu-synaptics-rmi-common.c', + 'fu-synaptics-rmi-common.c', # fuzzing 'fu-synaptics-rmi-device.c', + 'fu-synaptics-rmi-hid-device.c', + 'fu-synaptics-rmi-ps2-device.c', 'fu-synaptics-rmi-v5-device.c', 'fu-synaptics-rmi-v6-device.c', 'fu-synaptics-rmi-v7-device.c', - 'fu-synaptics-rmi-firmware.c', + 'fu-synaptics-rmi-firmware.c', # fuzzing ], include_directories : [ root_incdir, @@ -25,35 +31,11 @@ c_args : cargs, dependencies : [ plugin_deps, + gnutls, ], link_with : [ fwupd, fwupdplugin, ], ) - -if get_option('tests') - # for fuzzing - synaptics_rmi_dump = executable( - 'synaptics-rmi-dump', - sources : [ - 'fu-dump.c', - 'fu-synaptics-rmi-common.c', - 'fu-synaptics-rmi-firmware.c', - ], - include_directories : [ - root_incdir, - fwupd_incdir, - fwupdplugin_incdir, - ], - dependencies : [ - gio, - ], - link_with : [ - fwupd, - fwupdplugin, - ], - c_args : cargs - ) - subdir('fuzzing') endif diff -Nru fwupd-1.4.5/plugins/synaptics-rmi/README.md fwupd-1.5.8/plugins/synaptics-rmi/README.md --- fwupd-1.4.5/plugins/synaptics-rmi/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-rmi/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -16,6 +16,13 @@ * `SYNAPTICS_RMI\TM3038-002` * `SYNAPTICS_RMI\TM3038` +Update Behavior +--------------- + +The device usually presents in HID mode, and the firmware is written to the +device by switching to a SERIO mode where the touchpad is nonfunctional. +Once complete the device is reset to get out of SERIO mode and to load the new +firmware version. Vendor ID Security ------------------ @@ -31,3 +38,7 @@ This plugin supports the following protocol ID: * com.synaptics.rmi + +External interface access +------------------------- +This plugin requires ioctl access to `HIDIOCSFEATURE` and `HIDIOCGFEATURE`. diff -Nru fwupd-1.4.5/plugins/synaptics-rmi/synaptics-rmi.quirk fwupd-1.5.8/plugins/synaptics-rmi/synaptics-rmi.quirk --- fwupd-1.4.5/plugins/synaptics-rmi/synaptics-rmi.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/synaptics-rmi/synaptics-rmi.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,7 +1,17 @@ -[DeviceInstanceId=HIDRAW\VEN_06CB] +# Dell K12A kbd-dock +[HIDRAW\VEN_06CB&DEV_2819] Plugin = synaptics_rmi +GType = FuSynapticsRmiHidDevice Vendor = Synaptics - -# Dell K12A kbd-dock -[DeviceInstanceId=HIDRAW\VEN_06CB&DEV_2819] Flags = only-supported + +# LENOVO X1 Nano +[SERIO\FWID_LEN0305-PNP0F13] +Plugin = synaptics_rmi +GType = FuSynapticsRmiPs2Device + +# LENOVO X1 Panther +[SERIO\FWID_LEN0306-PNP0F13] +Plugin = synaptics_rmi +GType = FuSynapticsRmiPs2Device +InstallDuration = 236 diff -Nru fwupd-1.4.5/plugins/system76-launch/fu-plugin-system76-launch.c fwupd-1.5.8/plugins/system76-launch/fu-plugin-system76-launch.c --- fwupd-1.4.5/plugins/system76-launch/fu-plugin-system76-launch.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/system76-launch/fu-plugin-system76-launch.c 2021-03-31 20:08:32.000000000 +0000 @@ -8,7 +8,6 @@ #include "config.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #include "fu-system76-launch-device.h" diff -Nru fwupd-1.4.5/plugins/system76-launch/fu-system76-launch-device.c fwupd-1.5.8/plugins/system76-launch/fu-system76-launch-device.c --- fwupd-1.4.5/plugins/system76-launch/fu-system76-launch-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/system76-launch/fu-system76-launch-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -20,58 +20,71 @@ G_DEFINE_TYPE (FuSystem76LaunchDevice, fu_system76_launch_device, FU_TYPE_USB_DEVICE) static gboolean -fu_system76_launch_device_setup (FuDevice *device, GError **error) +fu_system76_launch_device_command (FuDevice *device, guint8 *data, gsize len, GError **error) { GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); const guint8 ep_in = 0x82; const guint8 ep_out = 0x03; - guint8 data[32] = { 0 }; gsize actual_len = 0; - g_autofree gchar *version = NULL; - /* send version command */ - data[0] = SYSTEM76_LAUNCH_CMD_VERSION; + /* send command */ if (!g_usb_device_interrupt_transfer (usb_device, ep_out, data, - sizeof(data), + len, &actual_len, SYSTEM76_LAUNCH_TIMEOUT, NULL, error)) { - g_prefix_error (error, "failed to send version command: "); + g_prefix_error (error, "failed to send command: "); return FALSE; } - if (actual_len < sizeof(data)) { + if (actual_len < len) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, - "version command truncated: sent %" G_GSIZE_FORMAT " bytes", + "command truncated: sent %" G_GSIZE_FORMAT " bytes", actual_len); return FALSE; } - /* receive version response */ + /* receive response */ if (!g_usb_device_interrupt_transfer (usb_device, ep_in, data, - sizeof(data), + len, &actual_len, SYSTEM76_LAUNCH_TIMEOUT, NULL, error)) { - g_prefix_error (error, "failed to read version response: "); + g_prefix_error (error, "failed to read response: "); return FALSE; } - if (actual_len < sizeof(data)) { + if (actual_len < len) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, - "version response truncated: received %" G_GSIZE_FORMAT " bytes", + "response truncated: received %" G_GSIZE_FORMAT " bytes", actual_len); return FALSE; } + return TRUE; +} + +static gboolean +fu_system76_launch_device_setup (FuDevice *device, GError **error) +{ + guint8 data[32] = { 0 }; + g_autofree gchar *version = NULL; + + /* execute version command */ + data[0] = SYSTEM76_LAUNCH_CMD_VERSION; + if (!fu_system76_launch_device_command (device, data, sizeof(data), error)) { + g_prefix_error (error, "failed to execute version command: "); + return FALSE; + } + version = g_strdup_printf ("%s", &data[2]); fu_device_set_version (device, version); @@ -81,39 +94,42 @@ static gboolean fu_system76_launch_device_detach (FuDevice *device, GError **error) { - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); - const guint8 ep_out = 0x03; guint8 data[32] = { 0 }; - gsize actual_len = 0; - g_autofree gchar *version = NULL; - - fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); - /* send reset command, should result in bootloader device appearing */ + /* execute reset command */ data[0] = SYSTEM76_LAUNCH_CMD_RESET; - if (!g_usb_device_interrupt_transfer (usb_device, - ep_out, - data, - sizeof(data), - &actual_len, - SYSTEM76_LAUNCH_TIMEOUT, - NULL, - error)) { - g_prefix_error (error, "failed to send reset command: "); + if (!fu_system76_launch_device_command (device, data, sizeof(data), error)) { + g_prefix_error (error, "failed to execute reset command: "); return FALSE; } + /* prompt for unlock if reset was blocked */ + if (data[1] != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NEEDS_USER_ACTION, + "To ensure you have physical access, %s needs to be manually unlocked. " + "Please press Fn+Esc to unlock and re-run the update.", + fu_device_get_name (device)); + return FALSE; + } + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); return TRUE; } static gboolean -fu_system76_launch_device_open (FuUsbDevice *device, GError **error) +fu_system76_launch_device_open (FuDevice *device, GError **error) { - GUsbDevice *usb_device = fu_usb_device_get_dev (device); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); const guint8 iface_idx = 0x01; + /* FuUsbDevice->open */ + if (!FU_DEVICE_CLASS (fu_system76_launch_device_parent_class)->open (device, error)) + return FALSE; + if (!g_usb_device_claim_interface (usb_device, iface_idx, G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, error)) { @@ -125,9 +141,9 @@ } static gboolean -fu_system76_launch_device_close (FuUsbDevice *device, GError **error) +fu_system76_launch_device_close (FuDevice *device, GError **error) { - GUsbDevice *usb_device = fu_usb_device_get_dev (device); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); const guint8 iface_idx = 0x01; if (!g_usb_device_release_interface (usb_device, iface_idx, @@ -137,27 +153,28 @@ return FALSE; } - return TRUE; + /* FuUsbDevice->close */ + return FU_DEVICE_CLASS (fu_system76_launch_device_parent_class)->close (device, error); } static void -fu_system76_launch_device_init (FuSystem76LaunchDevice *device) +fu_system76_launch_device_init (FuSystem76LaunchDevice *self) { - fu_device_set_remove_delay (FU_DEVICE (device), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); - fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_UPDATABLE); - fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_ADD_COUNTERPART_GUIDS); - fu_device_set_version_format (FU_DEVICE (device), FWUPD_VERSION_FORMAT_PLAIN); - fu_device_set_protocol (FU_DEVICE (device), "org.usb.dfu"); - fu_device_retry_set_delay (FU_DEVICE (device), 100); + fu_device_set_remove_delay (FU_DEVICE (self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_ADD_COUNTERPART_GUIDS); + fu_device_add_internal_flag (FU_DEVICE (self), FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID); + fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_PLAIN); + fu_device_add_protocol (FU_DEVICE (self), "org.usb.dfu"); + fu_device_retry_set_delay (FU_DEVICE (self), 100); } static void fu_system76_launch_device_class_init (FuSystem76LaunchDeviceClass *klass) { FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); klass_device->setup = fu_system76_launch_device_setup; klass_device->detach = fu_system76_launch_device_detach; - klass_usb_device->open = fu_system76_launch_device_open; - klass_usb_device->close = fu_system76_launch_device_close; + klass_device->open = fu_system76_launch_device_open; + klass_device->close = fu_system76_launch_device_close; } diff -Nru fwupd-1.4.5/plugins/system76-launch/meson.build fwupd-1.5.8/plugins/system76-launch/meson.build --- fwupd-1.4.5/plugins/system76-launch/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/system76-launch/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,4 @@ +if get_option('gusb') cargs = ['-DG_LOG_DOMAIN="FuPluginSystem76Launch"'] install_data(['system76-launch.quirk'], @@ -18,6 +19,7 @@ install : true, install_dir: plugin_dir, link_with : [ + fwupd, fwupdplugin, ], c_args : cargs, @@ -25,3 +27,4 @@ plugin_deps, ], ) +endif diff -Nru fwupd-1.4.5/plugins/system76-launch/README.md fwupd-1.5.8/plugins/system76-launch/README.md --- fwupd-1.4.5/plugins/system76-launch/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/system76-launch/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -16,6 +16,18 @@ * `USB\VID_3384&PID_0001&REV_0001` +Update Behavior +--------------- + +The device usually presents in runtime mode, but on detach re-enumerates with a +different USB VID and PID in DFU mode. The device is then handled by the `dfu` +plugin. + +On DFU attach the device again re-enumerates back to the runtime mode. + +For this reason the `REPLUG_MATCH_GUID` internal device flag is used so that +the bootloader and runtime modes are treated as the same device. + Vendor ID Security ------------------ diff -Nru fwupd-1.4.5/plugins/system76-launch/system76-launch.quirk fwupd-1.5.8/plugins/system76-launch/system76-launch.quirk --- fwupd-1.4.5/plugins/system76-launch/system76-launch.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/system76-launch/system76-launch.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,4 +1,4 @@ # System76 Launch -[DeviceInstanceId=USB\VID_3384&PID_0001&REV_0001] +[USB\VID_3384&PID_0001&REV_0001] Plugin = system76_launch CounterpartGuid = USB\VID_03EB&PID_2FF4 diff -Nru fwupd-1.4.5/plugins/test/fu-plugin-test-ble.c fwupd-1.5.8/plugins/test/fu-plugin-test-ble.c --- fwupd-1.4.5/plugins/test/fu-plugin-test-ble.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/test/fu-plugin-test-ble.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2021 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-test-ble-device.h" + +#include "fu-plugin-vfuncs.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_set_device_gtype (plugin, FU_TYPE_TEST_BLE_DEVICE); +} diff -Nru fwupd-1.4.5/plugins/test/fu-plugin-test.c fwupd-1.5.8/plugins/test/fu-plugin-test.c --- fwupd-1.4.5/plugins/test/fu-plugin-test.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/test/fu-plugin-test.c 2021-03-31 20:08:32.000000000 +0000 @@ -7,7 +7,6 @@ #include "config.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" struct FuPluginData { GMutex mutex; @@ -38,11 +37,11 @@ fu_device_set_name (device, "Integrated_Webcam(TM)"); fu_device_add_icon (device, "preferences-desktop-keyboard"); fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); - fu_device_add_flag (device, FWUPD_DEVICE_FLAG_CAN_VERIFY); - fu_device_set_protocol (device, "com.acme.test"); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE); + fu_device_add_protocol (device, "com.acme.test"); fu_device_set_summary (device, "A fake webcam"); fu_device_set_vendor (device, "ACME Corp."); - fu_device_set_vendor_id (device, "USB:0x046D"); + fu_device_add_vendor_id (device, "USB:0x046D"); fu_device_set_version_format (device, FWUPD_VERSION_FORMAT_TRIPLET); fu_device_set_version_bootloader (device, "0.1.2"); fu_device_set_version (device, "1.2.2"); @@ -64,8 +63,8 @@ g_autoptr(FuDevice) child2 = NULL; child1 = fu_device_new (); - fu_device_set_vendor_id (child1, "USB:FFFF"); - fu_device_set_protocol (child1, "com.acme"); + fu_device_add_vendor_id (child1, "USB:FFFF"); + fu_device_add_protocol (child1, "com.acme"); fu_device_set_physical_id (child1, "fake"); fu_device_set_logical_id (child1, "child1"); fu_device_add_guid (child1, "7fddead7-12b5-4fb9-9fa0-6d30305df755"); @@ -77,8 +76,8 @@ fu_plugin_device_add (plugin, child1); child2 = fu_device_new (); - fu_device_set_vendor_id (child2, "USB:FFFF"); - fu_device_set_protocol (child2, "com.acme"); + fu_device_add_vendor_id (child2, "USB:FFFF"); + fu_device_add_protocol (child2, "com.acme"); fu_device_set_physical_id (child2, "fake"); fu_device_set_logical_id (child2, "child2"); fu_device_add_guid (child2, "b8fe6b45-8702-4bcd-8120-ef236caac76f"); diff -Nru fwupd-1.4.5/plugins/test/fu-test-ble-device.c fwupd-1.5.8/plugins/test/fu-test-ble-device.c --- fwupd-1.4.5/plugins/test/fu-test-ble-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/test/fu-test-ble-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2021 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-test-ble-device.h" + +struct _FuTestBleDevice { + FuBluezDevice parent_instance; +}; + +G_DEFINE_TYPE (FuTestBleDevice, fu_test_ble_device, FU_TYPE_BLUEZ_DEVICE) + +static void +fu_test_ble_device_init (FuTestBleDevice *self) +{ + fu_device_add_protocol (FU_DEVICE (self), "org.test.testble"); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); +} + +static void +fu_test_ble_device_class_init (FuTestBleDeviceClass *klass) +{ +} diff -Nru fwupd-1.4.5/plugins/test/fu-test-ble-device.h fwupd-1.5.8/plugins/test/fu-test-ble-device.h --- fwupd-1.4.5/plugins/test/fu-test-ble-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/test/fu-test-ble-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,12 @@ +/* + * Copyright (C) 2021 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +#define FU_TYPE_TEST_BLE_DEVICE (fu_test_ble_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuTestBleDevice, fu_test_ble_device, FU, TEST_BLE_DEVICE, FuBluezDevice) diff -Nru fwupd-1.4.5/plugins/test/meson.build fwupd-1.5.8/plugins/test/meson.build --- fwupd-1.4.5/plugins/test/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/test/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -5,6 +5,12 @@ install_dummy = true endif +if get_option('bluez') +install_data(['test-ble.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) +endif + shared_module('fu_plugin_test', fu_hash, sources : [ @@ -46,3 +52,28 @@ plugin_deps, ], ) + +if get_option('bluez') +shared_module('fu_plugin_test_ble', + fu_hash, + sources : [ + 'fu-plugin-test-ble.c', + 'fu-test-ble-device.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : install_dummy, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) +endif diff -Nru fwupd-1.4.5/plugins/test/README.md fwupd-1.5.8/plugins/test/README.md --- fwupd-1.4.5/plugins/test/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/test/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -12,7 +12,15 @@ The devices created by this plugin use hardcoded GUIDs that do not correspond to any kind of DeviceInstanceId values. +In other cases devices use the standard BLE DeviceInstanceId values, e.g. + + * `USB\VID_2DC8&PID_AB11` + Vendor ID Security ------------------ The fake device is only for local testing and thus requires no vendor ID set. + +External interface access +------------------------- +This plugin requires no extra access. diff -Nru fwupd-1.4.5/plugins/test/test-ble.quirk fwupd-1.5.8/plugins/test/test-ble.quirk --- fwupd-1.4.5/plugins/test/test-ble.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/test/test-ble.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,4 @@ +[BLUETOOTH\VID_0461&PID_4EEE&REV_0001] +Plugin = test_ble +[BLUETOOTH\VID_0461&PID_4EEF&REV_0001] +Plugin = test_ble diff -Nru fwupd-1.4.5/plugins/thelio-io/fu-plugin-thelio-io.c fwupd-1.5.8/plugins/thelio-io/fu-plugin-thelio-io.c --- fwupd-1.4.5/plugins/thelio-io/fu-plugin-thelio-io.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/thelio-io/fu-plugin-thelio-io.c 2021-03-31 20:08:32.000000000 +0000 @@ -8,7 +8,6 @@ #include "config.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #include "fu-thelio-io-device.h" diff -Nru fwupd-1.4.5/plugins/thelio-io/fu-thelio-io-device.c fwupd-1.5.8/plugins/thelio-io/fu-thelio-io-device.c --- fwupd-1.4.5/plugins/thelio-io/fu-thelio-io-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/thelio-io/fu-thelio-io-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -96,8 +96,10 @@ fu_thelio_io_device_init (FuThelioIoDevice *self) { fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_internal_flag (FU_DEVICE (self), FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID); fu_device_set_remove_delay (FU_DEVICE (self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_add_protocol (FU_DEVICE (self), "org.usb.dfu"); } static void diff -Nru fwupd-1.4.5/plugins/thelio-io/meson.build fwupd-1.5.8/plugins/thelio-io/meson.build --- fwupd-1.4.5/plugins/thelio-io/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/thelio-io/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,4 @@ +if get_option('gudev') cargs = ['-DG_LOG_DOMAIN="FuPluginThelioIo"'] install_data(['thelio-io.quirk'], @@ -26,3 +27,4 @@ plugin_deps, ], ) +endif diff -Nru fwupd-1.4.5/plugins/thelio-io/README.md fwupd-1.5.8/plugins/thelio-io/README.md --- fwupd-1.4.5/plugins/thelio-io/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/thelio-io/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -16,7 +16,23 @@ * `USB\VID_1209&PID_1776&REV_0001` +Update Behavior +--------------- + +The device usually presents in runtime mode, but on detach re-enumerates with a +different USB VID and PID in DFU mode. The device is then handled by the `dfu` +plugin. + +On DFU attach the device again re-enumerates back to the runtime mode. + +For this reason the `REPLUG_MATCH_GUID` internal device flag is used so that +the bootloader and runtime modes are treated as the same device. + Vendor ID Security ------------------ The vendor ID is set from the USB vendor, in this instance set to `USB:0x1209` + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff -Nru fwupd-1.4.5/plugins/thelio-io/thelio-io.quirk fwupd-1.5.8/plugins/thelio-io/thelio-io.quirk --- fwupd-1.4.5/plugins/thelio-io/thelio-io.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/thelio-io/thelio-io.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,3 @@ # System76 Thelio IO -[DeviceInstanceId=USB\VID_1209&PID_1776&REV_0001] +[USB\VID_1209&PID_1776&REV_0001] Plugin = thelio_io diff -Nru fwupd-1.4.5/plugins/thunderbolt/fu-plugin-thunderbolt.c fwupd-1.5.8/plugins/thunderbolt/fu-plugin-thunderbolt.c --- fwupd-1.4.5/plugins/thunderbolt/fu-plugin-thunderbolt.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/thunderbolt/fu-plugin-thunderbolt.c 2021-03-31 20:08:32.000000000 +0000 @@ -9,7 +9,6 @@ #include #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #include "fu-thunderbolt-device.h" #include "fu-thunderbolt-firmware.h" #include "fu-thunderbolt-firmware-update.h" @@ -63,11 +62,13 @@ return; /* Operating system will handle finishing updates later */ - if (fu_plugin_get_config_value_boolean (plugin, "DelayedActivation")) { + if (fu_plugin_get_config_value_boolean (plugin, "DelayedActivation") && + !fu_device_has_flag (device, FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE)) { g_debug ("Turning on delayed activation for %s", fu_device_get_name (device)); fu_device_add_flag (device, FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE); fu_device_add_flag (device, FWUPD_DEVICE_FLAG_SKIPS_RESTART); + fu_device_remove_internal_flag (device, FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID); } } @@ -77,8 +78,8 @@ fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_udev_subsystem (plugin, "thunderbolt"); fu_plugin_set_device_gtype (plugin, FU_TYPE_THUNDERBOLT_DEVICE); - fu_plugin_add_firmware_gtype (plugin, "thunderbolt", FU_TYPE_THUNDERBOLT_FIRMWARE); - fu_plugin_add_firmware_gtype (plugin, "thunderbolt-update", FU_TYPE_THUNDERBOLT_FIRMWARE_UPDATE); + fu_plugin_add_firmware_gtype (plugin, NULL, FU_TYPE_THUNDERBOLT_FIRMWARE); + fu_plugin_add_firmware_gtype (plugin, NULL, FU_TYPE_THUNDERBOLT_FIRMWARE_UPDATE); /* dell-dock plugin uses a slower bus for flashing */ fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_BETTER_THAN, "dell_dock"); } diff -Nru fwupd-1.4.5/plugins/thunderbolt/fu-self-test.c fwupd-1.5.8/plugins/thunderbolt/fu-self-test.c --- fwupd-1.4.5/plugins/thunderbolt/fu-self-test.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/thunderbolt/fu-self-test.c 2021-03-31 20:08:32.000000000 +0000 @@ -26,6 +26,7 @@ #include "fu-plugin-private.h" #include "fu-thunderbolt-firmware.h" #include "fu-thunderbolt-firmware-update.h" +#include "fu-udev-device-private.h" static gchar * udev_mock_add_domain (UMockdevTestbed *bed, int id) @@ -395,7 +396,7 @@ "device", dev->id, "vendor", "042", "vendor_name", "GNOME.org", - "authorized", "0", + "authorized", "1", "nvm_authenticate", authenticate, "nvm_version", tree->nvm_version, "unique_id", tree->uuid, @@ -672,6 +673,8 @@ if (ctx == NULL) return; + g_file_monitor_cancel (ctx->monitor); + g_object_unref (ctx->bed); g_object_unref (ctx->plugin); g_object_unref (ctx->monitor); @@ -873,11 +876,11 @@ GUdevDevice *udev_device, ThunderboltTest *tt) { - g_autoptr(GError) error_local = NULL; - if (g_strcmp0 (action, "add") == 0) { g_autoptr(FuUdevDevice) device = fu_udev_device_new (udev_device); - fu_plugin_runner_udev_device_added (tt->plugin, device, &error_local); + g_autoptr(GError) error_local = NULL; + if (!fu_plugin_runner_backend_device_added (tt->plugin, FU_DEVICE (device), &error_local)) + g_debug ("failed to add: %s", error_local->message); return; } if (g_strcmp0 (action, "remove") == 0) { @@ -888,8 +891,8 @@ if (g_strcmp0 (action, "change") == 0) { const gchar *uuid = g_udev_device_get_sysfs_attr (udev_device, "unique_id"); MockTree *target = (MockTree *) mock_tree_find_uuid (tt->tree, uuid); - fu_plugin_runner_udev_device_changed (tt->plugin, FU_UDEV_DEVICE (target->fu_device), - &error_local); + g_assert_nonnull (target); + fu_udev_device_emit_changed (FU_UDEV_DEVICE (target->fu_device)); return; } } @@ -1004,7 +1007,6 @@ const MockTree *found; gboolean ret; g_autoptr(MockTree) tree = NULL; - g_autoptr(GError) error = NULL; tree = mock_tree_init (&root_one); g_assert_nonnull (tree); @@ -1230,6 +1232,37 @@ } static void +test_update_wd19 (ThunderboltTest *tt, gconstpointer user_data) +{ + FuPlugin *plugin = tt->plugin; + MockTree *tree = tt->tree; + GBytes *fw_data = tt->fw_data; + gboolean ret; + const gchar *version_before; + const gchar *version_after; + g_autoptr(GError) error = NULL; + + /* test sanity check */ + g_assert_nonnull (tree); + g_assert_nonnull (fw_data); + + /* simulate a wd19 update which will not disappear / re-appear */ + fu_device_add_flag (tree->fu_device, FWUPD_DEVICE_FLAG_SKIPS_RESTART); + fu_device_add_flag (tree->fu_device, FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE); + version_before = fu_device_get_version (tree->fu_device); + + ret = fu_plugin_runner_update (plugin, tree->fu_device, fw_data, 0, &error); + g_assert_no_error (error); + g_assert_true (ret); + + ret = fu_device_has_flag (tree->fu_device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION); + g_assert_true (ret); + + version_after = fu_device_get_version (tree->fu_device); + g_assert_cmpstr (version_after, ==, version_before); +} + +static void test_update_fail (ThunderboltTest *tt, gconstpointer user_data) { FuPlugin *plugin = tt->plugin; @@ -1357,6 +1390,12 @@ test_set_up, test_update_fail_nowshow, test_tear_down); + g_test_add ("/thunderbolt/update{delayed_activation}", + ThunderboltTest, + TEST_INIT_FULL, + test_set_up, + test_update_wd19, + test_tear_down); return g_test_run (); } diff -Nru fwupd-1.4.5/plugins/thunderbolt/fu-thunderbolt-device.c fwupd-1.5.8/plugins/thunderbolt/fu-thunderbolt-device.c --- fwupd-1.4.5/plugins/thunderbolt/fu-thunderbolt-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/thunderbolt/fu-thunderbolt-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -20,10 +20,17 @@ #include "fu-thunderbolt-device.h" #include "fu-thunderbolt-firmware.h" #include "fu-thunderbolt-firmware-update.h" +#include "fu-udev-device-private.h" + +typedef enum { + FU_THUNDERBOLT_DEVICE_TYPE_DEVICE_CONTROLLER, + FU_THUNDERBOLT_DEVICE_TYPE_HOST_CONTROLLER, + FU_THUNDERBOLT_DEVICE_TYPE_RETIMER +} FuThunderboltDeviceType; struct _FuThunderboltDevice { FuUdevDevice parent_instance; - gboolean host; + FuThunderboltDeviceType device_type; gboolean safe_mode; gboolean is_native; guint16 gen; @@ -104,6 +111,42 @@ } static gboolean +fu_thunderbolt_device_check_authorized (FuThunderboltDevice *self, GError **error) +{ + guint64 status; + g_autofree gchar *attribute = NULL; + const gchar *update_error = NULL; + /* read directly from file to prevent udev caching */ + g_autofree gchar *safe_path = g_build_path ("/", self->devpath, "authorized", NULL); + + if (!g_file_test (safe_path, G_FILE_TEST_EXISTS)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "missing authorized attribute"); + return FALSE; + } + + if (!g_file_get_contents (safe_path, &attribute, NULL, error)) + return FALSE; + status = g_ascii_strtoull (attribute, NULL, 16); + if (status == G_MAXUINT64 && errno == ERANGE) { + g_set_error (error, G_IO_ERROR, + g_io_error_from_errno (errno), + "failed to read 'authorized: %s", + g_strerror (errno)); + return FALSE; + } + if (status == 1 || status == 2) + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + else + update_error = "Not authorized"; + fu_device_set_update_error (FU_DEVICE (self), update_error); + + return TRUE; +} + +static gboolean fu_thunderbolt_device_can_update (FuThunderboltDevice *self) { g_autoptr(GError) nvmem_error = NULL; @@ -120,7 +163,7 @@ } static gboolean -fu_thunderbolt_device_get_version (FuThunderboltDevice *self) +fu_thunderbolt_device_get_version (FuThunderboltDevice *self, GError **error) { g_auto(GStrv) split = NULL; g_autofree gchar *version_raw = NULL; @@ -128,6 +171,14 @@ /* read directly from file to prevent udev caching */ g_autofree gchar *safe_path = g_build_path ("/", self->devpath, "nvm_version", NULL); + if (!g_file_test (safe_path, G_FILE_TEST_EXISTS)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "missing nvm_version attribute"); + return FALSE; + } + for (guint i = 0; i < 50; i++) { g_autoptr(GError) error_local = NULL; /* glib can't return a properly mapped -ENODATA but the @@ -141,18 +192,26 @@ break; } - if (version_raw == NULL) + if (version_raw == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to read NVM"); return FALSE; + } split = g_strsplit (version_raw, ".", -1); - if (g_strv_length (split) != 2) + if (g_strv_length (split) != 2) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid nvm_version format: %s", version_raw); return FALSE; + } version = g_strdup_printf ("%02x.%02x", (guint) g_ascii_strtoull (split[0], NULL, 16), (guint) g_ascii_strtoull (split[1], NULL, 16)); fu_device_set_version (FU_DEVICE (self), version); - g_debug ("setting version to %s", version); - g_debug ("path is %s", self->devpath); return TRUE; } @@ -160,7 +219,7 @@ fu_thunderbolt_device_check_safe_mode (FuThunderboltDevice *self) { /* failed to read, for host check for safe mode */ - if (!self->host || self->gen >= 4) + if (self->device_type != FU_THUNDERBOLT_DEVICE_TYPE_DEVICE_CONTROLLER) return; g_warning ("%s is in safe mode -- VID/DID will " "need to be set by another plugin", @@ -171,11 +230,35 @@ fu_device_set_metadata_boolean (FU_DEVICE (self), FU_DEVICE_METADATA_TBT_IS_SAFE_MODE, TRUE); } +static const gchar* +fu_thunderbolt_device_type_to_string (FuThunderboltDevice *self) +{ + if (self->device_type == FU_THUNDERBOLT_DEVICE_TYPE_HOST_CONTROLLER) { + if (self->gen >= 4) + return "USB4 host controller"; + else + return "Thunderbolt host controller"; + } + if (self->device_type == FU_THUNDERBOLT_DEVICE_TYPE_DEVICE_CONTROLLER) { + if (self->gen >= 4) + return "USB4 device controller"; + else + return "Thunderbolt device controller"; + } + if (self->device_type == FU_THUNDERBOLT_DEVICE_TYPE_RETIMER) + return "USB4 Retimer"; + return "Unknown"; +} + static void fu_thunderbolt_device_to_string (FuDevice *device, guint idt, GString *str) { FuThunderboltDevice *self = FU_THUNDERBOLT_DEVICE (device); - fu_common_string_append_kb (str, idt, "Host Controller", self->host); + + /* FuUdevDevice->to_string */ + FU_DEVICE_CLASS (fu_thunderbolt_device_parent_class)->to_string (device, idt, str); + + fu_common_string_append_kv (str, idt, "Device Type", fu_thunderbolt_device_type_to_string (self)); fu_common_string_append_kb (str, idt, "Safe Mode", self->safe_mode); fu_common_string_append_kb (str, idt, "Native mode", self->is_native); fu_common_string_append_ku (str, idt, "Generation", self->gen); @@ -183,18 +266,34 @@ } static gboolean -fu_thunderbolt_device_probe (FuUdevDevice *device, GError **error) +fu_thunderbolt_device_probe (FuDevice *device, GError **error) { - const gchar *tmp = fu_udev_device_get_sysfs_attr (device, "unique_id", NULL); - /* most likely the domain itself, ignore */ - if (tmp == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "thunderbolt domain not used"); + FuThunderboltDevice *self = FU_THUNDERBOLT_DEVICE (device); + const gchar *tmp = fu_udev_device_get_devtype (FU_UDEV_DEVICE (device)); + + /* FuUdevDevice->probe */ + if (!FU_DEVICE_CLASS (fu_thunderbolt_device_parent_class)->probe (device, error)) + return FALSE; + + /* device */ + if (g_strcmp0 (tmp, "thunderbolt_device") == 0) { + tmp = fu_udev_device_get_sysfs_attr (FU_UDEV_DEVICE (device), "unique_id", NULL); + if (tmp != NULL) + fu_device_set_physical_id (device, tmp); + /* retimer */ + } else if (g_strcmp0 (tmp, "thunderbolt_retimer") == 0) { + self->device_type = FU_THUNDERBOLT_DEVICE_TYPE_RETIMER; + tmp = g_path_get_basename (fu_udev_device_get_sysfs_path (FU_UDEV_DEVICE (device))); + if (tmp != NULL) + fu_device_set_physical_id (device, tmp); + /* domain or unsupported */ + } else { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "%s not used", tmp); return FALSE; } - fu_device_set_physical_id (FU_DEVICE (device), tmp); return TRUE; } @@ -231,7 +330,7 @@ } static gboolean -fu_thunderbolt_device_setup (FuDevice *device, GError **error) +fu_thunderbolt_device_setup_controller (FuDevice *device, GError **error) { FuThunderboltDevice *self = FU_THUNDERBOLT_DEVICE (device); const gchar *tmp = NULL; @@ -240,9 +339,6 @@ g_autoptr(GError) error_gen = NULL; g_autofree gchar *parent_name = fu_udev_device_get_parent_name (FU_UDEV_DEVICE (self)); - self->devpath = g_strdup (fu_udev_device_get_sysfs_path (FU_UDEV_DEVICE (device))); - fu_device_set_metadata (device, "sysfs-path", self->devpath); - /* these may be missing on ICL or later */ vid = fu_udev_device_get_vendor (FU_UDEV_DEVICE (self)); if (vid == 0x0) @@ -263,7 +359,7 @@ /* determine if host controller or not */ if (parent_name != NULL && g_str_has_prefix (parent_name, "domain")) { - self->host = TRUE; + self->device_type = FU_THUNDERBOLT_DEVICE_TYPE_HOST_CONTROLLER; fu_device_add_flag (device, FWUPD_DEVICE_FLAG_INTERNAL); fu_device_set_summary (device, "Unmatched performance for high-speed I/O"); } else { @@ -271,12 +367,8 @@ } /* set the controller name */ - if (tmp == NULL) { - if (self->gen == 4) - tmp = "USB4 Controller"; - else - tmp = "Thunderbolt Controller"; - } + if (tmp == NULL) + tmp = fu_thunderbolt_device_type_to_string (self); fu_device_set_name (device, tmp); /* set vendor string */ @@ -285,8 +377,7 @@ return FALSE; fu_device_set_vendor (device, tmp); - /* try to read the version */ - if (!fu_thunderbolt_device_get_version (self)) + if (fu_device_get_version (device) == NULL) fu_thunderbolt_device_check_safe_mode (self); if (self->safe_mode) { @@ -299,7 +390,8 @@ g_autofree gchar *domain = g_path_get_basename (self->devpath); /* USB4 controllers don't have a concept of legacy vs native * so don't try to read a native attribute from their NVM */ - if (self->host && self->gen < 4) { + if (self->device_type == FU_THUNDERBOLT_DEVICE_TYPE_HOST_CONTROLLER + && self->gen < 4) { domain_id = g_strdup_printf ("TBT-%04x%04x%s-controller%s", (guint) vid, (guint) did, @@ -307,13 +399,17 @@ domain); } vendor_id = g_strdup_printf ("TBT:0x%04X", (guint) vid); - fu_device_set_vendor_id (device, vendor_id); + fu_device_add_vendor_id (device, vendor_id); device_id = g_strdup_printf ("TBT-%04x%04x%s", (guint) vid, (guint) did, self->is_native ? "-native" : ""); - fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_add_flag (device, FWUPD_DEVICE_FLAG_DUAL_IMAGE); + + /* check if device is authorized */ + if (!fu_thunderbolt_device_check_authorized (self, error)) + return FALSE; + } else { device_id = g_strdup ("TBT-fixed"); } @@ -331,15 +427,100 @@ fu_device_add_flag (device, FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE); /* forces the device to write to authenticate on disconnect attribute */ fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_SKIPS_RESTART); + /* control the order of activation (less relevant; install too though) */ + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_INSTALL_PARENT_FIRST); } else { - self->auth_method = "nvm_authenticate"; + fu_device_add_internal_flag (device, FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID); } - /* success */ return TRUE; } static gboolean +fu_thunderbolt_device_setup_retimer (FuDevice *device, GError **error) +{ + FuThunderboltDevice *self = FU_THUNDERBOLT_DEVICE (device); + guint16 did; + guint16 vid; + g_autofree gchar *instance = NULL; + + /* as defined in PCIe 4.0 spec */ + fu_device_set_summary (device, "A physical layer protocol-aware, software-transparent extension device " + "that forms two separate electrical link segments"); + fu_device_set_name (device, fu_thunderbolt_device_type_to_string (self)); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_DUAL_IMAGE); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_INTERNAL); + vid = fu_udev_device_get_vendor (FU_UDEV_DEVICE (self)); + if (vid == 0x0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "missing vendor id"); + return FALSE; + } + + did = fu_udev_device_get_model (FU_UDEV_DEVICE (self)); + if (did == 0x0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "missing device id"); + return FALSE; + + } + + instance = g_strdup_printf ("TBT-%04x%04x-retimer%s", + (guint) vid, + (guint) did, + fu_device_get_physical_id (device)); + fu_device_add_instance_id (device, instance); + + /* hardcoded for now: + * 1. unsure if ID_VENDOR_FROM_DATABASE works in this instance + * 2. we don't recognize anyone else yet + */ + if (fu_device_get_vendor (device) == NULL) + fu_device_set_vendor (device, "Intel"); + + return TRUE; +} + +static gboolean +fu_thunderbolt_device_setup (FuDevice *device, GError **error) +{ + FuThunderboltDevice *self = FU_THUNDERBOLT_DEVICE (device); + g_autoptr(GError) error_version = NULL; + + self->devpath = g_strdup (fu_udev_device_get_sysfs_path (FU_UDEV_DEVICE (device))); + + /* try to read the version */ + if (!fu_thunderbolt_device_get_version (self, &error_version)) { + if (g_error_matches (error_version, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED)) { + g_propagate_error (error, g_steal_pointer (&error_version)); + return FALSE; + } + g_debug ("%s", error_version->message); + } + + /* default behavior */ + self->auth_method = "nvm_authenticate"; + + /* configure differences between retimer and controller */ + if (self->device_type == FU_THUNDERBOLT_DEVICE_TYPE_RETIMER) + return fu_thunderbolt_device_setup_retimer (device, error); + return fu_thunderbolt_device_setup_controller (device, error); +} + +static gboolean +fu_thunderbolt_device_activate (FuDevice *device, GError **error) +{ + FuUdevDevice *udev = FU_UDEV_DEVICE (device); + + return fu_udev_device_write_sysfs (udev, "nvm_authenticate", "1", error); +} + +static gboolean fu_thunderbolt_device_authenticate (FuDevice *device, GError **error) { FuThunderboltDevice *self = FU_THUNDERBOLT_DEVICE (device); @@ -394,8 +575,13 @@ fu_thunderbolt_device_rescan (FuDevice *device, GError **error) { FuThunderboltDevice *self = FU_THUNDERBOLT_DEVICE (device); + + /* refresh updatability */ + if (!fu_thunderbolt_device_check_authorized (self, error)) + return FALSE; + /* refresh the version */ - return fu_thunderbolt_device_get_version (self); + return fu_thunderbolt_device_get_version (self, error); } static gboolean @@ -428,9 +614,12 @@ do { g_autoptr(GBytes) fw_data = NULL; - fw_data = g_bytes_new_from_bytes (blob_fw, - nwritten, - fw_size - nwritten); + fw_data = fu_common_bytes_new_offset (blob_fw, + nwritten, + fw_size - nwritten, + error); + if (fw_data == NULL) + return FALSE; n = g_output_stream_write_bytes (os, fw_data, @@ -465,7 +654,6 @@ g_autoptr(FuThunderboltFirmwareUpdate) firmware = fu_thunderbolt_firmware_update_new (); g_autoptr(FuThunderboltFirmware) firmware_old = fu_thunderbolt_firmware_new (); g_autoptr(GBytes) controller_fw = NULL; - g_autoptr(GError) error_local = NULL; g_autoptr(GFile) nvmem = NULL; /* parse */ @@ -477,6 +665,8 @@ if (nvmem == NULL) return NULL; controller_fw = g_file_load_bytes (nvmem, NULL, NULL, error); + if (controller_fw == NULL) + return NULL; if (!fu_firmware_parse (FU_FIRMWARE (firmware_old), controller_fw, flags, error)) return NULL; if (fu_thunderbolt_firmware_is_host (FU_THUNDERBOLT_FIRMWARE (firmware)) != @@ -509,7 +699,7 @@ fu_thunderbolt_firmware_get_device_id (firmware_old)); return NULL; } - if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + if ((flags & FWUPD_INSTALL_FLAG_IGNORE_VID_PID) == 0) { if (fu_thunderbolt_firmware_get_model_id (FU_THUNDERBOLT_FIRMWARE (firmware)) != fu_thunderbolt_firmware_get_model_id (firmware_old)) { g_set_error (error, @@ -600,7 +790,7 @@ { fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_REQUIRE_AC); fu_device_add_icon (FU_DEVICE (self), "thunderbolt"); - fu_device_set_protocol (FU_DEVICE (self), "com.intel.thunderbolt"); + fu_device_add_protocol (FU_DEVICE (self), "com.intel.thunderbolt"); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_PAIR); } @@ -617,14 +807,13 @@ { GObjectClass *object_class = G_OBJECT_CLASS (klass); FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - FuUdevDeviceClass *klass_udev_device = FU_UDEV_DEVICE_CLASS (klass); object_class->finalize = fu_thunderbolt_device_finalize; - klass_device->activate = fu_thunderbolt_device_authenticate; + klass_device->activate = fu_thunderbolt_device_activate; klass_device->to_string = fu_thunderbolt_device_to_string; klass_device->setup = fu_thunderbolt_device_setup; klass_device->prepare_firmware = fu_thunderbolt_device_prepare_firmware; klass_device->write_firmware = fu_thunderbolt_device_write_firmware; klass_device->attach = fu_thunderbolt_device_attach; klass_device->rescan = fu_thunderbolt_device_rescan; - klass_udev_device->probe = fu_thunderbolt_device_probe; + klass_device->probe = fu_thunderbolt_device_probe; } diff -Nru fwupd-1.4.5/plugins/thunderbolt/fu-thunderbolt-firmware.c fwupd-1.5.8/plugins/thunderbolt/fu-thunderbolt-firmware.c --- fwupd-1.4.5/plugins/thunderbolt/fu-thunderbolt-firmware.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/thunderbolt/fu-thunderbolt-firmware.c 2021-03-31 20:08:32.000000000 +0000 @@ -10,6 +10,7 @@ #include #include "fu-common.h" +#include "fu-common-version.h" #include "fu-thunderbolt-firmware.h" typedef struct @@ -73,7 +74,7 @@ fu_thunderbolt_firmware_get_device_id (FuThunderboltFirmware *self) { FuThunderboltFirmwarePrivate *priv; - g_return_val_if_fail (FU_IS_THUNDERBOLT_FIRMWARE (self), FALSE); + g_return_val_if_fail (FU_IS_THUNDERBOLT_FIRMWARE (self), 0x0); priv = GET_PRIVATE (self); return priv->device_id; } @@ -82,7 +83,7 @@ fu_thunderbolt_firmware_get_vendor_id (FuThunderboltFirmware *self) { FuThunderboltFirmwarePrivate *priv; - g_return_val_if_fail (FU_IS_THUNDERBOLT_FIRMWARE (self), FALSE); + g_return_val_if_fail (FU_IS_THUNDERBOLT_FIRMWARE (self), 0x0); priv = GET_PRIVATE (self); return priv->vendor_id; } @@ -91,7 +92,7 @@ fu_thunderbolt_firmware_get_model_id (FuThunderboltFirmware *self) { FuThunderboltFirmwarePrivate *priv; - g_return_val_if_fail (FU_IS_THUNDERBOLT_FIRMWARE (self), FALSE); + g_return_val_if_fail (FU_IS_THUNDERBOLT_FIRMWARE (self), 0x0); priv = GET_PRIVATE (self); return priv->model_id; } @@ -100,7 +101,7 @@ fu_thunderbolt_firmware_get_flash_size (FuThunderboltFirmware *self) { FuThunderboltFirmwarePrivate *priv; - g_return_val_if_fail (FU_IS_THUNDERBOLT_FIRMWARE (self), FALSE); + g_return_val_if_fail (FU_IS_THUNDERBOLT_FIRMWARE (self), 0x0); priv = GET_PRIVATE (self); return priv->flash_size; } @@ -120,6 +121,8 @@ return "Titan Ridge"; if (family == _FAMILY_BB) return "BB"; + if (family == _FAMILY_MR) + return "Maple Ridge"; return "Unknown"; } @@ -369,6 +372,7 @@ FuThunderboltFirmwareClass *klass_firmware = FU_THUNDERBOLT_FIRMWARE_GET_CLASS (firmware); guint8 tmp = 0; + guint16 version = 0; static const FuThunderboltHwInfo hw_info_arr[] = { { 0x156D, 2, _FAMILY_FR, 2 }, /* FR 4C */ { 0x156B, 2, _FAMILY_FR, 1 }, /* FR 2C */ @@ -382,9 +386,16 @@ { 0x15EA, 3, _FAMILY_TR, 2 }, /* TR 4C */ { 0x15EF, 3, _FAMILY_TR, 2 }, /* TR 4C device */ { 0x15EE, 3, _FAMILY_BB, 0 }, /* BB device */ + /* Maple ridge devices + * NOTE: These are expected to be flashed via UEFI capsules *not* Thunderbolt plugin + * Flashing via fwupd will require matching kernel work. + * They're left here only for parsing the binaries + */ + { 0x1136, 4, _FAMILY_MR, 2 }, + { 0x1137, 4, _FAMILY_MR, 2 }, { 0 } }; - + g_autofree gchar *version_str = NULL; g_autoptr(FuFirmwareImage) img = fu_firmware_image_new (fw); /* add this straight away so we can read it without a self */ @@ -442,7 +453,7 @@ g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, - "Unknown controller"); + "Unknown controller: %x", priv->device_id); return FALSE; } @@ -491,6 +502,24 @@ priv->has_pd = fu_thunderbolt_firmware_valid_pd_pointer (pd_pointer); } + /* versions */ + switch (priv->family) { + case _FAMILY_TR: + if (!fu_thunderbolt_firmware_read_uint16 (self, + _SECTION_DIGITAL, + 0x09, + &version, + error)) { + g_prefix_error (error, "failed to read version: "); + return FALSE; + } + version_str = fu_common_version_from_uint16 (version, FWUPD_VERSION_FORMAT_BCD); + fu_firmware_set_version (FU_FIRMWARE (self), version_str); + break; + default: + break; + } + if (priv->is_host) { switch (priv->family) { case _FAMILY_AR: @@ -519,6 +548,7 @@ static void fu_thunderbolt_firmware_init (FuThunderboltFirmware *self) { + fu_firmware_add_flag (FU_FIRMWARE (self), FU_FIRMWARE_FLAG_HAS_VID_PID); } static void diff -Nru fwupd-1.4.5/plugins/thunderbolt/fu-thunderbolt-firmware.h fwupd-1.5.8/plugins/thunderbolt/fu-thunderbolt-firmware.h --- fwupd-1.4.5/plugins/thunderbolt/fu-thunderbolt-firmware.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/thunderbolt/fu-thunderbolt-firmware.h 2021-03-31 20:08:32.000000000 +0000 @@ -28,6 +28,7 @@ _FAMILY_AR_C, _FAMILY_TR, _FAMILY_BB, + _FAMILY_MR, } FuThunderboltFamily; struct _FuThunderboltFirmwareClass diff -Nru fwupd-1.4.5/plugins/thunderbolt/meson.build fwupd-1.5.8/plugins/thunderbolt/meson.build --- fwupd-1.4.5/plugins/thunderbolt/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/thunderbolt/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,7 @@ +if get_option('plugin_thunderbolt') +if not get_option('gudev') + error('gudev is required for plugin_thunderbolt') +endif cargs = ['-DG_LOG_DOMAIN="FuPluginThunderbolt"'] cargs += '-DTESTDATADIR="' + join_paths(meson.source_root(), 'data', 'tests') + '"' install_data([ @@ -70,3 +74,4 @@ endif test('thunderbolt-self-test', e, env: test_env, timeout : 120) endif +endif diff -Nru fwupd-1.4.5/plugins/thunderbolt/README.md fwupd-1.5.8/plugins/thunderbolt/README.md --- fwupd-1.4.5/plugins/thunderbolt/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/thunderbolt/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -37,6 +37,28 @@ * `TBT-$(vid)$(pid)-native-controller$(num)` +For retimers the only GUID created is as follows: +* `TBT-$(vid)$(pid)-retimer$index` + +The retimer index is oriented around the physical connection within +the machine. It is important as multiple controllers may otherwise +identify identically. + +Update Behavior +--------------- + +For most devices the firmware is written to the device at runtime and the +update is applied immediately. Once complete the controller may reboot +which may cause all connected USB and TBT devices to be reenumerated. + +For some devices and circumstances (such as the Dell WD19 with a new enough +kernel) the device will remain functional for the duration of the update. +The update will complete on unplug. + +If a user sets `DelayedActivation` configuration option then the update will +be staged but not completed until `activate` is separately called such as at +logout or shutdown. + Vendor ID Security ------------------ @@ -85,3 +107,7 @@ If the controller is in native enumeration mode, the string "-native" is added at the end so the format is "TBT-vvvvdddd-native". + +External interface access +------------------------- +This plugin requires read/write access to `/sys/bus/thunderbolt`. diff -Nru fwupd-1.4.5/plugins/thunderbolt/thunderbolt.quirk fwupd-1.5.8/plugins/thunderbolt/thunderbolt.quirk --- fwupd-1.4.5/plugins/thunderbolt/thunderbolt.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/thunderbolt/thunderbolt.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,3 @@ # match all devices with this udev subsystem -[DeviceInstanceId=THUNDERBOLT] +[THUNDERBOLT] Plugin = thunderbolt diff -Nru fwupd-1.4.5/plugins/tpm/fu-plugin-tpm.c fwupd-1.5.8/plugins/tpm/fu-plugin-tpm.c --- fwupd-1.4.5/plugins/tpm/fu-plugin-tpm.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/tpm/fu-plugin-tpm.c 2021-03-31 20:08:32.000000000 +0000 @@ -6,15 +6,59 @@ #include "config.h" -#include "fu-hash.h" #include "fu-plugin-vfuncs.h" #include "fu-tpm-device.h" +struct FuPluginData { + gboolean has_tpm; + gboolean has_tpm_v20; +}; + void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_udev_subsystem (plugin, "tpm"); fu_plugin_set_device_gtype (plugin, FU_TYPE_TPM_DEVICE); } + +void +fu_plugin_device_added (FuPlugin *plugin, FuDevice *dev) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + const gchar *family = fu_tpm_device_get_family (FU_TPM_DEVICE (dev)); + + data->has_tpm = TRUE; + if (g_strcmp0 (family, "2.0") == 0) + data->has_tpm_v20 = TRUE; + fu_plugin_add_report_metadata (plugin, "TpmFamily", family); +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_TPM_VERSION_20); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fu_security_attrs_append (attrs, attr); + + /* check exists, and in v2.0 mode */ + if (!data->has_tpm) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND); + return; + } + if (!data->has_tpm_v20) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_FOUND); +} diff -Nru fwupd-1.4.5/plugins/tpm/fu-tpm-device.c fwupd-1.5.8/plugins/tpm/fu-tpm-device.c --- fwupd-1.4.5/plugins/tpm/fu-tpm-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/tpm/fu-tpm-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -12,6 +12,7 @@ struct _FuTpmDevice { FuUdevDevice parent_instance; + gchar *family; }; G_DEFINE_TYPE (FuTpmDevice, fu_tpm_device, FU_TYPE_UDEV_DEVICE) @@ -22,10 +23,19 @@ } G_DEFINE_AUTOPTR_CLEANUP_FUNC (ESYS_CONTEXT, Esys_Finalize_autoptr_cleanup) +const gchar * +fu_tpm_device_get_family (FuTpmDevice *self) +{ + return self->family; +} + static gboolean -fu_tpm_device_probe (FuUdevDevice *device, GError **error) +fu_tpm_device_probe (FuDevice *device, GError **error) { - return fu_udev_device_set_physical_id (device, "tpm", error); + /* FuUdevDevice->probe */ + if (!FU_DEVICE_CLASS (fu_tpm_device_parent_class)->probe (device, error)) + return FALSE; + return fu_udev_device_set_physical_id (FU_UDEV_DEVICE (device), "tpm", error); } static gboolean @@ -134,6 +144,7 @@ static gboolean fu_tpm_device_setup (FuDevice *device, GError **error) { + FuTpmDevice *self = FU_TPM_DEVICE (device); FwupdVersionFormat verfmt; TSS2_RC rc; const gchar *tmp; @@ -141,7 +152,6 @@ guint32 version1 = 0; guint32 version2 = 0; guint64 version_raw; - g_autofree gchar *family = NULL; g_autofree gchar *id1 = NULL; g_autofree gchar *id2 = NULL; g_autofree gchar *id3 = NULL; @@ -171,23 +181,23 @@ } /* lookup guaranteed details from TPM */ - family = fu_tpm_device_get_string (ctx, TPM2_PT_FAMILY_INDICATOR, error); - if (family == NULL) { - g_prefix_error (error, "failed to read TPM family"); + self->family = fu_tpm_device_get_string (ctx, TPM2_PT_FAMILY_INDICATOR, error); + if (self->family == NULL) { + g_prefix_error (error, "failed to read TPM family: "); return FALSE; } manufacturer = fu_tpm_device_get_string (ctx, TPM2_PT_MANUFACTURER, error); if (manufacturer == NULL) { - g_prefix_error (error, "failed to read TPM manufacturer"); + g_prefix_error (error, "failed to read TPM manufacturer: "); return FALSE; } model1 = fu_tpm_device_get_string (ctx, TPM2_PT_VENDOR_STRING_1, error); if (model1 == NULL) { - g_prefix_error (error, "failed to read TPM vendor string"); + g_prefix_error (error, "failed to read TPM vendor string: "); return FALSE; } if (!fu_tpm_device_get_uint32 (ctx, TPM2_PT_VENDOR_TPM_TYPE, &tpm_type, error)) { - g_prefix_error (error, "failed to read TPM type"); + g_prefix_error (error, "failed to read TPM type: "); return FALSE; } @@ -202,14 +212,14 @@ fu_device_add_instance_id (device, id1); id2 = g_strdup_printf ("TPM\\VEN_%s&MOD_%s", manufacturer, model); fu_device_add_instance_id (device, id2); - id3 = g_strdup_printf ("TPM\\VEN_%s&DEV_%04X&VER_%s", manufacturer, tpm_type, family); + id3 = g_strdup_printf ("TPM\\VEN_%s&DEV_%04X&VER_%s", manufacturer, tpm_type, self->family); fu_device_add_instance_id (device, id3); - id4 = g_strdup_printf ("TPM\\VEN_%s&MOD_%s&VER_%s", manufacturer, model, family); + id4 = g_strdup_printf ("TPM\\VEN_%s&MOD_%s&VER_%s", manufacturer, model, self->family); fu_device_add_instance_id (device, id4); /* enforce vendors can only ship updates for their own hardware */ vendor_id = g_strdup_printf ("TPM:%s", manufacturer); - fu_device_set_vendor_id (device, vendor_id); + fu_device_add_vendor_id (device, vendor_id); tmp = fu_tpm_device_convert_manufacturer (manufacturer); fu_device_set_vendor (device, tmp != NULL ? tmp : manufacturer); @@ -245,6 +255,8 @@ static void fu_tpm_device_finalize (GObject *object) { + FuTpmDevice *self = FU_TPM_DEVICE (object); + g_free (self->family); G_OBJECT_CLASS (fu_tpm_device_parent_class)->finalize (object); } @@ -253,8 +265,7 @@ { GObjectClass *object_class = G_OBJECT_CLASS (klass); FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - FuUdevDeviceClass *klass_udev_device = FU_UDEV_DEVICE_CLASS (klass); object_class->finalize = fu_tpm_device_finalize; klass_device->setup = fu_tpm_device_setup; - klass_udev_device->probe = fu_tpm_device_probe; + klass_device->probe = fu_tpm_device_probe; } diff -Nru fwupd-1.4.5/plugins/tpm/fu-tpm-device.h fwupd-1.5.8/plugins/tpm/fu-tpm-device.h --- fwupd-1.4.5/plugins/tpm/fu-tpm-device.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/tpm/fu-tpm-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -10,3 +10,5 @@ #define FU_TYPE_TPM_DEVICE (fu_tpm_device_get_type ()) G_DECLARE_FINAL_TYPE (FuTpmDevice, fu_tpm_device, FU, TPM_DEVICE, FuUdevDevice) + +const gchar *fu_tpm_device_get_family (FuTpmDevice *self); diff -Nru fwupd-1.4.5/plugins/tpm/meson.build fwupd-1.5.8/plugins/tpm/meson.build --- fwupd-1.4.5/plugins/tpm/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/tpm/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,7 @@ +if get_option('plugin_tpm') +if not get_option('gudev') + error('gudev is required for tpm') +endif cargs = ['-DG_LOG_DOMAIN="FuPluginTpm"'] install_data([ @@ -29,3 +33,4 @@ tpm2tss, ], ) +endif diff -Nru fwupd-1.4.5/plugins/tpm/README.md fwupd-1.5.8/plugins/tpm/README.md --- fwupd-1.4.5/plugins/tpm/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/tpm/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -30,3 +30,7 @@ ------------------ The device is not upgradable and thus requires no vendor ID set. + +External interface access +------------------------- +This plugin uses the tpm2-tss library to access the TPM. It requires access to `/sys/class/tpm`. diff -Nru fwupd-1.4.5/plugins/tpm/tpm.quirk fwupd-1.5.8/plugins/tpm/tpm.quirk --- fwupd-1.4.5/plugins/tpm/tpm.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/tpm/tpm.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,2 +1,2 @@ -[DeviceInstanceId=TPM] +[TPM] Plugin = tpm diff -Nru fwupd-1.4.5/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c fwupd-1.5.8/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c --- fwupd-1.4.5/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c 2021-03-31 20:08:32.000000000 +0000 @@ -6,22 +6,23 @@ #include "config.h" -#include "fu-hash.h" #include "fu-plugin-vfuncs.h" #include "fu-tpm-eventlog-device.h" -#include "fu-efivar.h" struct FuPluginData { GPtrArray *pcr0s; - gboolean secure_boot_problem; + gboolean has_tpm_device; + gboolean has_uefi_device; + gboolean reconstructed; }; void fu_plugin_init (FuPlugin *plugin) { fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); - fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_BEFORE, "uefi"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_BEFORE, "uefi_capsule"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_AFTER, "tpm"); fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); } @@ -42,16 +43,9 @@ g_autofree gchar *str = NULL; g_autofree guint8 *buf = NULL; g_autoptr(FuTpmEventlogDevice) dev = NULL; - g_autoptr(GError) error_local = NULL; - if (!g_file_get_contents (fn, (gchar **) &buf, &bufsz, &error_local)) { - if (fu_efivar_supported (NULL) && !fu_efivar_secure_boot_enabled ()) { - data->secure_boot_problem = TRUE; - return TRUE; - } - g_propagate_error (error, g_steal_pointer (&error_local)); + if (!g_file_get_contents (fn, (gchar **) &buf, &bufsz, error)) return FALSE; - } if (bufsz == 0) { g_set_error (error, FWUPD_ERROR, @@ -73,48 +67,107 @@ const gchar *csum = g_ptr_array_index (data->pcr0s, i); fu_device_add_checksum (FU_DEVICE (dev), csum); } + for (guint i = 0; i < data->pcr0s->len; i++) { + const gchar *csum = g_ptr_array_index (data->pcr0s, i); + GChecksumType csum_type = fwupd_checksum_guess_kind (csum); + if (csum_type == G_CHECKSUM_SHA1) { + fu_plugin_add_report_metadata (plugin, "Pcr0_SHA1", csum); + continue; + } + if (csum_type == G_CHECKSUM_SHA256) { + fu_plugin_add_report_metadata (plugin, "Pcr0_SHA256", csum); + continue; + } + } /* add optional report metadata */ str = fu_tpm_eventlog_device_report_metadata (dev); - g_debug ("using TPM event log report data of:\n%s", str); fu_plugin_add_report_metadata (plugin, "TpmEventLog", str); fu_plugin_device_add (plugin, FU_DEVICE (dev)); return TRUE; } -void -fu_plugin_device_registered (FuPlugin *plugin, FuDevice *device) +static void +fu_plugin_device_registered_tpm (FuPlugin *plugin, FuDevice *device) { FuPluginData *data = fu_plugin_get_data (plugin); - GPtrArray *checksums; + data->has_tpm_device = TRUE; +} - /* only care about UEFI devices from ESRT */ - if (g_strcmp0 (fu_device_get_plugin (device), "uefi") != 0) - return; +static void +fu_plugin_device_registered_uefi (FuPlugin *plugin, FuDevice *device) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + GPtrArray *checksums; /* only the system-firmware device gets checksums */ checksums = fu_device_get_checksums (device); if (checksums->len == 0) return; - - if (data->secure_boot_problem) { - g_warning ("Platform firmware measurement unavailable. Secure boot is disabled in " - "BIOS setup, enabling it may fix this issue"); - return; - } + data->has_uefi_device = TRUE; for (guint i = 0; i < checksums->len; i++) { const gchar *checksum = g_ptr_array_index (checksums, i); + data->reconstructed = FALSE; for (guint j = 0; j < data->pcr0s->len; j++) { const gchar *checksum_tmp = g_ptr_array_index (data->pcr0s, j); + /* skip unless same algorithm */ + if (strlen (checksum) != strlen (checksum_tmp)) + continue; if (g_strcmp0 (checksum, checksum_tmp) == 0) { - g_debug ("TPM reconstructed event log matched PCR0 reading"); - return; + data->reconstructed = TRUE; + break; } } + /* check at least one reconstruction for this algorithm */ + if (!data->reconstructed) + return; + } +} + +void +fu_plugin_device_registered (FuPlugin *plugin, FuDevice *device) +{ + /* only care about UEFI devices from ESRT */ + if (g_strcmp0 (fu_device_get_plugin (device), "uefi_capsule") == 0) { + fu_plugin_device_registered_uefi (plugin, device); + return; + } + + /* detect the system TPM device */ + if (g_strcmp0 (fu_device_get_plugin (device), "tpm") == 0) { + fu_plugin_device_registered_tpm (plugin, device); + return; + } +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* no TPM device */ + if (!data->has_tpm_device) + return; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_TPM_RECONSTRUCTION_PCR0); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT); + fu_security_attrs_append (attrs, attr); + + /* check reconstructed to PCR0 */ + if (fu_plugin_has_flag (plugin, FWUPD_PLUGIN_FLAG_DISABLED) || !data->has_uefi_device) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND); + return; + } + if (!data->reconstructed) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); + return; } - /* urgh, this is unexpected */ - g_warning ("TPM PCR0 differs from reconstruction, " - "please see https://github.com/fwupd/fwupd/wiki/TPM-PCR0-differs-from-reconstruction"); + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_VALID); } diff -Nru fwupd-1.4.5/plugins/tpm-eventlog/fu-self-test.c fwupd-1.5.8/plugins/tpm-eventlog/fu-self-test.c --- fwupd-1.4.5/plugins/tpm-eventlog/fu-self-test.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/tpm-eventlog/fu-self-test.c 2021-03-31 20:08:32.000000000 +0000 @@ -14,6 +14,7 @@ static void fu_test_tpm_eventlog_parse_v1_func (void) { + const gchar *ci = g_getenv ("CI_NETWORK"); const gchar *tmp; gboolean ret; gsize bufsz = 0; @@ -24,7 +25,11 @@ g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) pcr0s = NULL; - fn = g_build_filename (TESTDATADIR, "binary_bios_measurements-v1", NULL); + fn = g_test_build_filename (G_TEST_DIST, "tests", "binary_bios_measurements-v1", NULL); + if (!g_file_test (fn, G_FILE_TEST_EXISTS) && ci == NULL) { + g_test_skip ("Missing binary_bios_measurements-v1"); + return; + } ret = g_file_get_contents (fn, (gchar **) &buf, &bufsz, &error); g_assert_no_error (error); g_assert_true (ret); @@ -48,6 +53,7 @@ static void fu_test_tpm_eventlog_parse_v2_func (void) { + const gchar *ci = g_getenv ("CI_NETWORK"); const gchar *tmp; gboolean ret; gsize bufsz = 0; @@ -58,7 +64,11 @@ g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) pcr0s = NULL; - fn = g_build_filename (TESTDATADIR, "binary_bios_measurements-v2", NULL); + fn = g_test_build_filename (G_TEST_DIST, "tests", "binary_bios_measurements-v2", NULL); + if (!g_file_test (fn, G_FILE_TEST_EXISTS) && ci == NULL) { + g_test_skip ("Missing binary_bios_measurements-v2"); + return; + } ret = g_file_get_contents (fn, (gchar **) &buf, &bufsz, &error); g_assert_no_error (error); g_assert_true (ret); @@ -75,9 +85,11 @@ pcr0s = fu_tpm_eventlog_device_get_checksums (dev, 0, &error); g_assert_no_error (error); g_assert_nonnull (pcr0s); - g_assert_cmpint (pcr0s->len, ==, 1); + g_assert_cmpint (pcr0s->len, ==, 2); tmp = g_ptr_array_index (pcr0s, 0); g_assert_cmpstr (tmp, ==, "ebead4b31c7c49e193c440cd6ee90bc1b61a3ca6"); + tmp = g_ptr_array_index (pcr0s, 1); + g_assert_cmpstr (tmp, ==, "6d9fed68092cfb91c9552bcb7879e75e1df36efd407af67690dc3389a5722fab"); } int diff -Nru fwupd-1.4.5/plugins/tpm-eventlog/fu-tpm-eventlog.c fwupd-1.5.8/plugins/tpm-eventlog/fu-tpm-eventlog.c --- fwupd-1.4.5/plugins/tpm-eventlog/fu-tpm-eventlog.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/tpm-eventlog/fu-tpm-eventlog.c 2021-03-31 20:08:32.000000000 +0000 @@ -15,6 +15,7 @@ #include #include +#include "fwupd-common-private.h" #include "fu-tpm-eventlog-parser.h" static gint @@ -36,12 +37,12 @@ g_autofree guint8 *buf = NULL; g_autoptr(GPtrArray) items = NULL; g_autoptr(GString) str = g_string_new (NULL); + gint max_pcr = 0; /* parse this */ if (!g_file_get_contents (fn, (gchar **) &buf, &bufsz, error)) return FALSE; items = fu_tpm_eventlog_parser_new (buf, bufsz, - FU_TPM_EVENTLOG_PARSER_FLAG_ALL_ALGS | FU_TPM_EVENTLOG_PARSER_FLAG_ALL_PCRS, error); if (items == NULL) @@ -50,20 +51,32 @@ for (guint i = 0; i < items->len; i++) { FuTpmEventlogItem *item = g_ptr_array_index (items, i); + if (item->pcr > max_pcr) + max_pcr = item->pcr; if (pcr >= 0 && item->pcr != pcr) continue; fu_tpm_eventlog_item_to_string (item, 0, str); g_string_append (str, "\n"); } - fu_common_string_append_kv (str, 0, "PCRs", NULL); - for (guint8 i = 0; i < 10; i++) { + if (pcr > max_pcr) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, + "invalid PCR specified: %d", pcr); + return FALSE; + } + fu_common_string_append_kv (str, 0, "Reconstructed PCRs", NULL); + for (guint8 i = 0; i <= max_pcr; i++) { g_autoptr(GPtrArray) pcrs = fu_tpm_eventlog_calc_checksums (items, i, NULL); if (pcrs == NULL) continue; for (guint j = 0; j < pcrs->len; j++) { const gchar *csum = g_ptr_array_index (pcrs, j); - g_autofree gchar *title = g_strdup_printf ("%x", i); - fu_common_string_append_kv (str, 1, title, csum); + g_autofree gchar *title = NULL; + g_autofree gchar *pretty = NULL; + if (pcr >= 0 && i != (guint) pcr) + continue; + title = g_strdup_printf ("PCR %x", i); + pretty = fwupd_checksum_format_for_display (csum); + fu_common_string_append_kv (str, 1, title, pretty); } } @@ -107,8 +120,9 @@ g_set_application_name (_("fwupd TPM event log utility")); g_option_context_add_main_entries (context, options, NULL); g_option_context_set_description (context, - "This tool will read and parse the TPM event log " - "from the system firwmare."); + /* TRANSLATORS: CLI description */ + _("This tool will read and parse the TPM event log " + "from the system firmware.")); if (!g_option_context_parse (context, &argc, &argv, &error)) { /* TRANSLATORS: the user didn't read the man page */ g_print ("%s: %s\n", _("Failed to parse arguments"), diff -Nru fwupd-1.4.5/plugins/tpm-eventlog/fu-tpm-eventlog-device.c fwupd-1.5.8/plugins/tpm-eventlog/fu-tpm-eventlog-device.c --- fwupd-1.4.5/plugins/tpm-eventlog/fu-tpm-eventlog-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/tpm-eventlog/fu-tpm-eventlog-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -30,7 +30,7 @@ fu_tpm_eventlog_device_to_string (FuDevice *device, guint idt, GString *str) { FuTpmEventlogDevice *self = FU_TPM_EVENTLOG_DEVICE (device); - if (self->items->len > 0) { + if (self->items != NULL && self->items->len > 0) { fu_common_string_append_kv (str, idt, "Items", NULL); for (guint i = 0; i < self->items->len; i++) { FuTpmEventlogItem *item = g_ptr_array_index (self->items, i); diff -Nru fwupd-1.4.5/plugins/tpm-eventlog/fu-tpm-eventlog-parser.c fwupd-1.5.8/plugins/tpm-eventlog/fu-tpm-eventlog-parser.c --- fwupd-1.4.5/plugins/tpm-eventlog/fu-tpm-eventlog-parser.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/tpm-eventlog/fu-tpm-eventlog-parser.c 2021-03-31 20:08:32.000000000 +0000 @@ -110,6 +110,7 @@ for (guint i = 0; i < digestcnt; i++) { guint16 alg_type = 0; guint32 alg_size = 0; + g_autofree guint8 *digest = NULL; /* get checksum type */ if (!fu_common_read_uint16_safe (buf, bufsz, idx, @@ -127,22 +128,19 @@ /* build checksum */ idx += sizeof(alg_type); - if (alg_type == TPM2_ALG_SHA1 || - flags & FU_TPM_EVENTLOG_PARSER_FLAG_ALL_ALGS) { - g_autofree guint8 *digest = g_malloc0 (alg_size); - /* copy hash */ - if (!fu_memcpy_safe (digest, alg_size, 0x0, /* dst */ - buf, bufsz, idx, /* src */ - alg_size, error)) - return NULL; + /* copy hash */ + digest = g_malloc0 (alg_size); + if (!fu_memcpy_safe (digest, alg_size, 0x0, /* dst */ + buf, bufsz, idx, /* src */ + alg_size, error)) + return NULL; - /* save this for analysis */ - if (alg_type == TPM2_ALG_SHA1) - checksum_sha1 = g_bytes_new_take (g_steal_pointer (&digest), alg_size); - else if (alg_type == TPM2_ALG_SHA256) - checksum_sha256 = g_bytes_new_take (g_steal_pointer (&digest), alg_size); - } + /* save this for analysis */ + if (alg_type == TPM2_ALG_SHA1) + checksum_sha1 = g_bytes_new_take (g_steal_pointer (&digest), alg_size); + else if (alg_type == TPM2_ALG_SHA256) + checksum_sha256 = g_bytes_new_take (g_steal_pointer (&digest), alg_size); /* next block */ idx += alg_size; diff -Nru fwupd-1.4.5/plugins/tpm-eventlog/fu-tpm-eventlog-parser.h fwupd-1.5.8/plugins/tpm-eventlog/fu-tpm-eventlog-parser.h --- fwupd-1.4.5/plugins/tpm-eventlog/fu-tpm-eventlog-parser.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/tpm-eventlog/fu-tpm-eventlog-parser.h 2021-03-31 20:08:32.000000000 +0000 @@ -13,7 +13,6 @@ typedef enum { FU_TPM_EVENTLOG_PARSER_FLAG_NONE = 0, FU_TPM_EVENTLOG_PARSER_FLAG_ALL_PCRS = 1 << 0, - FU_TPM_EVENTLOG_PARSER_FLAG_ALL_ALGS = 1 << 1, FU_TPM_EVENTLOG_PARSER_FLAG_LAST } FuTpmEventlogParserFlags; diff -Nru fwupd-1.4.5/plugins/tpm-eventlog/fuzzing/v2.bin fwupd-1.5.8/plugins/tpm-eventlog/fuzzing/v2.bin --- fwupd-1.4.5/plugins/tpm-eventlog/fuzzing/v2.bin 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/tpm-eventlog/fuzzing/v2.bin 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +Spec ID Event03 diff -Nru fwupd-1.4.5/plugins/tpm-eventlog/meson.build fwupd-1.5.8/plugins/tpm-eventlog/meson.build --- fwupd-1.4.5/plugins/tpm-eventlog/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/tpm-eventlog/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,4 @@ +if get_option('plugin_tpm') cargs = ['-DG_LOG_DOMAIN="FuPluginTpmEventlog"'] shared_module('fu_plugin_tpm_eventlog', @@ -27,8 +28,9 @@ ) if get_option('tests') - testdatadir = join_paths(meson.current_source_dir(), 'tests') - cargs += '-DTESTDATADIR="' + testdatadir + '"' + testdatadirs = environment() + testdatadirs.set('G_TEST_SRCDIR', meson.current_source_dir()) + testdatadirs.set('G_TEST_BUILDDIR', meson.current_build_dir()) e = executable( 'tpm-eventlog-self-test', fu_hash, @@ -53,7 +55,7 @@ ], c_args : cargs ) - test('tpm-eventlog-self-test', e) + test('tpm-eventlog-self-test', e, env : testdatadirs) # added to installed-tests endif fwupdtpmevlog = executable( @@ -97,11 +99,16 @@ ) endif -run_target('fuzz-tpm-eventlog', - command: [ - join_paths(meson.source_root(), 'contrib/afl-fuzz.py'), - '-i', join_paths(meson.current_source_dir(), 'tests'), - '-o', join_paths(meson.current_build_dir(), 'findings'), - fwupdtpmevlog, - ], -) +if honggfuzz.found() + run_target('fuzz-tpm-eventlog', + command: [ + honggfuzz, + '--input', join_paths(meson.current_source_dir(), 'fuzzing'), + '--output', join_paths(meson.current_build_dir(), 'fuzzing-corpus'), + '--workspace', join_paths(meson.current_build_dir(), 'fuzzing-findings'), + '--verifier', + '--', fwupdtpmevlog, '___FILE___', + ], + ) +endif +endif diff -Nru fwupd-1.4.5/plugins/tpm-eventlog/README.md fwupd-1.5.8/plugins/tpm-eventlog/README.md --- fwupd-1.4.5/plugins/tpm-eventlog/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/tpm-eventlog/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -15,3 +15,7 @@ ------------------ The device is not upgradable and thus requires no vendor ID set. + +External interface access +------------------------- +This plugin requires read only access to `/sys/kernel/security/tpm0/binary_bios_measurements`. Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/tpm-eventlog/tests/binary_bios_measurements-v1 and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/tpm-eventlog/tests/binary_bios_measurements-v1 differ Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/tpm-eventlog/tests/binary_bios_measurements-v2 and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/tpm-eventlog/tests/binary_bios_measurements-v2 differ diff -Nru fwupd-1.4.5/plugins/uefi/efi/fwup-cleanups.h fwupd-1.5.8/plugins/uefi/efi/fwup-cleanups.h --- fwupd-1.4.5/plugins/uefi/efi/fwup-cleanups.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/efi/fwup-cleanups.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2019 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#define _DEFINE_CLEANUP_FUNCTION0(Type, name, func) \ - static inline VOID name(VOID *v) \ - { \ - if (*(Type*)v) \ - func (*(Type*)v); \ - } -_DEFINE_CLEANUP_FUNCTION0(VOID *, _FreePool_p, FreePool) -#define _cleanup_free __attribute__ ((cleanup(_FreePool_p))) - -static inline VOID * -_steal_pointer(VOID *pp) -{ - VOID **ptr = (VOID **) pp; - VOID *ref = *ptr; - *ptr = NULL; - return ref; -} diff -Nru fwupd-1.4.5/plugins/uefi/efi/fwup-common.c fwupd-1.5.8/plugins/uefi/efi/fwup-common.c --- fwupd-1.4.5/plugins/uefi/efi/fwup-common.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/efi/fwup-common.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2019 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include -#include - -#include "fwup-debug.h" -#include "fwup-common.h" - -VOID -fwup_msleep(unsigned long msecs) -{ - BS->Stall(msecs); -} - -/* - * Allocate some raw pages that aren't part of the pool allocator. - */ -VOID * -fwup_malloc_raw(UINTN size) -{ - UINTN pages = size / 4096 + ((size % 4096) ? 1 : 0); /* page size is always 4096 */ - EFI_STATUS rc; - EFI_PHYSICAL_ADDRESS pageaddr = 0; - EFI_ALLOCATE_TYPE type = AllocateAnyPages; - - if (sizeof(VOID *) == 4) { - pageaddr = 0xffffffffULL - 8192; - type = AllocateMaxAddress; - } - - rc = uefi_call_wrapper(BS->AllocatePages, 4, type, - EfiLoaderData, pages, - &pageaddr); - if (EFI_ERROR(rc)) { - fwup_warning(L"Could not allocate %d", size); - return NULL; - } - if (sizeof(VOID *) == 4 && pageaddr > 0xffffffffULL) { - uefi_call_wrapper(BS->FreePages, 2, pageaddr, pages); - fwup_warning(L"Got bad allocation at 0x%016x", (UINT64)pageaddr); - return NULL; - } - return (VOID *)(UINTN)pageaddr; -} - -/* - * Free our raw page allocations. - */ -static EFI_STATUS -fwup_free_raw(VOID *addr, UINTN size) -{ - UINTN pages = size / 4096 + ((size % 4096) ? 1 : 0); - return uefi_call_wrapper(BS->FreePages, 2, - (EFI_PHYSICAL_ADDRESS)(UINTN)addr, pages); -} - -VOID * -fwup_malloc (UINTN size) -{ - VOID *addr = AllocatePool(size); - if (addr == NULL) - fwup_warning(L"Could not allocate %d", size); - return addr; -} - -VOID * -fwup_malloc0 (UINTN size) -{ - VOID *addr = AllocateZeroPool(size); - if (addr == NULL) - fwup_warning(L"Could not allocate %d", size); - return addr; -} - -EFI_STATUS -fwup_time(EFI_TIME *ts) -{ - EFI_TIME_CAPABILITIES timecaps = { 0, }; - return uefi_call_wrapper(RT->GetTime, 2, ts, &timecaps); -} - -EFI_STATUS -fwup_read_file(EFI_FILE_HANDLE fh, UINT8 **buf_out, UINTN *buf_size_out) -{ - const UINTN bs = 512; - UINTN i = 0; - UINTN n_blocks = 4096; - UINT8 *buf = NULL; - - while (1) { - VOID *newb = NULL; - UINTN news = n_blocks * bs * 2; - - newb = fwup_malloc_raw(news); - if (newb == NULL) - return EFI_OUT_OF_RESOURCES; - if (buf != NULL) { - CopyMem(newb, buf, bs * n_blocks); - fwup_free_raw(buf, bs * n_blocks); - } - buf = newb; - n_blocks *= 2; - - for (; i < n_blocks; i++) { - EFI_STATUS rc; - UINTN sz = bs; - - rc = uefi_call_wrapper(fh->Read, 3, fh, &sz, &buf[i * bs]); - if (EFI_ERROR(rc)) { - fwup_free_raw(buf, bs * n_blocks); - fwup_warning(L"Could not read file: %r", rc); - return rc; - } - - if (sz != bs) { - *buf_size_out = bs * i + sz; - *buf_out = buf; - return EFI_SUCCESS; - } - } - } - return EFI_SUCCESS; -} diff -Nru fwupd-1.4.5/plugins/uefi/efi/fwup-common.h fwupd-1.5.8/plugins/uefi/efi/fwup-common.h --- fwupd-1.4.5/plugins/uefi/efi/fwup-common.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/efi/fwup-common.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2015-2016 Peter Jones - * Copyright (C) 2019 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include "fwup-efi.h" - -VOID fwup_msleep (unsigned long msecs); -EFI_STATUS fwup_time (EFI_TIME *ts); -EFI_STATUS fwup_read_file (EFI_FILE_HANDLE fh, - UINT8 **buf_out, - UINTN *buf_size_out); -VOID *fwup_malloc_raw (UINTN size); - -VOID *fwup_malloc (UINTN size); -VOID *fwup_malloc0 (UINTN size); - -#define fwup_new(struct_type, n) ((struct_type*)fwup_malloc((n)*sizeof(struct_type))) -#define fwup_new0(struct_type, n) ((struct_type*)fwup_malloc0((n)*sizeof(struct_type))) diff -Nru fwupd-1.4.5/plugins/uefi/efi/fwupdate.c fwupd-1.5.8/plugins/uefi/efi/fwupdate.c --- fwupd-1.4.5/plugins/uefi/efi/fwupdate.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/efi/fwupdate.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,620 +0,0 @@ -/* - * Copyright (C) 2014-2018 Red Hat, Inc. - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include -#include - -#include "fwup-cleanups.h" -#include "fwup-common.h" -#include "fwup-efi.h" -#include "fwup-debug.h" - -#define UNUSED __attribute__((__unused__)) -#define GNVN_BUF_SIZE 1024 -#define FWUP_NUM_CAPSULE_UPDATES_MAX 128 - -typedef struct { - CHAR16 *name; - UINT32 attrs; - UINTN size; - FWUP_UPDATE_INFO *info; -} FWUP_UPDATE_TABLE; - -static VOID -fwup_update_table_free(FWUP_UPDATE_TABLE *update) -{ - FreePool(update->info); - FreePool(update->name); - FreePool(update); -} - -_DEFINE_CLEANUP_FUNCTION0(FWUP_UPDATE_TABLE *, _fwup_update_table_free_p, fwup_update_table_free) -#define _cleanup_update_table __attribute__ ((cleanup(_fwup_update_table_free_p))) - -#define SECONDS 1000000 - -static INTN -fwup_dp_size(EFI_DEVICE_PATH *dp, INTN limit) -{ - INTN ret = 0; - while (1) { - if (limit < 4) - break; - INTN nodelen = DevicePathNodeLength(dp); - if (nodelen > limit) - break; - limit -= nodelen; - ret += nodelen; - - if (IsDevicePathEnd(dp)) - return ret; - dp = NextDevicePathNode(dp); - } - return -1; -} - -static EFI_STATUS -fwup_populate_update_info(CHAR16 *name, FWUP_UPDATE_TABLE *info_out) -{ - EFI_STATUS rc; - FWUP_UPDATE_INFO *info = NULL; - UINTN info_size = 0; - UINT32 attrs = 0; - VOID *info_ptr = NULL; - - rc = fwup_get_variable(name, &fwupdate_guid, &info_ptr, &info_size, &attrs); - if (EFI_ERROR(rc)) - return rc; - info = (FWUP_UPDATE_INFO *)info_ptr; - - if (info_size < sizeof(*info)) { - fwup_warning(L"Update '%s' is is too small", name); - return EFI_INVALID_PARAMETER; - } - - if (info_size - sizeof(EFI_DEVICE_PATH) <= sizeof(*info)) { - fwup_warning(L"Update '%s' is malformed, " - L"and cannot hold a file path", name); - return EFI_INVALID_PARAMETER; - } - - EFI_DEVICE_PATH *hdr = (EFI_DEVICE_PATH *)&info->dp; - INTN is = EFI_FIELD_OFFSET(FWUP_UPDATE_INFO, dp); - if (is > (INTN)info_size) { - fwup_warning(L"Update '%s' has an invalid file path, " - L"device path offset is %d, but total size is %d", - name, is, info_size); - return EFI_INVALID_PARAMETER; - } - - is = info_size - is; - INTN sz = fwup_dp_size(hdr, info_size); - if (sz < 0 || is > (INTN)info_size || is != sz) { - fwup_warning(L"Update '%s' has an invalid file path, " - L"update info size: %d dp size: %d size for dp: %d", - name, info_size, sz, is); - return EFI_INVALID_PARAMETER; - } - - info_out->info = info; - info_out->size = info_size; - info_out->attrs = attrs; - info_out->name = StrDuplicate(name); - if (info_out->name == NULL) { - fwup_warning(L"Could not allocate %d", StrSize(name)); - return EFI_OUT_OF_RESOURCES; - } - - return EFI_SUCCESS; -} - -static EFI_STATUS -fwup_populate_update_table(FWUP_UPDATE_TABLE **updates, UINTN *n_updates_out) -{ - EFI_GUID vendor_guid = empty_guid; - EFI_STATUS rc; - UINTN n_updates = 0; - _cleanup_free CHAR16 *variable_name = NULL; - - /* How much do we trust "size of the VariableName buffer" to mean - * sizeof(vn) and not sizeof(vn)/sizeof(vn[0]) ? */ - variable_name = fwup_malloc0(GNVN_BUF_SIZE * 2); - if (variable_name == NULL) - return EFI_OUT_OF_RESOURCES; - - while (1) { - UINTN variable_name_size = GNVN_BUF_SIZE; - rc = uefi_call_wrapper(RT->GetNextVariableName, 3, - &variable_name_size, variable_name, - &vendor_guid); - if (rc == EFI_NOT_FOUND) - break; - - /* ignore any huge names */ - if (rc == EFI_BUFFER_TOO_SMALL) - continue; - if (EFI_ERROR(rc)) { - fwup_warning(L"Could not get variable name: %r", rc); - return rc; - } - - /* not one of our state variables */ - if (CompareGuid(&vendor_guid, &fwupdate_guid)) - continue; - - /* ignore debugging settings */ - if (StrCmp(variable_name, L"FWUPDATE_VERBOSE") == 0 || - StrCmp(variable_name, L"FWUPDATE_DEBUG_LOG") == 0) - continue; - - if (n_updates > FWUP_NUM_CAPSULE_UPDATES_MAX) { - fwup_warning(L"Ignoring update %s", variable_name); - continue; - } - - fwup_info(L"Found update %s", variable_name); - _cleanup_update_table FWUP_UPDATE_TABLE *update = fwup_malloc0(sizeof(FWUP_UPDATE_TABLE)); - if (update == NULL) - return EFI_OUT_OF_RESOURCES; - rc = fwup_populate_update_info(variable_name, update); - if (EFI_ERROR(rc)) { - fwup_delete_variable(variable_name, &fwupdate_guid); - fwup_warning(L"Could not populate update info for '%s'", variable_name); - return rc; - } - if (update->info->status & FWUPDATE_ATTEMPT_UPDATE) { - fwup_time(&update->info->time_attempted); - update->info->status = FWUPDATE_ATTEMPTED; - updates[n_updates++] = _steal_pointer(&update); - } - } - - *n_updates_out = n_updates; - return EFI_SUCCESS; -} - -static EFI_STATUS -fwup_search_file(EFI_DEVICE_PATH **file_dp, EFI_FILE_HANDLE *fh) -{ - EFI_DEVICE_PATH *dp, *parent_dp; - EFI_GUID sfsp = SIMPLE_FILE_SYSTEM_PROTOCOL; - EFI_GUID dpp = DEVICE_PATH_PROTOCOL; - UINTN n_handles, count; - EFI_STATUS rc; - _cleanup_free EFI_FILE_HANDLE *devices = NULL; - - rc = uefi_call_wrapper(BS->LocateHandleBuffer, 5, ByProtocol, &sfsp, - NULL, &n_handles, (EFI_HANDLE **)&devices); - if (EFI_ERROR(rc)) { - fwup_warning(L"Could not find handles"); - return rc; - } - - dp = *file_dp; - - fwup_debug(L"Searching Device Path: %s...", DevicePathToStr(dp)); - parent_dp = DuplicateDevicePath(dp); - if (parent_dp == NULL) - return EFI_INVALID_PARAMETER; - - dp = parent_dp; - count = 0; - while (1) { - if (IsDevicePathEnd(dp)) - return EFI_INVALID_PARAMETER; - - if (DevicePathType(dp) == MEDIA_DEVICE_PATH && - DevicePathSubType(dp) == MEDIA_FILEPATH_DP) - break; - - dp = NextDevicePathNode(dp); - ++count; - } - - SetDevicePathEndNode(dp); - fwup_debug(L"Device Path prepared: %s", DevicePathToStr(parent_dp)); - - for (UINTN i = 0; i < n_handles; i++) { - EFI_DEVICE_PATH *path; - - rc = uefi_call_wrapper(BS->HandleProtocol, 3, devices[i], &dpp, - (VOID **)&path); - if (EFI_ERROR(rc)) - continue; - - fwup_debug(L"Device supporting SFSP: %s", DevicePathToStr(path)); - - while (!IsDevicePathEnd(path)) { - fwup_debug(L"Comparing: %s and %s", - DevicePathToStr(parent_dp), - DevicePathToStr(path)); - - if (LibMatchDevicePaths(path, parent_dp) == TRUE) { - *fh = devices[i]; - for (UINTN j = 0; j < count; j++) - *file_dp = NextDevicePathNode(*file_dp); - - fwup_debug(L"Match up! Returning %s", - DevicePathToStr(*file_dp)); - return EFI_SUCCESS; - } - - path = NextDevicePathNode(path); - } - } - - fwup_warning(L"Failed to find '%s' DevicePath", DevicePathToStr(*file_dp)); - return EFI_UNSUPPORTED; -} - -static EFI_STATUS -fwup_open_file(EFI_DEVICE_PATH *dp, EFI_FILE_HANDLE *fh) -{ - CONST UINTN devpath_max_size = 1024; /* arbitrary limit */ - EFI_DEVICE_PATH *file_dp = dp; - EFI_GUID sfsp = SIMPLE_FILE_SYSTEM_PROTOCOL; - EFI_FILE_HANDLE device; - EFI_FILE_IO_INTERFACE *drive; - EFI_FILE_HANDLE root; - EFI_STATUS rc; - - rc = uefi_call_wrapper(BS->LocateDevicePath, 3, &sfsp, &file_dp, - (EFI_HANDLE *)&device); - if (EFI_ERROR(rc)) { - rc = fwup_search_file(&file_dp, &device); - if (EFI_ERROR(rc)) { - fwup_warning(L"Could not locate device handle: %r", rc); - return rc; - } - } - - if (DevicePathType(file_dp) != MEDIA_DEVICE_PATH || - DevicePathSubType(file_dp) != MEDIA_FILEPATH_DP) { - fwup_warning(L"Could not find appropriate device"); - return EFI_UNSUPPORTED; - } - - UINT16 sz16; - UINTN sz; - CopyMem(&sz16, &file_dp->Length[0], sizeof(sz16)); - sz = sz16; - sz -= 4; - if (sz <= 6 || sz % 2 != 0 || - sz > devpath_max_size * sizeof(CHAR16)) { - fwup_warning(L"Invalid file device path of size %d", sz); - return EFI_INVALID_PARAMETER; - } - - _cleanup_free CHAR16 *filename = fwup_malloc0(sz + sizeof(CHAR16)); - CopyMem(filename, (UINT8 *)file_dp + 4, sz); - - rc = uefi_call_wrapper(BS->HandleProtocol, 3, device, &sfsp, - (VOID **)&drive); - if (EFI_ERROR(rc)) { - fwup_warning(L"Could not open device interface: %r", rc); - return rc; - } - fwup_debug(L"Found device"); - - rc = uefi_call_wrapper(drive->OpenVolume, 2, drive, &root); - if (EFI_ERROR(rc)) { - fwup_warning(L"Could not open volume: %r", rc); - return rc; - } - fwup_debug(L"Found volume"); - - rc = uefi_call_wrapper(root->Open, 5, root, fh, filename, - EFI_FILE_MODE_READ, 0); - if (EFI_ERROR(rc)) { - fwup_warning(L"Could not open file '%s': %r", filename, rc); - return rc; - } - fwup_debug(L"Found file"); - - return EFI_SUCCESS; -} - -static EFI_STATUS -fwup_get_gop_mode(UINT32 *mode, EFI_HANDLE loaded_image) -{ - EFI_HANDLE *handles, gop_handle; - UINTN num_handles; - EFI_STATUS status; - EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; - EFI_GRAPHICS_OUTPUT_PROTOCOL *gop; - VOID *iface; - - status = LibLocateHandle(ByProtocol, &gop_guid, NULL, &num_handles, - &handles); - if (EFI_ERROR(status)) - return status; - - if (handles == NULL || num_handles == 0) - return EFI_UNSUPPORTED; - - for (UINTN i = 0; i < num_handles; i++) { - gop_handle = handles[i]; - - status = uefi_call_wrapper(BS->OpenProtocol, 6, - gop_handle, &gop_guid, &iface, - loaded_image, 0, - EFI_OPEN_PROTOCOL_GET_PROTOCOL); - if (EFI_ERROR(status)) - continue; - - gop = (EFI_GRAPHICS_OUTPUT_PROTOCOL *)iface; - - *mode = gop->Mode->Mode; - return EFI_SUCCESS; - } - - return EFI_UNSUPPORTED; -} - -static inline void -fwup_update_ux_capsule_checksum(UX_CAPSULE_HEADER *payload_hdr) -{ - UINT8 *buf = (UINT8 *)payload_hdr; - UINT8 sum = 0; - - payload_hdr->checksum = 0; - for (UINTN i = 0; i < sizeof(*payload_hdr); i++) - sum = (UINT8) (sum + buf[i]); - payload_hdr->checksum = sum; -} - -static EFI_STATUS -fwup_check_gop_for_ux_capsule(EFI_HANDLE loaded_image, - EFI_CAPSULE_HEADER *capsule) -{ - UX_CAPSULE_HEADER *payload_hdr; - EFI_STATUS rc; - - payload_hdr = (UX_CAPSULE_HEADER *) (((UINT8 *) capsule) + capsule->HeaderSize); - rc = fwup_get_gop_mode(&payload_hdr->mode, loaded_image); - if (EFI_ERROR(rc)) - return EFI_UNSUPPORTED; - - fwup_update_ux_capsule_checksum(payload_hdr); - - return EFI_SUCCESS; -} - -static EFI_STATUS -fwup_add_update_capsule(FWUP_UPDATE_TABLE *update, EFI_CAPSULE_HEADER **capsule_out, - EFI_CAPSULE_BLOCK_DESCRIPTOR *cbd_out, EFI_HANDLE loaded_image) -{ - EFI_STATUS rc; - EFI_FILE_HANDLE fh = NULL; - UINT8 *fbuf = NULL; - UINTN fsize = 0; - EFI_CAPSULE_HEADER *capsule; - - UINTN cbd_len; - EFI_PHYSICAL_ADDRESS cbd_data; - EFI_CAPSULE_HEADER *cap_out; - - rc = fwup_open_file((EFI_DEVICE_PATH *)update->info->dp_buf, &fh); - if (EFI_ERROR(rc)) - return rc; - - rc = fwup_read_file(fh, &fbuf, &fsize); - if (EFI_ERROR(rc)) - return rc; - - uefi_call_wrapper(fh->Close, 1, fh); - - if (fsize < sizeof(EFI_CAPSULE_HEADER)) { - fwup_warning(L"Invalid capsule size %d", fsize); - return EFI_INVALID_PARAMETER; - } - - fwup_debug(L"Read file; %d bytes", fsize); - fwup_debug(L"updates guid: %g", &update->info->guid); - fwup_debug(L"File guid: %g", fbuf); - - cbd_len = fsize; - cbd_data = (EFI_PHYSICAL_ADDRESS)(UINTN)fbuf; - capsule = cap_out = (EFI_CAPSULE_HEADER *)fbuf; - if (cap_out->Flags == 0 && - CompareGuid(&update->info->guid, &ux_capsule_guid) != 0) { -#if defined(__aarch64__) - cap_out->Flags |= update->info->capsule_flags; -#else - cap_out->Flags |= update->info->capsule_flags | - CAPSULE_FLAGS_PERSIST_ACROSS_RESET | - CAPSULE_FLAGS_INITIATE_RESET; -#endif - } - - if (CompareGuid(&update->info->guid, &ux_capsule_guid) == 0) { - fwup_debug(L"Checking GOP for ux capsule"); - rc = fwup_check_gop_for_ux_capsule(loaded_image, capsule); - if (EFI_ERROR(rc)) - return EFI_UNSUPPORTED; - } - - cbd_out->Length = cbd_len; - cbd_out->Union.DataBlock = cbd_data; - *capsule_out = cap_out; - - return EFI_SUCCESS; -} - -static EFI_STATUS -fwup_apply_capsules(EFI_CAPSULE_HEADER **capsules, - EFI_CAPSULE_BLOCK_DESCRIPTOR *cbd, - UINTN num_updates, EFI_RESET_TYPE *reset) -{ - UINT64 max_capsule_size; - EFI_STATUS rc; - - rc = uefi_call_wrapper(RT->QueryCapsuleCapabilities, 4, capsules, - num_updates, &max_capsule_size, reset); - if (EFI_ERROR(rc)) { - fwup_warning(L"Could not query capsule capabilities: %r", rc); - return rc; - } - fwup_debug(L"QueryCapsuleCapabilities: %r max: %ld reset:%d", - rc, max_capsule_size, *reset); - fwup_debug(L"Capsules: %d", num_updates); - - fwup_msleep(1 * SECONDS); - rc = uefi_call_wrapper(RT->UpdateCapsule, 3, capsules, num_updates, - (EFI_PHYSICAL_ADDRESS)(UINTN)cbd); - if (EFI_ERROR(rc)) { - fwup_warning(L"Could not apply capsule update: %r", rc); - return rc; - } - - return EFI_SUCCESS; -} - -static EFI_STATUS -fwup_set_update_statuses(FWUP_UPDATE_TABLE **updates) -{ - EFI_STATUS rc; - for (UINTN i = 0; i < FWUP_NUM_CAPSULE_UPDATES_MAX; i++) { - if (updates[i] == NULL || updates[i]->name == NULL) - break; - rc = fwup_set_variable(updates[i]->name, &fwupdate_guid, - updates[i]->info, updates[i]->size, - updates[i]->attrs); - if (EFI_ERROR(rc)) { - fwup_warning(L"Could not update variable status for '%s': %r", - updates[i]->name, rc); - return rc; - } - } - return EFI_SUCCESS; -} - -EFI_GUID SHIM_LOCK_GUID = - {0x605dab50,0xe046,0x4300,{0xab,0xb6,0x3d,0xd8,0x10,0xdd,0x8b,0x23}}; - -static VOID -__attribute__((__optimize__("0"))) -fwup_debug_hook(VOID) -{ - EFI_GUID guid = SHIM_LOCK_GUID; - UINTN data = 0; - UINTN data_size = 1; - EFI_STATUS efi_status; - UINT32 attrs; - register volatile int x = 0; - extern char _text UNUSED, _data UNUSED; - - /* shim has done whatever is needed to get a debugger attached */ - efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"SHIM_DEBUG", - &guid, &attrs, &data_size, &data); - if (EFI_ERROR(efi_status) || data != 1) { - efi_status = uefi_call_wrapper(RT->GetVariable, 5, - L"FWUPDATE_VERBOSE", - &fwupdate_guid, &attrs, - &data_size, &data); - if (EFI_ERROR(efi_status) || data != 1) - return; - fwup_debug_set_enabled(TRUE); - return; - } - - fwup_debug_set_enabled(TRUE); - if (x) - return; - - x = 1; - fwup_info(L"add-symbol-file "DEBUGDIR - L"fwupdate.efi.debug %p -s .data %p", - &_text, &_data); -} - -EFI_STATUS -efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) -{ - EFI_STATUS rc; - UINTN i, n_updates = 0; - EFI_RESET_TYPE reset_type = EfiResetWarm; - _cleanup_free FWUP_UPDATE_TABLE **updates = NULL; - - InitializeLib(image, systab); - - /* if SHIM_DEBUG is set, fwup_info info for our attached debugger */ - fwup_debug_hook(); - - /* step 1: find and validate update state variables */ - /* XXX TODO: - * 1) survey the reset types first, and separate into groups - * according to them - * 2) if there's more than one, mirror BootCurrent back into BootNext - * so we can do multiple runs - * 3) only select the ones from one type for the first go - */ - updates = fwup_new0(FWUP_UPDATE_TABLE *, FWUP_NUM_CAPSULE_UPDATES_MAX); - if (updates == NULL) - return EFI_OUT_OF_RESOURCES; - rc = fwup_populate_update_table(updates, &n_updates); - if (EFI_ERROR(rc)) { - fwup_warning(L"Could not find updates: %r", rc); - return rc; - } - if (n_updates == 0) { - fwup_warning(L"No updates to process. Called in error?"); - return EFI_INVALID_PARAMETER; - } - - /* step 2: Build our data structure and add the capsules to it */ - _cleanup_free EFI_CAPSULE_HEADER **capsules = NULL; - capsules = fwup_new0(EFI_CAPSULE_HEADER *, n_updates + 1); - EFI_CAPSULE_BLOCK_DESCRIPTOR *cbd_data; - UINTN j = 0; - cbd_data = fwup_malloc_raw(sizeof(EFI_CAPSULE_BLOCK_DESCRIPTOR)*(n_updates+1)); - if (cbd_data == NULL) - return EFI_OUT_OF_RESOURCES; - for (i = 0; i < n_updates; i++) { - fwup_info(L"Adding new capsule"); - rc = fwup_add_update_capsule(updates[i], &capsules[j], &cbd_data[j], image); - if (EFI_ERROR(rc)) { - /* ignore a failing capsule */ - fwup_warning(L"Could not add capsule with guid %g for update: %r", - updates[i]->info->guid, rc); - continue; - } - j++; - } - - if (j == 0) { - fwup_warning(L"Could not build update list: %r\n", rc); - return rc; - } - n_updates = j; - fwup_debug(L"n_updates: %d", n_updates); - - cbd_data[i].Length = 0; - cbd_data[i].Union.ContinuationPointer = 0; - - /* step 3: update the state variables */ - rc = fwup_set_update_statuses(updates); - if (EFI_ERROR(rc)) { - fwup_warning(L"Could not set update status: %r", rc); - return rc; - } - - /* step 4: apply the capsules */ - rc = fwup_apply_capsules(capsules, cbd_data, n_updates, &reset_type); - if (EFI_ERROR(rc)) { - fwup_warning(L"Could not apply capsules: %r", rc); - return rc; - } - - /* step 5: if #4 didn't reboot us, do it manually */ - fwup_info(L"Reset System"); - fwup_msleep(5 * SECONDS); - if (fwup_debug_get_enabled()) - fwup_msleep(30 * SECONDS); - uefi_call_wrapper(RT->ResetSystem, 4, reset_type, EFI_SUCCESS, 0, NULL); - - return EFI_SUCCESS; -} diff -Nru fwupd-1.4.5/plugins/uefi/efi/fwup-debug.c fwupd-1.5.8/plugins/uefi/efi/fwup-debug.c --- fwupd-1.4.5/plugins/uefi/efi/fwup-debug.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/efi/fwup-debug.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2019 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include -#include - -#include "fwup-cleanups.h" -#include "fwup-debug.h" -#include "fwup-efi.h" - -static BOOLEAN debugging = FALSE; - -BOOLEAN -fwup_debug_get_enabled(VOID) -{ - return debugging; -} - -VOID -fwup_debug_set_enabled(BOOLEAN val) -{ - debugging = val; -} - -static VOID -fwupd_debug_efivar_append(CHAR16 *out1) -{ - CHAR16 *name = L"FWUPDATE_DEBUG_LOG"; - UINT32 attrs = EFI_VARIABLE_NON_VOLATILE | - EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS; - static BOOLEAN once = TRUE; - if (once) { - once = FALSE; - fwup_delete_variable(name, &fwupdate_guid); - } else { - attrs |= EFI_VARIABLE_APPEND_WRITE; - } - fwup_set_variable(name, &fwupdate_guid, out1, StrSize(out1) - sizeof(CHAR16), attrs); -} - -VOID -fwup_log(FwupLogLevel level, const char *func, const char *file, const int line, CHAR16 *fmt, ...) -{ - va_list args; - _cleanup_free CHAR16 *tmp = NULL; - - va_start(args, fmt); - tmp = VPoolPrint(fmt, args); - va_end(args); - if (tmp == NULL) { - Print(L"fwupdate: Allocation for debug log failed!\n"); - return; - } - - if (debugging) { - _cleanup_free CHAR16 *out1 = NULL; - out1 = PoolPrint(L"%a:%d:%a(): %s\n", file, line, func, tmp); - if (out1 == NULL) { - Print(L"fwupdate: Allocation for debug log failed!\n"); - return; - } - Print(L"%s", out1); - fwupd_debug_efivar_append(out1); - } else { - switch (level) { - case FWUP_DEBUG_LEVEL_DEBUG: - break; - case FWUP_DEBUG_LEVEL_WARNING: - Print(L"WARNING: %s\n", tmp); - break; - default: - Print(L"%s\n", tmp); - break; - } - } -} diff -Nru fwupd-1.4.5/plugins/uefi/efi/fwup-debug.h fwupd-1.5.8/plugins/uefi/efi/fwup-debug.h --- fwupd-1.4.5/plugins/uefi/efi/fwup-debug.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/efi/fwup-debug.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2015-2016 Peter Jones - * Copyright (C) 2019 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -typedef enum { - FWUP_DEBUG_LEVEL_DEBUG, - FWUP_DEBUG_LEVEL_INFO, - FWUP_DEBUG_LEVEL_WARNING, - FWUP_DEBUG_LEVEL_LAST -} FwupLogLevel; - -VOID fwup_log (FwupLogLevel level, - const char *func, - const char *file, - const int line, - CHAR16 *fmt, - ...); - -BOOLEAN fwup_debug_get_enabled (VOID); -VOID fwup_debug_set_enabled (BOOLEAN val); - -#define fwup_debug(fmt, args...) fwup_log(FWUP_DEBUG_LEVEL_DEBUG, __func__, __FILE__, __LINE__, fmt, ## args ) -#define fwup_info(fmt, args...) fwup_log(FWUP_DEBUG_LEVEL_INFO, __func__, __FILE__, __LINE__, fmt, ## args ) -#define fwup_warning(fmt, args...) fwup_log(FWUP_DEBUG_LEVEL_WARNING, __func__, __FILE__, __LINE__, fmt, ## args ) diff -Nru fwupd-1.4.5/plugins/uefi/efi/fwup-efi.c fwupd-1.5.8/plugins/uefi/efi/fwup-efi.c --- fwupd-1.4.5/plugins/uefi/efi/fwup-efi.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/efi/fwup-efi.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2019 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include -#include - -#include "fwup-cleanups.h" -#include "fwup-common.h" -#include "fwup-debug.h" -#include "fwup-efi.h" - -EFI_STATUS -fwup_delete_variable(CHAR16 *name, EFI_GUID *guid) -{ - EFI_STATUS rc; - UINT32 attrs = 0; - - /* get the attrs so we can delete it */ - rc = uefi_call_wrapper(RT->GetVariable, 5, name, guid, &attrs, NULL, NULL); - if (EFI_ERROR(rc)) { - if (rc == EFI_NOT_FOUND) { - fwup_debug(L"Not deleting variable '%s' as not found", name); - return EFI_SUCCESS; - } - fwup_debug(L"Could not get variable '%s' for delete: %r", name, rc); - return rc; - } - return uefi_call_wrapper(RT->SetVariable, 5, name, guid, attrs, 0, NULL); -} - -EFI_STATUS -fwup_set_variable(CHAR16 *name, EFI_GUID *guid, VOID *data, UINTN size, UINT32 attrs) -{ - return uefi_call_wrapper(RT->SetVariable, 5, name, guid, attrs, size, data); -} - -EFI_STATUS -fwup_get_variable(CHAR16 *name, EFI_GUID *guid, VOID **buf_out, UINTN *buf_size_out, UINT32 *attrs_out) -{ - EFI_STATUS rc; - UINTN size = 0; - UINT32 attrs; - _cleanup_free VOID *buf = NULL; - - rc = uefi_call_wrapper(RT->GetVariable, 5, name, guid, &attrs, &size, NULL); - if (EFI_ERROR(rc)) { - if (rc == EFI_BUFFER_TOO_SMALL) { - buf = fwup_malloc(size); - if (buf == NULL) - return EFI_OUT_OF_RESOURCES; - } else if (rc != EFI_NOT_FOUND) { - fwup_debug(L"Could not get variable '%s': %r", name, rc); - return rc; - } - } else { - fwup_debug(L"GetVariable(%s) succeeded with size=0", name); - return EFI_INVALID_PARAMETER; - } - rc = uefi_call_wrapper(RT->GetVariable, 5, name, guid, &attrs, &size, buf); - if (EFI_ERROR(rc)) { - fwup_warning(L"Could not get variable '%s': %r", name, rc); - return rc; - } - *buf_out = _steal_pointer(&buf); - *buf_size_out = size; - *attrs_out = attrs; - return EFI_SUCCESS; -} diff -Nru fwupd-1.4.5/plugins/uefi/efi/fwup-efi.h fwupd-1.5.8/plugins/uefi/efi/fwup-efi.h --- fwupd-1.4.5/plugins/uefi/efi/fwup-efi.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/efi/fwup-efi.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2015-2017 Peter Jones - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#define FWUPDATE_ATTEMPT_UPDATE 0x00000001 -#define FWUPDATE_ATTEMPTED 0x00000002 - -#define UPDATE_INFO_VERSION 7 - -static __attribute__((__unused__)) EFI_GUID empty_guid = - {0x0,0x0,0x0,{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}}; -static __attribute__((__unused__))EFI_GUID fwupdate_guid = - {0x0abba7dc,0xe516,0x4167,{0xbb,0xf5,0x4d,0x9d,0x1c,0x73,0x94,0x16}}; -static __attribute__((__unused__))EFI_GUID ux_capsule_guid = - {0x3b8c8162,0x188c,0x46a4,{0xae,0xc9,0xbe,0x43,0xf1,0xd6,0x56,0x97}}; -static __attribute__((__unused__))EFI_GUID global_variable_guid = EFI_GLOBAL_VARIABLE; - -typedef struct { - UINT8 version; - UINT8 checksum; - UINT8 image_type; - UINT8 reserved; - UINT32 mode; - UINT32 x_offset; - UINT32 y_offset; -} __attribute__((__packed__)) UX_CAPSULE_HEADER; - -typedef struct { - UINT32 update_info_version; - - /* stuff we need to apply an update */ - EFI_GUID guid; - UINT32 capsule_flags; - UINT64 hw_inst; - - EFI_TIME time_attempted; - - /* our metadata */ - UINT32 status; - - /* variadic device path */ - union { - EFI_DEVICE_PATH dp; - UINT8 dp_buf[0]; - }; -} __attribute__((__packed__)) FWUP_UPDATE_INFO; - -typedef struct { - UINT32 attributes; - UINT16 file_path_list_length; - CHAR16 *description; -} __attribute__((__packed__)) EFI_LOAD_OPTION; - -EFI_STATUS fwup_delete_variable (CHAR16 *name, - EFI_GUID *guid); -EFI_STATUS fwup_set_variable (CHAR16 *name, - EFI_GUID *guid, - VOID *data, - UINTN size, - UINT32 attrs); -EFI_STATUS fwup_get_variable (CHAR16 *name, - EFI_GUID *guid, - VOID **buf_out, - UINTN *buf_size_out, - UINT32 *attrs_out); diff -Nru fwupd-1.4.5/plugins/uefi/efi/generate_binary.sh fwupd-1.5.8/plugins/uefi/efi/generate_binary.sh --- fwupd-1.4.5/plugins/uefi/efi/generate_binary.sh 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/efi/generate_binary.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -#!/bin/sh -output=$2 -objcopy_cmd=$(command -v objcopy) -genpeimg_cmd=$(command -v genpeimg) - -"$objcopy_cmd" -j .text \ - -j .sdata \ - -j .data \ - -j .dynamic \ - -j .dynsym \ - -j '.rel*' \ - "$@" - -if [ -n "${genpeimg_cmd}" ]; then - $genpeimg_cmd -d \ - +d \ - -d \ - +n \ - -d \ - +s \ - "$output" -fi diff -Nru fwupd-1.4.5/plugins/uefi/efi/meson.build fwupd-1.5.8/plugins/uefi/efi/meson.build --- fwupd-1.4.5/plugins/uefi/efi/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/efi/meson.build 1970-01-01 00:00:00.000000000 +0000 @@ -1,182 +0,0 @@ -efi_cc = get_option('efi-cc') -efi_ld = get_option('efi-ld') -efi_ldsdir = get_option('efi-ldsdir') -efi_incdir = get_option('efi-includedir') - -gnu_efi_path_arch = '' -foreach name : [gnu_efi_arch, EFI_MACHINE_TYPE_NAME] - if (gnu_efi_path_arch == '' and name != '' and - cc.has_header('@0@/@1@/efibind.h'.format(efi_incdir, name))) - gnu_efi_path_arch = name - endif -endforeach - -if gnu_efi_path_arch != '' and EFI_MACHINE_TYPE_NAME == '' - error('gnu-efi is available, but EFI_MACHINE_TYPE_NAME is unknown') -endif - -efi_libdir = get_option('efi-libdir') -if efi_libdir == '' - cmd = 'cd /usr/lib/$(@0@ -print-multi-os-directory) && pwd'.format(efi_cc) - ret = run_command('sh', '-c', cmd) - if ret.returncode() == 0 - efi_libdir = ret.stdout().strip() - endif -endif - -have_gnu_efi = gnu_efi_path_arch != '' and efi_libdir != '' - -if not have_gnu_efi - error('gnu-efi support requested, but headers were not found') -endif - -arch_lds = 'efi.lds' -arch_crt = 'crt0.o' -if efi_ldsdir == '' - efi_ldsdir = join_paths(efi_libdir, 'gnuefi', gnu_efi_path_arch) - cmd = run_command('test', '-f', join_paths(efi_ldsdir, arch_lds)) - if cmd.returncode() != 0 - arch_lds = 'elf_@0@_efi.lds'.format(gnu_efi_path_arch) - arch_crt = 'crt0-efi-@0@.o'.format(gnu_efi_path_arch) - efi_ldsdir = join_paths(efi_libdir, 'gnuefi') - cmd = run_command('test', '-f', join_paths(efi_ldsdir, arch_lds)) - endif - if cmd.returncode() != 0 - efi_ldsdir = efi_libdir - cmd = run_command('test', '-f', join_paths(efi_ldsdir, arch_lds)) - if cmd.returncode() != 0 - error('Cannot find @0@'.format(arch_lds)) - endif - endif -else - cmd = run_command('test', '-f', join_paths(efi_ldsdir, arch_lds)) - if cmd.returncode() != 0 - arch_lds = 'elf_@0@_efi.lds'.format(gnu_efi_path_arch) - arch_crt = 'crt0-efi-@0@.o'.format(gnu_efi_path_arch) - cmd = run_command('test', '-f', join_paths(efi_ldsdir, arch_lds)) - endif - if cmd.returncode() != 0 - error('Cannot find @0@'.format(arch_lds)) - endif -endif - -message('efi-libdir: "@0@"'.format(efi_libdir)) -message('efi-ldsdir: "@0@"'.format(efi_ldsdir)) -message('efi-includedir: "@0@"'.format(efi_incdir)) - -debugdir = join_paths (libdir, 'debug') -compile_args = ['-Og', - '-g3', - '--param=ssp-buffer-size=4', - '-fexceptions', - '-Wall', - '-Wextra', - '-Wvla', - '-std=gnu11', - '-fpic', - '-fshort-wchar', - '-ffreestanding', - '-fno-strict-aliasing', - '-fno-stack-protector', - '-fno-stack-check', - '-fno-merge-constants', - '-Wsign-compare', - '-Wno-missing-field-initializers', - '-Wno-address-of-packed-member', - '-grecord-gcc-switches', - '-DDEBUGDIR="@0@"'.format(debugdir), - '-isystem', efi_incdir, - '-isystem', join_paths(efi_incdir, gnu_efi_path_arch)] -if get_option('werror') - compile_args += '-Werror' -endif -if efi_arch == 'x86_64' - compile_args += ['-mno-red-zone', - '-mno-sse', - '-mno-mmx', - '-DEFI_FUNCTION_WRAPPER', - '-DGNU_EFI_USE_MS_ABI'] -elif efi_arch == 'ia32' - compile_args += ['-mno-sse', - '-mno-mmx', - '-mno-red-zone', - '-m32'] -# no special cases for aarch64 or arm -endif - -efi_ldflags = ['-T', - join_paths(efi_ldsdir, arch_lds), - '-shared', - '-Bsymbolic', - '-nostdlib', - '-znocombreloc', - '-L', efi_ldsdir, - '-L', efi_libdir, - join_paths(efi_ldsdir, arch_crt)] -if efi_arch == 'aarch64' or efi_arch == 'arm' - # Aarch64 and ARM32 don't have an EFI capable objcopy. Use 'binary' - # instead, and add required symbols manually. - efi_ldflags += ['--defsym=EFI_SUBSYSTEM=0xa'] - efi_format = ['-O', 'binary'] -else - efi_format = ['--target=efi-app-@0@'.format(gnu_efi_arch)] -endif - -libgcc_file_name = run_command(efi_cc, '-print-libgcc-file-name').stdout().strip() -efi_name = 'fwupd@0@.efi'.format(EFI_MACHINE_TYPE_NAME) - -o_file1 = custom_target('fwupdate.o', - input : 'fwupdate.c', - output : 'fwupdate.o', - command : [efi_cc, '-c', '@INPUT@', '-o', '@OUTPUT@'] - + compile_args) -o_file2 = custom_target('fwup-debug.o', - input : 'fwup-debug.c', - output : 'fwup-debug.o', - command : [efi_cc, '-c', '@INPUT@', '-o', '@OUTPUT@'] - + compile_args) -o_file3 = custom_target('fwup-efi.o', - input : 'fwup-efi.c', - output : 'fwup-efi.o', - command : [efi_cc, '-c', '@INPUT@', '-o', '@OUTPUT@'] - + compile_args) -o_file4 = custom_target('fwup-common.o', - input : 'fwup-common.c', - output : 'fwup-common.o', - command : [efi_cc, '-c', '@INPUT@', '-o', '@OUTPUT@'] - + compile_args) - -so = custom_target('fwup.so', - input : [o_file1, o_file2, o_file3, o_file4], - output : 'fwup.so', - command : [efi_ld, '-o', '@OUTPUT@'] + - efi_ldflags + ['@INPUT@'] + - ['-lefi', '-lgnuefi', libgcc_file_name]) - -build_tool = join_paths(meson.source_root(), 'plugins', 'uefi', 'efi', 'generate_binary.sh') -app = custom_target(efi_name, - input : so, - output : efi_name, - command : [build_tool, '@INPUT@', '@OUTPUT@', efi_format], - install : true, - install_dir : efi_app_location) - -dbg = custom_target('efi_debug', - input : so, - output : efi_name + '.debug', - command : [objcopy, - '-j', '.text', - '-j', '.sdata', - '-j', '.data', - '-j', '.dynamic', - '-j', '.dynsym', - '-j', '.rel*', - '-j', '.rela*', - '-j', '.reloc', - '-j', '.eh_frame', - '-j', '.debug*', - '-j', '.note.gnu.build-id'] - + efi_format + - ['@INPUT@', '@OUTPUT@'], - install : false, - install_dir : debugdir) diff -Nru fwupd-1.4.5/plugins/uefi/fu-plugin-uefi.c fwupd-1.5.8/plugins/uefi/fu-plugin-uefi.c --- fwupd-1.4.5/plugins/uefi/fu-plugin-uefi.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/fu-plugin-uefi.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,818 +0,0 @@ -/* - * Copyright (C) 2016-2018 Richard Hughes - * Copyright (C) 2015-2017 Peter Jones - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include -#include -#include - -#include "fu-device-metadata.h" -#include "fu-plugin-vfuncs.h" -#include "fu-hash.h" - -#include "fu-uefi-bgrt.h" -#include "fu-uefi-common.h" -#include "fu-uefi-device.h" -#include "fu-efivar.h" - -#ifndef HAVE_GIO_2_55_0 -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-function" -G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUnixMountEntry, g_unix_mount_free) -#pragma clang diagnostic pop -#endif - -struct FuPluginData { - FuUefiBgrt *bgrt; -}; - -void -fu_plugin_init (FuPlugin *plugin) -{ - FuPluginData *data = fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); - data->bgrt = fu_uefi_bgrt_new (); - fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_AFTER, "upower"); - fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_METADATA_SOURCE, "tpm_eventlog"); - fu_plugin_add_compile_version (plugin, "com.redhat.efivar", EFIVAR_LIBRARY_VERSION); - fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); -} - -void -fu_plugin_destroy (FuPlugin *plugin) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - g_object_unref (data->bgrt); -} - -gboolean -fu_plugin_clear_results (FuPlugin *plugin, FuDevice *device, GError **error) -{ - FuUefiDevice *device_uefi = FU_UEFI_DEVICE (device); - return fu_uefi_device_clear_status (device_uefi, error); -} - -gboolean -fu_plugin_get_results (FuPlugin *plugin, FuDevice *device, GError **error) -{ - FuUefiDevice *device_uefi = FU_UEFI_DEVICE (device); - FuUefiDeviceStatus status = fu_uefi_device_get_status (device_uefi); - const gchar *tmp; - g_autofree gchar *err_msg = NULL; - g_autofree gchar *version_str = NULL; - - /* trivial case */ - if (status == FU_UEFI_DEVICE_STATUS_SUCCESS) { - fu_device_set_update_state (device, FWUPD_UPDATE_STATE_SUCCESS); - return TRUE; - } - - /* something went wrong */ - if (status == FU_UEFI_DEVICE_STATUS_ERROR_PWR_EVT_AC || - status == FU_UEFI_DEVICE_STATUS_ERROR_PWR_EVT_BATT) { - fu_device_set_update_state (device, FWUPD_UPDATE_STATE_FAILED_TRANSIENT); - } else { - fu_device_set_update_state (device, FWUPD_UPDATE_STATE_FAILED); - } - version_str = g_strdup_printf ("%u", fu_uefi_device_get_version_error (device_uefi)); - tmp = fu_uefi_device_status_to_string (status); - if (tmp == NULL) { - err_msg = g_strdup_printf ("failed to update to %s", - version_str); - } else { - err_msg = g_strdup_printf ("failed to update to %s: %s", - version_str, tmp); - } - fu_device_set_update_error (device, err_msg); - return TRUE; -} - -static GBytes * -fu_plugin_uefi_get_splash_data (guint width, guint height, GError **error) -{ - const gchar * const *langs = g_get_language_names (); - const gchar *localedir = FWUPD_LOCALEDIR; - const gsize chunk_size = 1024 * 1024; - gsize buf_idx = 0; - gsize buf_sz = chunk_size; - gssize len; - g_autofree gchar *basename = NULL; - g_autofree guint8 *buf = NULL; - g_autoptr(GBytes) compressed_data = NULL; - g_autoptr(GConverter) conv = NULL; - g_autoptr(GInputStream) stream_compressed = NULL; - g_autoptr(GInputStream) stream_raw = NULL; - - /* ensure this is sane */ - if (!g_str_has_prefix (localedir, "/")) - localedir = "/usr/share/locale"; - - /* find the closest locale match, falling back to `en` and `C` */ - basename = g_strdup_printf ("fwupd-%u-%u.bmp.gz", width, height); - for (guint i = 0; langs[i] != NULL; i++) { - g_autofree gchar *fn = NULL; - if (g_str_has_suffix (langs[i], ".UTF-8")) - continue; - fn = g_build_filename (localedir, langs[i], - "LC_IMAGES", basename, NULL); - if (g_file_test (fn, G_FILE_TEST_EXISTS)) { - compressed_data = fu_common_get_contents_bytes (fn, error); - if (compressed_data == NULL) - return NULL; - break; - } - g_debug ("no %s found", fn); - } - - /* we found nothing */ - if (compressed_data == NULL) { - g_autofree gchar *tmp = g_strjoinv (",", (gchar **) langs); - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "failed to get splash file for %s in %s", - tmp, localedir); - return NULL; - } - - /* decompress data */ - stream_compressed = g_memory_input_stream_new_from_bytes (compressed_data); - conv = G_CONVERTER (g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP)); - stream_raw = g_converter_input_stream_new (stream_compressed, conv); - buf = g_malloc0 (buf_sz); - while ((len = g_input_stream_read (stream_raw, - buf + buf_idx, - buf_sz - buf_idx, - NULL, error)) > 0) { - buf_idx += len; - if (buf_sz - buf_idx < chunk_size) { - buf_sz += chunk_size; - buf = g_realloc (buf, buf_sz); - } - } - if (len < 0) { - g_prefix_error (error, "failed to decompress file: "); - return NULL; - } - g_debug ("decompressed image to %" G_GSIZE_FORMAT "kb", buf_idx / 1024); - return g_bytes_new_take (g_steal_pointer (&buf), buf_idx); -} - -static guint8 -fu_plugin_uefi_calc_checksum (const guint8 *buf, gsize sz) -{ - guint8 csum = 0; - for (gsize i = 0; i < sz; i++) - csum += buf[i]; - return csum; -} - -static gboolean -fu_plugin_uefi_write_splash_data (FuPlugin *plugin, - FuDevice *device, - GBytes *blob, - GError **error) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - const gchar *esp_path = fu_device_get_metadata (device, "EspPath"); - guint32 screen_x, screen_y; - gsize buf_size = g_bytes_get_size (blob); - gssize size; - guint32 height, width; - guint8 csum = 0; - efi_ux_capsule_header_t header = { 0 }; - efi_capsule_header_t capsule_header = { - .flags = EFI_CAPSULE_HEADER_FLAGS_PERSIST_ACROSS_RESET, - .guid = efi_guid_ux_capsule, - .header_size = sizeof(efi_capsule_header_t), - .capsule_image_size = 0 - }; - g_autofree gchar *fn = NULL; - g_autofree gchar *directory = NULL; - g_autofree gchar *basename = NULL; - g_autoptr(GFile) ofile = NULL; - g_autoptr(GOutputStream) ostream = NULL; - - /* get screen dimensions */ - if (!fu_uefi_get_framebuffer_size (&screen_x, &screen_y, error)) - return FALSE; - if (!fu_uefi_get_bitmap_size ((const guint8 *) g_bytes_get_data (blob, NULL), - buf_size, &width, &height, error)) { - g_prefix_error (error, "splash invalid: "); - return FALSE; - } - - /* save to a predicatable filename */ - directory = fu_uefi_get_esp_path_for_os (esp_path); - basename = g_strdup_printf ("fwupd-%s.cap", FU_EFIVAR_GUID_UX_CAPSULE); - fn = g_build_filename (directory, "fw", basename, NULL); - if (!fu_common_mkdir_parent (fn, error)) - return FALSE; - ofile = g_file_new_for_path (fn); - ostream = G_OUTPUT_STREAM (g_file_replace (ofile, NULL, FALSE, - G_FILE_CREATE_NONE, NULL, error)); - if (ostream == NULL) - return FALSE; - - capsule_header.capsule_image_size = - g_bytes_get_size (blob) + - sizeof(efi_capsule_header_t) + - sizeof(efi_ux_capsule_header_t); - - header.version = 1; - header.image_type = 0; - header.reserved = 0; - header.x_offset = (screen_x / 2) - (width / 2); - header.y_offset = fu_uefi_bgrt_get_yoffset (data->bgrt) + - fu_uefi_bgrt_get_height (data->bgrt); - - /* header, payload and image has to add to zero */ - csum += fu_plugin_uefi_calc_checksum ((guint8 *) &capsule_header, - sizeof(capsule_header)); - csum += fu_plugin_uefi_calc_checksum ((guint8 *) &header, - sizeof(header)); - csum += fu_plugin_uefi_calc_checksum (g_bytes_get_data (blob, NULL), - g_bytes_get_size (blob)); - header.checksum = 0x100 - csum; - - /* write capsule file */ - size = g_output_stream_write (ostream, &capsule_header, - capsule_header.header_size, NULL, error); - if (size < 0) - return FALSE; - size = g_output_stream_write (ostream, &header, sizeof(header), NULL, error); - if (size < 0) - return FALSE; - size = g_output_stream_write_bytes (ostream, blob, NULL, error); - if (size < 0) - return FALSE; - - /* write display capsule location as UPDATE_INFO */ - if (!fu_uefi_device_write_update_info (FU_UEFI_DEVICE (device), fn, - "fwupd-ux-capsule", - &efi_guid_ux_capsule, error)) - return FALSE; - - /* success */ - return TRUE; -} - -static gboolean -fu_plugin_uefi_update_splash (FuPlugin *plugin, FuDevice *device, GError **error) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - guint best_idx = G_MAXUINT; - guint32 lowest_border_pixels = G_MAXUINT; - guint32 screen_height = 768; - guint32 screen_width = 1024; - g_autoptr(GBytes) image_bmp = NULL; - - struct { - guint32 width; - guint32 height; - } sizes[] = { - { 640, 480 }, /* matching the sizes in po/make-images */ - { 800, 600 }, - { 1024, 768 }, - { 1920, 1080 }, - { 3840, 2160 }, - { 5120, 2880 }, - { 5688, 3200 }, - { 7680, 4320 }, - { 0, 0 } - }; - - /* no UX capsule support, so deleting var if it exists */ - if (fu_device_has_custom_flag (device, "no-ux-capsule")) { - g_debug ("not providing UX capsule"); - return fu_efivar_delete (FU_EFIVAR_GUID_FWUPDATE, - "fwupd-ux-capsule", error); - } - - /* get the boot graphics resource table data */ - if (!fu_uefi_bgrt_get_supported (data->bgrt)) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "BGRT is not supported"); - return FALSE; - } - if (!fu_uefi_get_framebuffer_size (&screen_width, &screen_height, error)) - return FALSE; - g_debug ("framebuffer size %" G_GUINT32_FORMAT " x%" G_GUINT32_FORMAT, - screen_width, screen_height); - - /* find the 'best sized' pre-generated image */ - for (guint i = 0; sizes[i].width != 0; i++) { - guint32 border_pixels; - - /* disregard any images that are bigger than the screen */ - if (sizes[i].width > screen_width) - continue; - if (sizes[i].height > screen_height) - continue; - - /* is this the best fit for the display */ - border_pixels = (screen_width * screen_height) - - (sizes[i].width * sizes[i].height); - if (border_pixels < lowest_border_pixels) { - lowest_border_pixels = border_pixels; - best_idx = i; - } - } - if (best_idx == G_MAXUINT) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "failed to find a suitable image to use"); - return FALSE; - } - - /* get the raw data */ - image_bmp = fu_plugin_uefi_get_splash_data (sizes[best_idx].width, - sizes[best_idx].height, - error); - if (image_bmp == NULL) - return FALSE; - - /* perform the upload */ - return fu_plugin_uefi_write_splash_data (plugin, device, image_bmp, error); -} - -gboolean -fu_plugin_update (FuPlugin *plugin, - FuDevice *device, - GBytes *blob_fw, - FwupdInstallFlags flags, - GError **error) -{ - const gchar *str; - guint32 flashes_left; - g_autoptr(GError) error_splash = NULL; - - /* test the flash counter */ - flashes_left = fu_device_get_flashes_left (device); - if (flashes_left > 0) { - g_debug ("%s has %" G_GUINT32_FORMAT " flashes left", - fu_device_get_name (device), - flashes_left); - if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0 && flashes_left <= 2) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "%s only has %" G_GUINT32_FORMAT " flashes left -- " - "see https://github.com/fwupd/fwupd/wiki/Dell-TPM:-flashes-left for more information.", - fu_device_get_name (device), flashes_left); - return FALSE; - } - } - - /* TRANSLATORS: this is shown when updating the firmware after the reboot */ - str = _("Installing firmware update…"); - g_assert (str != NULL); - - /* perform the update */ - g_debug ("Performing UEFI capsule update"); - fu_device_set_status (device, FWUPD_STATUS_SCHEDULING); - if (!fu_plugin_uefi_update_splash (plugin, device, &error_splash)) { - g_debug ("failed to upload UEFI UX capsule text: %s", - error_splash->message); - } - - if (!fu_device_write_firmware (device, blob_fw, flags, error)) - return FALSE; - - /* record if we had an invalid header during update */ - str = fu_uefi_missing_capsule_header (device) ? "True" : "False"; - fu_plugin_add_report_metadata (plugin, "MissingCapsuleHeader", str); - - /* where the ESP was mounted during installation */ - str = fu_device_get_metadata (device, "EspPath"); - fu_plugin_add_report_metadata (plugin, "ESPMountPoint", str); - - return TRUE; -} - -static gboolean -fu_plugin_uefi_load_config (FuPlugin *plugin, FuDevice *device, GError **error) -{ - gboolean disable_shim; - guint64 sz_reqd = FU_UEFI_COMMON_REQUIRED_ESP_FREE_SPACE; - g_autofree gchar *require_esp_free_space = NULL; - g_autofree gchar *require_shim_for_sb = NULL; - g_autofree gchar *esp_path = NULL; - - /* parse free space needed for ESP */ - require_esp_free_space = fu_plugin_get_config_value (plugin, "RequireESPFreeSpace"); - if (require_esp_free_space != NULL) - sz_reqd = fu_common_strtoull (require_esp_free_space); - fu_device_set_metadata_integer (device, "RequireESPFreeSpace", sz_reqd); - - /* shim used for SB or not? */ - disable_shim = fu_plugin_get_config_value_boolean (plugin, "DisableShimForSecureBoot"); - fu_device_set_metadata_boolean (device, - "RequireShimForSecureBoot", - !disable_shim); - - /* load ESP from file */ - esp_path = fu_plugin_get_config_value (plugin, "OverrideESPMountPoint"); - if (esp_path != NULL) { - g_autoptr(GError) error_local = NULL; - if (!fu_uefi_check_esp_path (esp_path, &error_local)) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_FILENAME, - "invalid OverrideESPMountPoint=%s specified in config: %s", - esp_path, error_local->message); - return FALSE; - } - fu_device_set_metadata (device, "EspPath", esp_path); - } - - /* success */ - return TRUE; -} - -static void -fu_plugin_uefi_register_proxy_device (FuPlugin *plugin, FuDevice *device) -{ - g_autoptr(FuUefiDevice) dev = fu_uefi_device_new_from_dev (device); - g_autoptr(GError) error_local = NULL; - - /* load all configuration variables */ - if (!fu_plugin_uefi_load_config (plugin, FU_DEVICE (dev), &error_local)) - g_warning ("%s", error_local->message); - - fu_plugin_device_add (plugin, FU_DEVICE (dev)); -} - -void -fu_plugin_device_registered (FuPlugin *plugin, FuDevice *device) -{ - if (fu_device_get_metadata (device, FU_DEVICE_METADATA_UEFI_DEVICE_KIND) != NULL) { - if (fu_device_get_guid_default (device) == NULL) { - g_autofree gchar *dbg = fu_device_to_string (device); - g_warning ("cannot create proxy device as no GUID: %s", dbg); - return; - } - fu_plugin_uefi_register_proxy_device (plugin, device); - } -} - -static const gchar * -fu_plugin_uefi_uefi_type_to_string (FuUefiDeviceKind device_kind) -{ - if (device_kind == FU_UEFI_DEVICE_KIND_UNKNOWN) - return "Unknown Firmware"; - if (device_kind == FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE) - return "System Firmware"; - if (device_kind == FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE) - return "Device Firmware"; - if (device_kind == FU_UEFI_DEVICE_KIND_UEFI_DRIVER) - return "UEFI Driver"; - if (device_kind == FU_UEFI_DEVICE_KIND_FMP) - return "Firmware Management Protocol"; - return NULL; -} - -static gchar * -fu_plugin_uefi_get_name_for_type (FuPlugin *plugin, FuUefiDeviceKind device_kind) -{ - GString *display_name; - - /* set Display Name prefix for capsules that are not PCI cards */ - display_name = g_string_new (fu_plugin_uefi_uefi_type_to_string (device_kind)); - if (device_kind == FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE) - g_string_prepend (display_name, "UEFI "); - return g_string_free (display_name, FALSE); -} - -static gboolean -fu_plugin_uefi_coldplug_device (FuPlugin *plugin, FuUefiDevice *dev, GError **error) -{ - FuUefiDeviceKind device_kind; - - /* probe to get add GUIDs (and hence any quirk fixups) */ - if (!fu_device_probe (FU_DEVICE (dev), error)) - return FALSE; - - /* if not already set by quirks */ - if (fu_device_get_custom_flags (FU_DEVICE (dev)) == NULL) { - /* for all Lenovo hardware */ - if (fu_plugin_check_hwid (plugin, "6de5d951-d755-576b-bd09-c5cf66b27234")) { - fu_device_set_custom_flags (FU_DEVICE (dev), "use-legacy-bootmgr-desc"); - fu_plugin_add_report_metadata (plugin, "BootMgrDesc", "legacy"); - } - } - - /* set fallback name if nothing else is set */ - device_kind = fu_uefi_device_get_kind (dev); - if (fu_device_get_name (FU_DEVICE (dev)) == NULL) { - g_autofree gchar *name = NULL; - name = fu_plugin_uefi_get_name_for_type (plugin, device_kind); - if (name != NULL) - fu_device_set_name (FU_DEVICE (dev), name); - if (device_kind != FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE) - fu_device_add_flag (FU_DEVICE (dev), FWUPD_DEVICE_FLAG_MD_SET_NAME_CATEGORY); - } - /* set fallback vendor if nothing else is set */ - if (fu_device_get_vendor (FU_DEVICE (dev)) == NULL && - device_kind == FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE) { - const gchar *vendor = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_MANUFACTURER); - if (vendor != NULL) - fu_device_set_vendor (FU_DEVICE (dev), vendor); - } - - /* set vendor ID as the BIOS vendor */ - if (device_kind != FU_UEFI_DEVICE_KIND_FMP) { - const gchar *dmi_vendor; - dmi_vendor = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_BIOS_VENDOR); - if (dmi_vendor != NULL) { - g_autofree gchar *vendor_id = g_strdup_printf ("DMI:%s", dmi_vendor); - fu_device_set_vendor_id (FU_DEVICE (dev), vendor_id); - } - } - - /* success */ - return TRUE; -} - -static void -fu_plugin_uefi_test_secure_boot (FuPlugin *plugin) -{ - const gchar *result_str = "Disabled"; - if (fu_efivar_secure_boot_enabled ()) - result_str = "Enabled"; - g_debug ("SecureBoot is: %s", result_str); - fu_plugin_add_report_metadata (plugin, "SecureBoot", result_str); -} - -static gboolean -fu_plugin_uefi_smbios_enabled (FuPlugin *plugin, GError **error) -{ - const guint8 *data; - gsize sz; - g_autoptr(GBytes) bios_information = fu_plugin_get_smbios_data (plugin, 0); - if (bios_information == NULL) { - const gchar *tmp = g_getenv ("FWUPD_DELL_FAKE_SMBIOS"); - if (tmp != NULL) - return TRUE; - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "SMBIOS not supported"); - return FALSE; - } - data = g_bytes_get_data (bios_information, &sz); - if (sz < 0x13) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "offset bigger than size %" G_GSIZE_FORMAT, sz); - return FALSE; - } - if (data[1] < 0x13) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "SMBIOS 2.3 not supported"); - return FALSE; - } - if (!(data[0x13] & (1 << 3))) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "System does not support UEFI mode"); - return FALSE; - } - return TRUE; -} - -gboolean -fu_plugin_startup (FuPlugin *plugin, GError **error) -{ - g_autoptr(GError) error_local = NULL; - - /* some platforms have broken SMBIOS data */ - if (fu_plugin_has_custom_flag (plugin, "uefi-force-enable")) - return TRUE; - - /* check SMBIOS for 'UEFI Specification is supported' */ - if (!fu_plugin_uefi_smbios_enabled (plugin, &error_local)) { - g_autofree gchar *fw = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); - g_autofree gchar *fn = g_build_filename (fw, "efi", NULL); - if (g_file_test (fn, G_FILE_TEST_EXISTS)) { - g_warning ("SMBIOS BIOS Characteristics Extension Byte 2 is invalid -- " - "UEFI Specification is unsupported, but %s exists: %s", - fn, error_local->message); - return TRUE; - } - g_propagate_error (error, g_steal_pointer (&error_local)); - return FALSE; - } - - /* test for invalid ESP in coldplug, and set the update-error rather - * than showing no output if the plugin had self-disabled here */ - return TRUE; -} - -static gboolean -fu_plugin_uefi_ensure_efivarfs_rw (GError **error) -{ - g_autofree gchar *sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); - g_autofree gchar *sysfsefivardir = g_build_filename (sysfsfwdir, "efi", "efivars", NULL); - g_autoptr(GUnixMountEntry) mount = g_unix_mount_at (sysfsefivardir, NULL); - - if (mount == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "%s was not mounted", sysfsefivardir); - return FALSE; - } - if (g_unix_mount_is_readonly (mount)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "%s is read only", sysfsefivardir); - return FALSE; - } - - return TRUE; -} - -gboolean -fu_plugin_unlock (FuPlugin *plugin, FuDevice *device, GError **error) -{ - FuUefiDevice *device_uefi = FU_UEFI_DEVICE (device); - FuDevice *device_alt = NULL; - FwupdDeviceFlags device_flags_alt = 0; - guint flashes_left = 0; - guint flashes_left_alt = 0; - - if (fu_uefi_device_get_kind (device_uefi) != - FU_UEFI_DEVICE_KIND_DELL_TPM_FIRMWARE) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Unable to unlock %s", - fu_device_get_name (device)); - return FALSE; - } - - /* for unlocking TPM1.2 <-> TPM2.0 switching */ - g_debug ("Unlocking upgrades for: %s (%s)", fu_device_get_name (device), - fu_device_get_id (device)); - device_alt = fu_device_get_alternate (device); - if (device_alt == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "No alternate device for %s", - fu_device_get_name (device)); - return FALSE; - } - g_debug ("Preventing upgrades for: %s (%s)", fu_device_get_name (device_alt), - fu_device_get_id (device_alt)); - - flashes_left = fu_device_get_flashes_left (device); - flashes_left_alt = fu_device_get_flashes_left (device_alt); - if (flashes_left == 0) { - /* flashes left == 0 on both means no flashes left */ - if (flashes_left_alt == 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "ERROR: %s has no flashes left.", - fu_device_get_name (device)); - /* flashes left == 0 on just unlocking device is ownership */ - } else { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "ERROR: %s is currently OWNED. " - "Ownership must be removed to switch modes.", - fu_device_get_name (device_alt)); - } - return FALSE; - } - - /* clone the info from real device but prevent it from being flashed */ - device_flags_alt = fu_device_get_flags (device_alt); - fu_device_set_flags (device, device_flags_alt); - fu_device_set_flags (device_alt, device_flags_alt & ~FWUPD_DEVICE_FLAG_UPDATABLE); - - /* make sure that this unlocked device can be updated */ - fu_device_set_version_format (device, FWUPD_VERSION_FORMAT_QUAD); - fu_device_set_version (device, "0.0.0.0"); - return TRUE; -} - -static gboolean -fu_plugin_uefi_create_dummy (FuPlugin *plugin, const gchar *reason, GError **error) -{ - const gchar *key; - g_autoptr(FuDevice) dev = fu_device_new (); - - fu_device_set_version_format (dev, FWUPD_VERSION_FORMAT_PLAIN); - key = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_MANUFACTURER); - if (key != NULL) - fu_device_set_vendor (dev, key); - key = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_BIOS_VENDOR); - if (key != NULL) { - g_autofree gchar *vendor_id = g_strdup_printf ("DMI:%s", key); - fu_device_set_vendor_id (FU_DEVICE (dev), vendor_id); - } - key = fu_plugin_uefi_get_name_for_type (plugin, FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE); - fu_device_set_name (dev, key); - key = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_BIOS_VERSION); - if (key != NULL) - fu_device_set_version (dev, key); - fu_device_set_update_error (dev, reason); - - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_INTERNAL); - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_REBOOT); - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_REQUIRE_AC); - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_MD_SET_VERFMT); - - fu_device_add_icon (dev, "computer"); - fu_device_set_id (dev, "UEFI-dummy"); - fu_device_add_instance_id (dev, "main-system-firmware"); - if (!fu_device_setup (dev, error)) - return FALSE; - fu_plugin_device_add (plugin, dev); - - return TRUE; -} - -gboolean -fu_plugin_coldplug (FuPlugin *plugin, GError **error) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - const gchar *str; - g_autofree gchar *esrt_path = NULL; - g_autofree gchar *sysfsfwdir = NULL; - g_autoptr(GError) error_efivarfs = NULL; - g_autoptr(GError) error_local = NULL; - g_autoptr(GPtrArray) entries = NULL; - - /* are the EFI dirs set up so we can update each device */ - if (!fu_efivar_supported (&error_local)) { - const gchar *reason = "Firmware can not be updated in legacy mode, switch to UEFI mode"; - g_warning ("%s", error_local->message); - return fu_plugin_uefi_create_dummy (plugin, reason, error); - } - - /* get the directory of ESRT entries */ - sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); - esrt_path = g_build_filename (sysfsfwdir, "efi", "esrt", NULL); - entries = fu_uefi_get_esrt_entry_paths (esrt_path, &error_local); - if (entries == NULL) { - const gchar *reason = "UEFI Capsule updates not available or enabled"; - g_warning ("%s", error_local->message); - return fu_plugin_uefi_create_dummy (plugin, reason, error); - } - - /* make sure that efivarfs is rw */ - if (!fu_plugin_uefi_ensure_efivarfs_rw (&error_efivarfs)) - g_warning ("%s", error_efivarfs->message); - - /* add each device */ - for (guint i = 0; i < entries->len; i++) { - const gchar *path = g_ptr_array_index (entries, i); - g_autoptr(GError) error_parse = NULL; - g_autoptr(FuUefiDevice) dev = fu_uefi_device_new_from_entry (path, &error_parse); - if (dev == NULL) { - g_warning ("failed to add %s: %s", path, error_parse->message); - continue; - } - fu_device_set_quirks (FU_DEVICE (dev), fu_plugin_get_quirks (plugin)); - if (!fu_plugin_uefi_coldplug_device (plugin, dev, error)) - return FALSE; - if (error_efivarfs != NULL) { - fu_device_set_update_error (FU_DEVICE (dev), error_efivarfs->message); - } else { - fu_device_add_flag (FU_DEVICE (dev), FWUPD_DEVICE_FLAG_UPDATABLE); - fu_device_add_flag (FU_DEVICE (dev), FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE); - } - /* load all configuration variables */ - if (!fu_plugin_uefi_load_config (plugin, FU_DEVICE (dev), error)) - return FALSE; - - fu_plugin_device_add (plugin, FU_DEVICE (dev)); - } - - /* for debugging problems later */ - fu_plugin_uefi_test_secure_boot (plugin); - if (!fu_uefi_bgrt_setup (data->bgrt, &error_local)) - g_debug ("BGRT setup failed: %s", error_local->message); - str = fu_uefi_bgrt_get_supported (data->bgrt) ? "Enabled" : "Disabled"; - g_debug ("UX Capsule support : %s", str); - fu_plugin_add_report_metadata (plugin, "UEFIUXCapsule", str); - - return TRUE; -} diff -Nru fwupd-1.4.5/plugins/uefi/fu-self-test.c fwupd-1.5.8/plugins/uefi/fu-self-test.c --- fwupd-1.4.5/plugins/uefi/fu-self-test.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/fu-self-test.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,266 +0,0 @@ -/* - * Copyright (C) 2018 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include - -#include "fu-ucs2.h" -#include "fu-uefi-bgrt.h" -#include "fu-uefi-common.h" -#include "fu-uefi-device.h" -#include "fu-uefi-pcrs.h" - -#include "fwupd-error.h" - -static void -fu_uefi_pcrs_1_2_func (void) -{ - gboolean ret; - g_autoptr(FuUefiPcrs) pcrs = fu_uefi_pcrs_new (); - g_autoptr(GError) error = NULL; - g_autoptr(GPtrArray) pcr0s = NULL; - g_autoptr(GPtrArray) pcrXs = NULL; - - g_setenv ("FWUPD_SYSFSTPMDIR", TESTDATADIR, TRUE); - - ret = fu_uefi_pcrs_setup (pcrs, &error); - g_assert_no_error (error); - g_assert_true (ret); - pcr0s = fu_uefi_pcrs_get_checksums (pcrs, 0); - g_assert_nonnull (pcr0s); - g_assert_cmpint (pcr0s->len, ==, 1); - pcrXs = fu_uefi_pcrs_get_checksums (pcrs, 999); - g_assert_nonnull (pcrXs); - g_assert_cmpint (pcrXs->len, ==, 0); - - g_unsetenv ("FWUPD_SYSFSTPMDIR"); -} - -static void -fu_uefi_pcrs_2_0_func (void) -{ - g_autoptr(FuUefiPcrs) pcrs = fu_uefi_pcrs_new (); - g_autoptr(GError) error = NULL; - g_autoptr(GPtrArray) pcr0s = NULL; - g_autoptr(GPtrArray) pcrXs = NULL; - const gchar *tpm_server_running = g_getenv ("TPM_SERVER_RUNNING"); - g_setenv ("FWUPD_FORCE_TPM2", "1", TRUE); - -#ifdef HAVE_GETUID - if (tpm_server_running == NULL && - (getuid () != 0 || geteuid () != 0)) { - g_test_skip ("TPM2.0 tests require simulated TPM2.0 running or need root access with physical TPM"); - return; - } -#endif - - if (!fu_uefi_pcrs_setup (pcrs, &error)) { - if (tpm_server_running == NULL && - g_error_matches (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND)) { - g_test_skip ("no physical or simulated TPM 2.0 device available"); - return; - } - } - g_assert_no_error (error); - pcr0s = fu_uefi_pcrs_get_checksums (pcrs, 0); - g_assert_nonnull (pcr0s); - g_assert_cmpint (pcr0s->len, >=, 1); - pcrXs = fu_uefi_pcrs_get_checksums (pcrs, 999); - g_assert_nonnull (pcrXs); - g_assert_cmpint (pcrXs->len, ==, 0); - g_unsetenv ("FWUPD_FORCE_TPM2"); -} - -static void -fu_uefi_ucs2_func (void) -{ - g_autofree guint16 *str1 = NULL; - g_autofree gchar *str2 = NULL; - str1 = fu_uft8_to_ucs2 ("hw!", -1); - g_assert_cmpint (fu_ucs2_strlen (str1, -1), ==, 3); - str2 = fu_ucs2_to_uft8 (str1, -1); - g_assert_cmpstr ("hw!", ==, str2); -} - -static void -fu_uefi_bgrt_func (void) -{ - gboolean ret; - g_autoptr(GError) error = NULL; - g_autoptr(FuUefiBgrt) bgrt = fu_uefi_bgrt_new (); - ret = fu_uefi_bgrt_setup (bgrt, &error); - g_assert_no_error (error); - g_assert_true (ret); - g_assert_true (fu_uefi_bgrt_get_supported (bgrt)); - g_assert_cmpint (fu_uefi_bgrt_get_xoffset (bgrt), ==, 123); - g_assert_cmpint (fu_uefi_bgrt_get_yoffset (bgrt), ==, 456); - g_assert_cmpint (fu_uefi_bgrt_get_width (bgrt), ==, 54); - g_assert_cmpint (fu_uefi_bgrt_get_height (bgrt), ==, 24); -} - -static void -fu_uefi_framebuffer_func (void) -{ - gboolean ret; - guint32 height = 0; - guint32 width = 0; - g_autoptr(GError) error = NULL; - ret = fu_uefi_get_framebuffer_size (&width, &height, &error); - g_assert_no_error (error); - g_assert_true (ret); - g_assert_cmpint (width, ==, 456); - g_assert_cmpint (height, ==, 789); -} - -static void -fu_uefi_bitmap_func (void) -{ - gboolean ret; - gsize sz = 0; - guint32 height = 0; - guint32 width = 0; - g_autofree gchar *fn = NULL; - g_autofree gchar *buf = NULL; - g_autoptr(GError) error = NULL; - - fn = g_build_filename (TESTDATADIR, "test.bmp", NULL); - ret = g_file_get_contents (fn, &buf, &sz, &error); - g_assert_no_error (error); - g_assert_true (ret); - g_assert_nonnull (buf); - ret = fu_uefi_get_bitmap_size ((guint8 *)buf, sz, &width, &height, &error); - g_assert_no_error (error); - g_assert_true (ret); - g_assert_cmpint (width, ==, 54); - g_assert_cmpint (height, ==, 24); -} - -static void -fu_uefi_device_func (void) -{ - g_autofree gchar *fn = NULL; - g_autoptr(FuUefiDevice) dev = NULL; - g_autoptr(GError) error = NULL; - - fn = g_build_filename (TESTDATADIR, "efi/esrt/entries/entry0", NULL); - dev = fu_uefi_device_new_from_entry (fn, &error); - g_assert_nonnull (dev); - g_assert_no_error (error); - - g_assert_cmpint (fu_uefi_device_get_kind (dev), ==, FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE); - g_assert_cmpstr (fu_uefi_device_get_guid (dev), ==, "ddc0ee61-e7f0-4e7d-acc5-c070a398838e"); - g_assert_cmpint (fu_uefi_device_get_hardware_instance (dev), ==, 0x0); - g_assert_cmpint (fu_uefi_device_get_version (dev), ==, 65586); - g_assert_cmpint (fu_uefi_device_get_version_lowest (dev), ==, 65582); - g_assert_cmpint (fu_uefi_device_get_version_error (dev), ==, 18472960); - g_assert_cmpint (fu_uefi_device_get_capsule_flags (dev), ==, 0xfe); - g_assert_cmpint (fu_uefi_device_get_status (dev), ==, FU_UEFI_DEVICE_STATUS_ERROR_UNSUCCESSFUL); - - /* check enums all converted */ - for (guint i = 0; i < FU_UEFI_DEVICE_STATUS_LAST; i++) - g_assert_nonnull (fu_uefi_device_status_to_string (i)); -} - -static void -fu_uefi_plugin_func (void) -{ - FuUefiDevice *dev; - g_autofree gchar *esrt_path = NULL; - g_autofree gchar *sysfsfwdir = NULL; - g_autoptr(GError) error = NULL; - g_autoptr(GPtrArray) devices = NULL; - g_autoptr(GPtrArray) entries = NULL; - - /* add each device */ - sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); - esrt_path = g_build_filename (sysfsfwdir, "efi", "esrt", NULL); - entries = fu_uefi_get_esrt_entry_paths (esrt_path, &error); - g_assert_no_error (error); - g_assert_nonnull (entries); - devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - for (guint i = 0; i < entries->len; i++) { - const gchar *path = g_ptr_array_index (entries, i); - g_autoptr(GError) error_local = NULL; - g_autoptr(FuUefiDevice) dev_tmp = fu_uefi_device_new_from_entry (path, &error_local); - if (dev_tmp == NULL) { - g_debug ("failed to add %s: %s", path, error_local->message); - continue; - } - g_ptr_array_add (devices, g_object_ref (dev_tmp)); - } - g_assert_cmpint (devices->len, ==, 2); - - /* system firmware */ - dev = g_ptr_array_index (devices, 0); - g_assert_cmpint (fu_uefi_device_get_kind (dev), ==, FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE); - g_assert_cmpstr (fu_uefi_device_get_guid (dev), ==, "ddc0ee61-e7f0-4e7d-acc5-c070a398838e"); - g_assert_cmpint (fu_uefi_device_get_version (dev), ==, 65586); - g_assert_cmpint (fu_uefi_device_get_version_lowest (dev), ==, 65582); - g_assert_cmpint (fu_uefi_device_get_version_error (dev), ==, 18472960); - g_assert_cmpint (fu_uefi_device_get_capsule_flags (dev), ==, 0xfe); - g_assert_cmpint (fu_uefi_device_get_status (dev), ==, FU_UEFI_DEVICE_STATUS_ERROR_UNSUCCESSFUL); - - /* system firmware */ - dev = g_ptr_array_index (devices, 1); - g_assert_cmpint (fu_uefi_device_get_kind (dev), ==, FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE); - g_assert_cmpstr (fu_uefi_device_get_guid (dev), ==, "671d19d0-d43c-4852-98d9-1ce16f9967e4"); - g_assert_cmpint (fu_uefi_device_get_version (dev), ==, 3090287969); - g_assert_cmpint (fu_uefi_device_get_version_lowest (dev), ==, 1); - g_assert_cmpint (fu_uefi_device_get_version_error (dev), ==, 0); - g_assert_cmpint (fu_uefi_device_get_capsule_flags (dev), ==, 32784); - g_assert_cmpint (fu_uefi_device_get_status (dev), ==, FU_UEFI_DEVICE_STATUS_SUCCESS); -} - -static void -fu_uefi_update_info_func (void) -{ - g_autofree gchar *fn = NULL; - g_autoptr(FuUefiDevice) dev = NULL; - g_autoptr(FuUefiUpdateInfo) info = NULL; - g_autoptr(GError) error = NULL; - - fn = g_build_filename (TESTDATADIR, "efi/esrt/entries/entry0", NULL); - dev = fu_uefi_device_new_from_entry (fn, &error); - g_assert_no_error (error); - g_assert_nonnull (dev); - g_assert_cmpint (fu_uefi_device_get_kind (dev), ==, FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE); - g_assert_cmpstr (fu_uefi_device_get_guid (dev), ==, "ddc0ee61-e7f0-4e7d-acc5-c070a398838e"); - info = fu_uefi_device_load_update_info (dev, &error); - g_assert_no_error (error); - g_assert_nonnull (info); - g_assert_cmpint (fu_uefi_update_info_get_version (info), ==, 0x7); - g_assert_cmpstr (fu_uefi_update_info_get_guid (info), ==, "697bd920-12cf-4da9-8385-996909bc6559"); - g_assert_cmpint (fu_uefi_update_info_get_capsule_flags (info), ==, 0x50000); - g_assert_cmpint (fu_uefi_update_info_get_hw_inst (info), ==, 0x0); - g_assert_cmpint (fu_uefi_update_info_get_status (info), ==, FU_UEFI_UPDATE_INFO_STATUS_ATTEMPT_UPDATE); - g_assert_cmpstr (fu_uefi_update_info_get_capsule_fn (info), ==, - "/EFI/fedora/fw/fwupd-697bd920-12cf-4da9-8385-996909bc6559.cap"); -} - -int -main (int argc, char **argv) -{ - g_test_init (&argc, &argv, NULL); - g_setenv ("FWUPD_SYSFSFWDIR", TESTDATADIR, TRUE); - g_setenv ("FWUPD_SYSFSDRIVERDIR", TESTDATADIR, TRUE); - - /* only critical and error are fatal */ - g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); - g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); - - /* tests go here */ - g_test_add_func ("/uefi/pcrs1.2", fu_uefi_pcrs_1_2_func); - g_test_add_func ("/uefi/pcrs2.0", fu_uefi_pcrs_2_0_func); - g_test_add_func ("/uefi/ucs2", fu_uefi_ucs2_func); - g_test_add_func ("/uefi/bgrt", fu_uefi_bgrt_func); - g_test_add_func ("/uefi/framebuffer", fu_uefi_framebuffer_func); - g_test_add_func ("/uefi/bitmap", fu_uefi_bitmap_func); - g_test_add_func ("/uefi/device", fu_uefi_device_func); - g_test_add_func ("/uefi/update-info", fu_uefi_update_info_func); - g_test_add_func ("/uefi/plugin", fu_uefi_plugin_func); - return g_test_run (); -} diff -Nru fwupd-1.4.5/plugins/uefi/fu-ucs2.c fwupd-1.5.8/plugins/uefi/fu-ucs2.c --- fwupd-1.4.5/plugins/uefi/fu-ucs2.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/fu-ucs2.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2018 Richard Hughes - * Copyright (C) 2015 Peter Jones - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include "fu-ucs2.h" - -#define ev_bits(val, mask, shift) (((val) & ((mask) << (shift))) >> (shift)) - -gchar * -fu_ucs2_to_uft8 (const guint16 *str, gssize max) -{ - gssize i, j; - gchar *ret; - - if (max < 0) - max = fu_ucs2_strlen (str, max); - ret = g_malloc0 (max * 3 + 1); /* would be s/3/6 if this were UCS-4 */ - for (i = 0, j = 0; i < max && str[i]; i++, j++) { - if (str[i] <= 0x7f) { - ret[j] = str[i]; - } else if (str[i] > 0x7f && str[i] <= 0x7ff) { - ret[j++] = 0xc0 | ev_bits(str[i], 0x1f, 6); - ret[j] = 0x80 | ev_bits(str[i], 0x3f, 0); - } else if (str[i] > 0x7ff /* && str[i] < 0x10000 */ ) { - ret[j++] = 0xe0 | ev_bits(str[i], 0xf, 12); - ret[j++] = 0x80 | ev_bits(str[i], 0x3f, 6); - ret[j] = 0x80 | ev_bits(str[i], 0x3f, 0); - } - } - return ret; -} - -guint16 * -fu_uft8_to_ucs2 (const gchar *str, gssize max) -{ - gssize i, j; - guint16 *ret = g_new0 (guint16, g_utf8_strlen (str, max) + 1); - for (i = 0, j = 0; i < (max >= 0 ? max : i + 1) && str[i] != '\0'; j++) { - guint32 val = 0; - if ((str[i] & 0xe0) == 0xe0 && !(str[i] & 0x10)) { - val = ((str[i+0] & 0x0f) << 10) - |((str[i+1] & 0x3f) << 6) - |((str[i+2] & 0x3f) << 0); - i += 3; - } else if ((str[i] & 0xc0) == 0xc0 && !(str[i] & 0x20)) { - val = ((str[i+0] & 0x1f) << 6) - |((str[i+1] & 0x3f) << 0); - i += 2; - } else { - val = str[i] & 0x7f; - i += 1; - } - ret[j] = val; - } - ret[j] = L'\0'; - return ret; -} - -gsize -fu_ucs2_strlen (const guint16 *str, gssize limit) -{ - gssize i; - for (i = 0; i < (limit >= 0 ? limit : i + 1) && str[i] != L'\0'; i++); - return i; -} diff -Nru fwupd-1.4.5/plugins/uefi/fu-ucs2.h fwupd-1.5.8/plugins/uefi/fu-ucs2.h --- fwupd-1.4.5/plugins/uefi/fu-ucs2.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/fu-ucs2.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,17 +0,0 @@ -/* - * Copyright (C) 2018 Richard Hughes - * Copyright (C) 2015 Peter Jones - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include - -gsize fu_ucs2_strlen (const guint16 *str, - gssize limit); -guint16 *fu_uft8_to_ucs2 (const gchar *str, - gssize max); -gchar *fu_ucs2_to_uft8 (const guint16 *str, - gssize max); diff -Nru fwupd-1.4.5/plugins/uefi/fu-uefi-bgrt.c fwupd-1.5.8/plugins/uefi/fu-uefi-bgrt.c --- fwupd-1.4.5/plugins/uefi/fu-uefi-bgrt.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/fu-uefi-bgrt.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2018 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include "fu-common.h" -#include "fu-uefi-bgrt.h" -#include "fu-uefi-common.h" - -struct _FuUefiBgrt { - GObject parent_instance; - guint32 xoffset; - guint32 yoffset; - guint32 width; - guint32 height; -}; - -G_DEFINE_TYPE (FuUefiBgrt, fu_uefi_bgrt, G_TYPE_OBJECT) - -gboolean -fu_uefi_bgrt_setup (FuUefiBgrt *self, GError **error) -{ - gsize sz = 0; - guint64 type; - guint64 version; - g_autofree gchar *bgrtdir = NULL; - g_autofree gchar *data = NULL; - g_autofree gchar *imagefn = NULL; - g_autofree gchar *sysfsfwdir = NULL; - - g_return_val_if_fail (FU_IS_UEFI_BGRT (self), FALSE); - - sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); - bgrtdir = g_build_filename (sysfsfwdir, "acpi", "bgrt", NULL); - if (!g_file_test (bgrtdir, G_FILE_TEST_EXISTS)) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - "BGRT is not supported"); - return FALSE; - } - type = fu_uefi_read_file_as_uint64 (bgrtdir, "type"); - if (type != 0) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - "BGRT type was %" G_GUINT64_FORMAT, type); - return FALSE; - } - version = fu_uefi_read_file_as_uint64 (bgrtdir, "version"); - if (version != 1) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - "BGRT version was %" G_GUINT64_FORMAT, version); - return FALSE; - } - - /* load image */ - self->xoffset = fu_uefi_read_file_as_uint64 (bgrtdir, "xoffset"); - self->yoffset = fu_uefi_read_file_as_uint64 (bgrtdir, "yoffset"); - imagefn = g_build_filename (bgrtdir, "image", NULL); - if (!g_file_get_contents (imagefn, &data, &sz, error)) { - g_prefix_error (error, "failed to load BGRT image: "); - return FALSE; - } - if (!fu_uefi_get_bitmap_size ((guint8 *) data, sz, - &self->width, &self->height, error)) { - g_prefix_error (error, "BGRT image invalid: "); - return FALSE; - } - - /* success */ - return TRUE; -} - -gboolean -fu_uefi_bgrt_get_supported (FuUefiBgrt *self) -{ - g_return_val_if_fail (FU_IS_UEFI_BGRT (self), FALSE); - if (self->width == 0 || self->height == 0) - return FALSE; - return TRUE; -} - -guint32 -fu_uefi_bgrt_get_xoffset (FuUefiBgrt *self) -{ - g_return_val_if_fail (FU_IS_UEFI_BGRT (self), 0); - return self->xoffset; -} - -guint32 -fu_uefi_bgrt_get_yoffset (FuUefiBgrt *self) -{ - g_return_val_if_fail (FU_IS_UEFI_BGRT (self), 0); - return self->yoffset; -} - -guint32 -fu_uefi_bgrt_get_width (FuUefiBgrt *self) -{ - g_return_val_if_fail (FU_IS_UEFI_BGRT (self), 0); - return self->width; -} - -guint32 -fu_uefi_bgrt_get_height (FuUefiBgrt *self) -{ - g_return_val_if_fail (FU_IS_UEFI_BGRT (self), 0); - return self->height; -} - -static void -fu_uefi_bgrt_class_init (FuUefiBgrtClass *klass) -{ -} - -static void -fu_uefi_bgrt_init (FuUefiBgrt *self) -{ -} - -FuUefiBgrt * -fu_uefi_bgrt_new (void) -{ - FuUefiBgrt *self; - self = g_object_new (FU_TYPE_UEFI_BGRT, NULL); - return FU_UEFI_BGRT (self); -} diff -Nru fwupd-1.4.5/plugins/uefi/fu-uefi-bgrt.h fwupd-1.5.8/plugins/uefi/fu-uefi-bgrt.h --- fwupd-1.4.5/plugins/uefi/fu-uefi-bgrt.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/fu-uefi-bgrt.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2017 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#define FU_TYPE_UEFI_BGRT (fu_uefi_bgrt_get_type ()) -G_DECLARE_FINAL_TYPE (FuUefiBgrt, fu_uefi_bgrt, FU, UEFI_BGRT, GObject) - -FuUefiBgrt *fu_uefi_bgrt_new (void); -gboolean fu_uefi_bgrt_setup (FuUefiBgrt *self, - GError **error); -gboolean fu_uefi_bgrt_get_supported (FuUefiBgrt *self); -guint32 fu_uefi_bgrt_get_xoffset (FuUefiBgrt *self); -guint32 fu_uefi_bgrt_get_yoffset (FuUefiBgrt *self); -guint32 fu_uefi_bgrt_get_width (FuUefiBgrt *self); -guint32 fu_uefi_bgrt_get_height (FuUefiBgrt *self); diff -Nru fwupd-1.4.5/plugins/uefi/fu-uefi-bootmgr.c fwupd-1.5.8/plugins/uefi/fu-uefi-bootmgr.c --- fwupd-1.4.5/plugins/uefi/fu-uefi-bootmgr.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/fu-uefi-bootmgr.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,421 +0,0 @@ -/* - * Copyright (C) 2018 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include -#include -#include -#include - -#include "fwupd-error.h" - -#include "fu-ucs2.h" -#include "fu-uefi-bootmgr.h" -#include "fu-uefi-common.h" -#include "fu-efivar.h" - -/* XXX PJFIX: this should be in efiboot-loadopt.h in efivar */ -#define LOAD_OPTION_ACTIVE 0x00000001 - -static gboolean -fu_uefi_bootmgr_add_to_boot_order (guint16 boot_entry, GError **error) -{ - gsize boot_order_size = 0; - gint rc; - guint i = 0; - guint32 attr = EFI_VARIABLE_NON_VOLATILE | - EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS; - g_autofree guint16 *boot_order = NULL; - g_autofree guint16 *new_boot_order = NULL; - - /* get size of the BootOrder */ - rc = efi_get_variable_size (efi_guid_global, "BootOrder", &boot_order_size); - if (rc == ENOENT) { - boot_order_size = 0; - efi_error_clear (); - } else if (rc < 0) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "efi_get_variable_size() failed"); - return rc; - } - - /* get the current boot order */ - if (boot_order_size != 0) { - rc = efi_get_variable (efi_guid_global, "BootOrder", - (guint8 **)&boot_order, &boot_order_size, - &attr); - if (rc < 0) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "efi_get_variable(BootOrder) failed"); - return FALSE; - } - - /* already set next */ - for (i = 0; i < boot_order_size / sizeof (guint16); i++) { - guint16 val = boot_order[i]; - if (val == boot_entry) - return TRUE; - } - } - - /* add the new boot index to the end of the list */ - new_boot_order = g_malloc0 (boot_order_size + sizeof (guint16)); - if (boot_order_size != 0) - memcpy (new_boot_order, boot_order, boot_order_size); - - i = boot_order_size / sizeof (guint16); - new_boot_order[i] = boot_entry; - boot_order_size += sizeof (guint16); - rc = efi_set_variable(efi_guid_global, "BootOrder", - (guint8 *)new_boot_order, boot_order_size, - attr, 0644); - if (rc < 0) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "efi_set_variable(BootOrder) failed"); - return FALSE; - } - - return TRUE; -} - -static gboolean -fu_uefi_setup_bootnext_with_dp (const guint8 *dp_buf, guint8 *opt, gssize opt_size, GError **error) -{ - efi_guid_t *guid = NULL; - efi_load_option *loadopt = NULL; - gchar *name = NULL; - gint rc; - gsize var_data_size = 0; - guint32 attr; - guint16 boot_next = G_MAXUINT16; - g_autofree guint8 *var_data = NULL; - g_autofree guint8 *set_entries = g_malloc0 (G_MAXUINT16); - - while ((rc = efi_get_next_variable_name (&guid, &name)) > 0) { - const gchar *desc; - gint scanned = 0; - guint16 entry = 0; - g_autofree guint8 *var_data_tmp = NULL; - - if (efi_guid_cmp (guid, &efi_guid_global) != 0) - continue; - rc = sscanf (name, "Boot%hX%n", &entry, &scanned); - if (rc < 0) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to parse Boot entry %s", name); - return FALSE; - } - if (rc != 1) - continue; - if (scanned != 8) - continue; - - /* mark this as used */ - set_entries[entry] = 1; - - rc = efi_get_variable (*guid, name, &var_data_tmp, &var_data_size, &attr); - if (rc < 0) { - g_debug ("efi_get_variable(%s) failed", name); - continue; - } - - loadopt = (efi_load_option *)var_data_tmp; - if (!efi_loadopt_is_valid(loadopt, var_data_size)) { - g_debug ("load option was invalid"); - continue; - } - - desc = (const gchar *) efi_loadopt_desc (loadopt, var_data_size); - if (g_strcmp0 (desc, "Linux Firmware Updater") != 0 && - g_strcmp0 (desc, "Linux-Firmware-Updater") != 0) { - g_debug ("description does not match"); - continue; - } - - var_data = g_steal_pointer (&var_data_tmp); - boot_next = entry; - efi_error_clear (); - break; - } - if (rc < 0) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to find boot variable"); - return FALSE; - } - - /* already exists */ - if (var_data != NULL) { - - /* is different than before */ - if (var_data_size != (gsize) opt_size || - memcmp (var_data, opt, opt_size) != 0) { - efi_loadopt_attr_set (loadopt, LOAD_OPTION_ACTIVE); - rc = efi_set_variable (*guid, name, opt, opt_size, attr, 0644); - if (rc < 0) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "could not set boot variable active"); - return FALSE; - } - } - /* create a new one */ - } else { - g_autofree gchar *boot_next_name = NULL; - for (guint16 value = 0; value < G_MAXUINT16; value++) { - if (set_entries[value]) - continue; - boot_next = value; - break; - } - if (boot_next == G_MAXUINT16) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "no free boot variables (tried %x)", - boot_next); - return FALSE; - } - boot_next_name = g_strdup_printf ("Boot%04X", (guint) boot_next); - rc = efi_set_variable (efi_guid_global, boot_next_name, opt, opt_size, - EFI_VARIABLE_NON_VOLATILE | - EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS, - 0644); - if (rc < 0) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "could not set boot variable %s: %d", - boot_next_name, rc); - return FALSE; - } - } - - /* TODO: conditionalize this on the UEFI version? */ - if(!fu_uefi_bootmgr_add_to_boot_order (boot_next, error)) - return FALSE; - - /* set the boot next */ - rc = efi_set_variable (efi_guid_global, "BootNext", (guint8 *)&boot_next, 2, - EFI_VARIABLE_NON_VOLATILE | - EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS, - 0644); - if (rc < 0) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "could not set BootNext(%" G_GUINT16_FORMAT ")", - boot_next); - return FALSE; - } - return TRUE; -} - -static gboolean -fu_uefi_cmp_asset (const gchar *source, const gchar *target) -{ - gsize len = 0; - g_autofree gchar *source_checksum = NULL; - g_autofree gchar *source_data = NULL; - g_autofree gchar *target_checksum = NULL; - g_autofree gchar *target_data = NULL; - - /* nothing in target yet */ - if (!g_file_test (target, G_FILE_TEST_EXISTS)) - return FALSE; - - /* test if the file needs to be updated */ - if (!g_file_get_contents (source, &source_data, &len, NULL)) - return FALSE; - source_checksum = g_compute_checksum_for_data (G_CHECKSUM_SHA256, - (guchar *) source_data, len); - if (!g_file_get_contents (target, &target_data, &len, NULL)) - return FALSE; - target_checksum = g_compute_checksum_for_data (G_CHECKSUM_SHA256, - (guchar *) target_data, len); - return g_strcmp0 (target_checksum, source_checksum) == 0; -} - -static gboolean -fu_uefi_copy_asset (const gchar *source, const gchar *target, GError **error) -{ - g_autoptr(GFile) source_file = g_file_new_for_path (source); - g_autoptr(GFile) target_file = g_file_new_for_path (target); - - if (!g_file_copy (source_file, - target_file, - G_FILE_COPY_OVERWRITE, - NULL, - NULL, - NULL, - error)) { - g_prefix_error (error, "Failed to copy %s to %s: ", - source, target); - return FALSE; - } - - return TRUE; -} - -gboolean -fu_uefi_bootmgr_bootnext (const gchar *esp_path, - const gchar *description, - FuUefiBootmgrFlags flags, - GError **error) -{ - const gchar *filepath; - gboolean use_fwup_path = TRUE; - gboolean secure_boot = FALSE; - gsize loader_sz = 0; - gssize opt_size = 0; - gssize sz, dp_size = 0; - guint32 attributes = LOAD_OPTION_ACTIVE; - g_autofree guint16 *loader_str = NULL; - g_autofree gchar *label = NULL; - g_autofree gchar *shim_app = NULL; - g_autofree gchar *shim_cpy = NULL; - g_autofree guint8 *dp_buf = NULL; - g_autofree guint8 *opt = NULL; - g_autofree gchar *source_app = NULL; - g_autofree gchar *target_app = NULL; - - /* skip for self tests */ - if (g_getenv ("FWUPD_UEFI_TEST") != NULL) - return TRUE; - - /* if secure boot was turned on this might need to be installed separately */ - source_app = fu_uefi_get_built_app_path (error); - if (source_app == NULL) - return FALSE; - - /* test if we should use shim */ - secure_boot = fu_efivar_secure_boot_enabled (); - if (secure_boot) { - /* test to make sure shim is there if we need it */ - shim_app = fu_uefi_get_esp_app_path (esp_path, "shim", error); - if (shim_app == NULL) - return FALSE; - - if (g_file_test (shim_app, G_FILE_TEST_EXISTS)) { - /* use a custom copy of shim for firmware updates */ - if (flags & FU_UEFI_BOOTMGR_FLAG_USE_SHIM_UNIQUE) { - shim_cpy = fu_uefi_get_esp_app_path (esp_path, "shimfwupd", error); - if (shim_cpy == NULL) - return FALSE; - if (!fu_uefi_cmp_asset (shim_app, shim_cpy)) { - if (!fu_uefi_copy_asset (shim_app, shim_cpy, error)) - return FALSE; - } - filepath = shim_cpy; - } else { - filepath = shim_app; - } - use_fwup_path = FALSE; - } else if ((flags & FU_UEFI_BOOTMGR_FLAG_USE_SHIM_FOR_SB) > 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_BROKEN_SYSTEM, - "Secure boot is enabled, but shim isn't installed to the EFI system partition"); - return FALSE; - } - } - - /* test if correct asset in place */ - target_app = fu_uefi_get_esp_app_path (esp_path, "fwupd", error); - if (target_app == NULL) - return FALSE; - if (!fu_uefi_cmp_asset (source_app, target_app)) { - if (!fu_uefi_copy_asset (source_app, target_app, error)) - return FALSE; - } - - /* no shim, so use this directly */ - if (use_fwup_path) - filepath = target_app; - - /* generate device path for target */ - sz = efi_generate_file_device_path (dp_buf, dp_size, filepath, - EFIBOOT_OPTIONS_IGNORE_FS_ERROR| - EFIBOOT_ABBREV_HD); - if (sz < 0) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "efi_generate_file_device_path(%s) failed", - filepath); - return FALSE; - } - - /* add the fwupdx64.efi ESP path as the shim loadopt data */ - dp_size = sz; - dp_buf = g_malloc0 (dp_size); - if (!use_fwup_path) { - g_autofree gchar *fwup_fs_basename = g_path_get_basename (target_app); - g_autofree gchar *fwup_esp_path = g_strdup_printf ("\\%s", fwup_fs_basename); - loader_str = fu_uft8_to_ucs2 (fwup_esp_path, -1); - loader_sz = fu_ucs2_strlen (loader_str, -1) * 2; - if (loader_sz) - loader_sz += 2; - } - - sz = efi_generate_file_device_path (dp_buf, dp_size, filepath, - EFIBOOT_OPTIONS_IGNORE_FS_ERROR| - EFIBOOT_ABBREV_HD); - if (sz != dp_size) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "efi_generate_file_device_path(%s) failed", - filepath); - return FALSE; - } - - label = g_strdup (description); - sz = efi_loadopt_create (opt, opt_size, attributes, - (efidp)dp_buf, dp_size, - (guint8 *)label, - (guint8 *)loader_str, loader_sz); - if (sz < 0) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "efi_loadopt_create(%s) failed", - label); - return FALSE; - } - opt = g_malloc0 (sz); - opt_size = sz; - sz = efi_loadopt_create (opt, opt_size, attributes, - (efidp)dp_buf, dp_size, - (guint8 *)label, - (guint8 *)loader_str, loader_sz); - if (sz != opt_size) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "loadopt size was unreasonable."); - return FALSE; - } - if (!fu_uefi_setup_bootnext_with_dp (dp_buf, opt, opt_size, error)) - return FALSE; - efi_error_clear(); - - return TRUE; -} diff -Nru fwupd-1.4.5/plugins/uefi/fu-uefi-bootmgr.h fwupd-1.5.8/plugins/uefi/fu-uefi-bootmgr.h --- fwupd-1.4.5/plugins/uefi/fu-uefi-bootmgr.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/fu-uefi-bootmgr.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2018 Richard Hughes - * Copyright (C) 2015-2017 Peter Jones - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include -#include - -typedef enum { - FU_UEFI_BOOTMGR_FLAG_NONE = 0, - FU_UEFI_BOOTMGR_FLAG_USE_SHIM_FOR_SB = 1 << 0, - FU_UEFI_BOOTMGR_FLAG_USE_SHIM_UNIQUE = 1 << 1, - FU_UEFI_BOOTMGR_FLAG_LAST -} FuUefiBootmgrFlags; - -gboolean fu_uefi_bootmgr_bootnext (const gchar *esp_path, - const gchar *description, - FuUefiBootmgrFlags flags, - GError **error); diff -Nru fwupd-1.4.5/plugins/uefi/fu-uefi-common.c fwupd-1.5.8/plugins/uefi/fu-uefi-common.c --- fwupd-1.4.5/plugins/uefi/fu-uefi-common.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/fu-uefi-common.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,440 +0,0 @@ -/* - * Copyright (C) 2018 Richard Hughes - * Copyright (C) 2015-2017 Peter Jones - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include -#include - -#include "fu-common.h" -#include "fu-uefi-common.h" -#include "fu-efivar.h" -#include "fu-uefi-udisks.h" - -#include "fwupd-common.h" -#include "fwupd-error.h" - -#ifndef HAVE_GIO_2_55_0 -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-function" -G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUnixMountEntry, g_unix_mount_free) -#pragma clang diagnostic pop -#endif - -static const gchar * -fu_uefi_bootmgr_get_suffix (GError **error) -{ - guint64 firmware_bits; - struct { - guint64 bits; - const gchar *arch; - } suffixes[] = { -#if defined(__x86_64__) - { 64, "x64" }, -#elif defined(__aarch64__) - { 64, "aa64" }, -#endif -#if defined(__x86_64__) || defined(__i386__) || defined(__i686__) - { 32, "ia32" }, -#endif - { 0, NULL } - }; - g_autofree gchar *sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); - g_autofree gchar *sysfsefidir = g_build_filename (sysfsfwdir, "efi", NULL); - firmware_bits = fu_uefi_read_file_as_uint64 (sysfsefidir, "fw_platform_size"); - if (firmware_bits == 0) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_NOT_FOUND, - "%s/fw_platform_size cannot be found", - sysfsefidir); - return NULL; - } - for (guint i = 0; suffixes[i].arch != NULL; i++) { - if (firmware_bits != suffixes[i].bits) - continue; - return suffixes[i].arch; - } - - /* this should exist */ - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_NOT_FOUND, - "%s/fw_platform_size has unknown value %" G_GUINT64_FORMAT, - sysfsefidir, firmware_bits); - return NULL; -} - -gchar * -fu_uefi_get_esp_app_path (const gchar *esp_path, const gchar *cmd, GError **error) -{ - const gchar *suffix = fu_uefi_bootmgr_get_suffix (error); - g_autofree gchar *base = NULL; - if (suffix == NULL) - return NULL; - base = fu_uefi_get_esp_path_for_os (esp_path); - return g_strdup_printf ("%s/%s%s.efi", base, cmd, suffix); -} - -gchar * -fu_uefi_get_built_app_path (GError **error) -{ - const gchar *extension = ""; - const gchar *suffix; - g_autofree gchar *source_path = NULL; - g_autofree gchar *prefix = NULL; - if (fu_efivar_secure_boot_enabled ()) - extension = ".signed"; - suffix = fu_uefi_bootmgr_get_suffix (error); - if (suffix == NULL) - return NULL; - prefix = fu_common_get_path (FU_PATH_KIND_EFIAPPDIR); - source_path = g_strdup_printf ("%s/fwupd%s.efi%s", - prefix, - suffix, - extension); - if (!g_file_test (source_path, G_FILE_TEST_EXISTS)) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_NOT_FOUND, - "%s cannot be found", - source_path); - return NULL; - } - return g_steal_pointer (&source_path); -} - -gboolean -fu_uefi_get_framebuffer_size (guint32 *width, guint32 *height, GError **error) -{ - guint32 height_tmp; - guint32 width_tmp; - g_autofree gchar *sysfsdriverdir = NULL; - g_autofree gchar *fbdir = NULL; - - sysfsdriverdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_DRIVERS); - fbdir = g_build_filename (sysfsdriverdir, "efi-framebuffer", "efi-framebuffer.0", NULL); - if (!g_file_test (fbdir, G_FILE_TEST_EXISTS)) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "EFI framebuffer not found"); - return FALSE; - } - height_tmp = fu_uefi_read_file_as_uint64 (fbdir, "height"); - width_tmp = fu_uefi_read_file_as_uint64 (fbdir, "width"); - if (width_tmp == 0 || height_tmp == 0) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "EFI framebuffer has invalid size " - "%"G_GUINT32_FORMAT"x%"G_GUINT32_FORMAT, - width_tmp, height_tmp); - return FALSE; - } - if (width != NULL) - *width = width_tmp; - if (height != NULL) - *height = height_tmp; - return TRUE; -} - -gboolean -fu_uefi_get_bitmap_size (const guint8 *buf, - gsize bufsz, - guint32 *width, - guint32 *height, - GError **error) -{ - guint32 ui32; - - g_return_val_if_fail (buf != NULL, FALSE); - - /* check header */ - if (bufsz < 26) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "blob was too small %" G_GSIZE_FORMAT, bufsz); - return FALSE; - } - if (memcmp (buf, "BM", 2) != 0) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "invalid BMP header signature"); - return FALSE; - } - - /* starting address */ - ui32 = fu_common_read_uint32 (buf + 10, G_LITTLE_ENDIAN); - if (ui32 < 26) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "BMP header invalid @ %"G_GUINT32_FORMAT"x", ui32); - return FALSE; - } - - /* BITMAPINFOHEADER header */ - ui32 = fu_common_read_uint32 (buf + 14, G_LITTLE_ENDIAN); - if (ui32 < 26 - 14) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "BITMAPINFOHEADER invalid @ %"G_GUINT32_FORMAT"x", ui32); - return FALSE; - } - - /* dimensions */ - if (width != NULL) - *width = fu_common_read_uint32 (buf + 18, G_LITTLE_ENDIAN); - if (height != NULL) - *height = fu_common_read_uint32 (buf + 22, G_LITTLE_ENDIAN); - return TRUE; -} - -static gint -fu_uefi_strcmp_sort_cb (gconstpointer a, gconstpointer b) -{ - const gchar *stra = *((const gchar **) a); - const gchar *strb = *((const gchar **) b); - return g_strcmp0 (stra, strb); -} - -GPtrArray * -fu_uefi_get_esrt_entry_paths (const gchar *esrt_path, GError **error) -{ - GPtrArray *entries = g_ptr_array_new_with_free_func (g_free); - const gchar *fn; - g_autofree gchar *esrt_entries = NULL; - g_autoptr(GDir) dir = NULL; - - /* search ESRT */ - esrt_entries = g_build_filename (esrt_path, "entries", NULL); - dir = g_dir_open (esrt_entries, 0, error); - if (dir == NULL) - return NULL; - while ((fn = g_dir_read_name (dir)) != NULL) - g_ptr_array_add (entries, g_build_filename (esrt_entries, fn, NULL)); - - /* sort by name */ - g_ptr_array_sort (entries, fu_uefi_strcmp_sort_cb); - return entries; -} - -gchar * -fu_uefi_get_esp_path_for_os (const gchar *base) -{ -#ifndef EFI_OS_DIR - const gchar *os_release_id = NULL; - const gchar *id_like_id; - g_autofree gchar *esp_path = NULL; - g_autoptr(GError) error_local = NULL; - g_autoptr(GHashTable) os_release = fwupd_get_os_release (&error_local); - /* try to lookup /etc/os-release ID key */ - if (os_release != NULL) { - os_release_id = g_hash_table_lookup (os_release, "ID"); - } else { - g_debug ("failed to get ID: %s", error_local->message); - } - if (os_release_id == NULL) - os_release_id = "unknown"; - /* if ID key points at something existing return it */ - esp_path = g_build_filename (base, "EFI", os_release_id, NULL); - if (g_file_test (esp_path, G_FILE_TEST_IS_DIR) || os_release == NULL) - return g_steal_pointer (&esp_path); - /* if ID key doesn't exist, try ID_LIKE */ - id_like_id = g_hash_table_lookup (os_release, "ID_LIKE"); - if (id_like_id != NULL) { - g_autofree gchar* id_like_path = g_build_filename (base, "EFI", id_like_id, NULL); - if (g_file_test (id_like_path, G_FILE_TEST_IS_DIR)) { - g_debug ("Using ID_LIKE key from os-release"); - return g_steal_pointer (&id_like_path); - } - } - return g_steal_pointer (&esp_path); -#else - return g_build_filename (base, "EFI", EFI_OS_DIR, NULL); -#endif -} - -guint64 -fu_uefi_read_file_as_uint64 (const gchar *path, const gchar *attr_name) -{ - g_autofree gchar *data = NULL; - g_autofree gchar *fn = g_build_filename (path, attr_name, NULL); - if (!g_file_get_contents (fn, &data, NULL, NULL)) - return 0x0; - return fu_common_strtoull (data); -} - -gboolean -fu_uefi_check_esp_free_space (const gchar *path, guint64 required, GError **error) -{ - guint64 fs_free; - g_autoptr(GFile) file = NULL; - g_autoptr(GFileInfo) info = NULL; - - /* skip the checks for unmounted disks */ - if (fu_uefi_udisks_objpath (path)) - return TRUE; - - file = g_file_new_for_path (path); - info = g_file_query_filesystem_info (file, - G_FILE_ATTRIBUTE_FILESYSTEM_FREE, - NULL, error); - if (info == NULL) - return FALSE; - fs_free = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE); - if (fs_free < required) { - g_autofree gchar *str_free = g_format_size (fs_free); - g_autofree gchar *str_reqd = g_format_size (required); - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "%s does not have sufficient space, required %s, got %s", - path, str_reqd, str_free); - return FALSE; - } - return TRUE; -} - -gboolean -fu_uefi_check_esp_path (const gchar *path, GError **error) -{ - const gchar *fs_types[] = { "vfat", "ntfs", "exfat", "autofs", NULL }; - g_autoptr(GUnixMountEntry) mount = g_unix_mount_at (path, NULL); - if (mount == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "%s was not mounted", path); - return FALSE; - } - - /* /boot is a special case because systemd sandboxing marks - * it read-only, but we need to write to /boot/EFI - */ - if (g_strcmp0 (path, "/boot") == 0) { - if (!g_file_test ("/boot/EFI", G_FILE_TEST_IS_DIR)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "%s/EFI does not exist", path); - return FALSE; - } - /* /efi is a special case because systemd sandboxing marks - * it read-only, but we need to write to /efi/EFI - */ - } else if (g_strcmp0 (path, "/efi") == 0) { - if (!g_file_test ("/efi/EFI", G_FILE_TEST_IS_DIR)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "%s/EFI does not exist", path); - return FALSE; - } - } else if (g_unix_mount_is_readonly (mount)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "%s is read only", path); - return FALSE; - } - if (!g_strv_contains (fs_types, g_unix_mount_get_fs_type (mount))) { - g_autofree gchar *supported = g_strjoinv ("|", (gchar **) fs_types); - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "%s has an invalid type, expected %s", - path, supported); - return FALSE; - } - return TRUE; -} - -static gchar * -fu_uefi_probe_udisks_esp (GError **error) -{ - g_autoptr(GPtrArray) devices = NULL; - g_autofree gchar *found_esp = NULL; - - devices = fu_uefi_udisks_get_block_devices (error); - if (devices == NULL) - return NULL; - for (guint i = 0; i < devices->len; i++) { - const gchar *obj = g_ptr_array_index (devices, i); - gboolean esp = fu_uefi_udisks_objpath_is_esp (obj); - g_debug ("block device %s, is_esp: %d", obj, esp); - if (!esp) - continue; - if (found_esp != NULL) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_FILENAME, - "Multiple EFI system partitions found, " - "See https://github.com/fwupd/fwupd/wiki/Determining-EFI-system-partition-location"); - return NULL; - } - found_esp = g_strdup (obj); - } - if (found_esp == NULL) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_FILENAME, - "Unable to determine EFI system partition location, " - "See https://github.com/fwupd/fwupd/wiki/Determining-EFI-system-partition-location"); - return NULL; - } - - g_debug ("Udisks detected objpath %s", found_esp); - return g_steal_pointer (&found_esp); -} - -gchar * -fu_uefi_guess_esp_path (GError **error) -{ - const gchar *paths[] = {"/boot/efi", "/boot", "/efi", NULL}; - const gchar *path_tmp; - - /* for the test suite use local directory for ESP */ - path_tmp = g_getenv ("FWUPD_UEFI_ESP_PATH"); - if (path_tmp != NULL) - return g_strdup (path_tmp); - - /* try to use known paths */ - for (guint i = 0; paths[i] != NULL; i++) { - g_autoptr(GError) error_local = NULL; - if (!fu_uefi_check_esp_path (paths[i], &error_local)) { - g_debug ("ignoring ESP path: %s", error_local->message); - continue; - } - return g_strdup (paths[i]); - } - - /* probe using udisks2 */ - return fu_uefi_probe_udisks_esp (error); -} - -void -fu_uefi_print_efivar_errors (void) -{ - for (gint i = 0; ; i++) { - gchar *filename = NULL; - gchar *function = NULL; - gchar *message = NULL; - gint line = 0; - gint err = 0; - if (efi_error_get (i, &filename, &function, &line, - &message, &err) <= 0) - break; - g_debug ("{efivar error #%d} %s:%d %s(): %s: %s\t", - i, filename, line, function, - message, strerror (err)); - } -} diff -Nru fwupd-1.4.5/plugins/uefi/fu-uefi-common.h fwupd-1.5.8/plugins/uefi/fu-uefi-common.h --- fwupd-1.4.5/plugins/uefi/fu-uefi-common.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/fu-uefi-common.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2018 Richard Hughes - * Copyright (C) 2015-2017 Peter Jones - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include -#include - -#define EFI_CAPSULE_HEADER_FLAGS_PERSIST_ACROSS_RESET 0x00010000 -#define EFI_CAPSULE_HEADER_FLAGS_POPULATE_SYSTEM_TABLE 0x00020000 -#define EFI_CAPSULE_HEADER_FLAGS_INITIATE_RESET 0x00040000 - -typedef struct __attribute__((__packed__)) { - guint16 year; - guint8 month; - guint8 day; - guint8 hour; - guint8 minute; - guint8 second; - guint8 pad1; - guint32 nanosecond; - guint16 timezone; - guint8 daylight; - guint8 pad2; -} efi_time_t; - -typedef struct __attribute__((__packed__)) { - efi_guid_t guid; - guint32 header_size; - guint32 flags; - guint32 capsule_image_size; -} efi_capsule_header_t; - -typedef struct __attribute__((__packed__)) { - guint8 version; - guint8 checksum; - guint8 image_type; - guint8 reserved; - guint32 mode; - guint32 x_offset; - guint32 y_offset; -} efi_ux_capsule_header_t; - -typedef struct __attribute__((__packed__)) { - guint32 update_info_version; - efi_guid_t guid; - guint32 capsule_flags; - guint64 hw_inst; - efi_time_t time_attempted; - guint32 status; -} efi_update_info_t; - -/* the biggest size SPI part currently seen */ -#define FU_UEFI_COMMON_REQUIRED_ESP_FREE_SPACE (32 * 1024 * 1024) - -gchar *fu_uefi_get_esp_app_path (const gchar *esp_path, - const gchar *cmd, - GError **error); -gchar *fu_uefi_get_built_app_path (GError **error); -gboolean fu_uefi_get_bitmap_size (const guint8 *buf, - gsize bufsz, - guint32 *width, - guint32 *height, - GError **error); -gboolean fu_uefi_get_framebuffer_size (guint32 *width, - guint32 *height, - GError **error); -gchar *fu_uefi_guess_esp_path (GError **error); -gboolean fu_uefi_check_esp_path (const gchar *path, - GError **error); -gboolean fu_uefi_check_esp_free_space (const gchar *path, - guint64 required, - GError **error); -gchar *fu_uefi_get_esp_path_for_os (const gchar *esp_path); -GPtrArray *fu_uefi_get_esrt_entry_paths (const gchar *esrt_path, - GError **error); -guint64 fu_uefi_read_file_as_uint64 (const gchar *path, - const gchar *attr_name); -void fu_uefi_print_efivar_errors (void); diff -Nru fwupd-1.4.5/plugins/uefi/fu-uefi-device.c fwupd-1.5.8/plugins/uefi/fu-uefi-device.c --- fwupd-1.4.5/plugins/uefi/fu-uefi-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/fu-uefi-device.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,850 +0,0 @@ -/* - * Copyright (C) 2018 Richard Hughes - * Copyright (C) 2015-2017 Peter Jones - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include -#include -#include - -#include "fu-device-metadata.h" - -#include "fu-common.h" - -#include "fu-uefi-common.h" -#include "fu-uefi-device.h" -#include "fu-uefi-devpath.h" -#include "fu-uefi-bootmgr.h" -#include "fu-uefi-pcrs.h" -#include "fu-efivar.h" -#include "fu-uefi-udisks.h" - -struct _FuUefiDevice { - FuDevice parent_instance; - gchar *fw_class; - FuUefiDeviceKind kind; - guint32 capsule_flags; - guint32 fw_version; - guint32 fw_version_lowest; - FuUefiDeviceStatus last_attempt_status; - guint32 last_attempt_version; - guint64 fmp_hardware_instance; - gboolean missing_header; - gboolean automounted_esp; - gboolean requires_header; -}; - -G_DEFINE_TYPE (FuUefiDevice, fu_uefi_device, FU_TYPE_DEVICE) - -const gchar * -fu_uefi_device_kind_to_string (FuUefiDeviceKind kind) -{ - if (kind == FU_UEFI_DEVICE_KIND_UNKNOWN) - return "unknown"; - if (kind == FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE) - return "system-firmware"; - if (kind == FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE) - return "device-firmware"; - if (kind == FU_UEFI_DEVICE_KIND_UEFI_DRIVER) - return "uefi-driver"; - if (kind == FU_UEFI_DEVICE_KIND_FMP) - return "fmp"; - if (kind == FU_UEFI_DEVICE_KIND_DELL_TPM_FIRMWARE) - return "dell-tpm-firmware"; - return NULL; -} - -static FuUefiDeviceKind -fu_uefi_device_kind_from_string (const gchar *kind) -{ - if (g_strcmp0 (kind, "system-firmware") == 0) - return FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE; - if (g_strcmp0 (kind, "device-firmware") == 0) - return FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE; - if (g_strcmp0 (kind, "uefi-driver") == 0) - return FU_UEFI_DEVICE_KIND_UEFI_DRIVER; - if (g_strcmp0 (kind, "fmp") == 0) - return FU_UEFI_DEVICE_KIND_FMP; - if (g_strcmp0 (kind, "dell-tpm-firmware") == 0) - return FU_UEFI_DEVICE_KIND_DELL_TPM_FIRMWARE; - return FU_UEFI_DEVICE_KIND_UNKNOWN; -} - -const gchar * -fu_uefi_device_status_to_string (FuUefiDeviceStatus status) -{ - if (status == FU_UEFI_DEVICE_STATUS_SUCCESS) - return "success"; - if (status == FU_UEFI_DEVICE_STATUS_ERROR_UNSUCCESSFUL) - return "unsuccessful"; - if (status == FU_UEFI_DEVICE_STATUS_ERROR_INSUFFICIENT_RESOURCES) - return "insufficient resources"; - if (status == FU_UEFI_DEVICE_STATUS_ERROR_INCORRECT_VERSION) - return "incorrect version"; - if (status == FU_UEFI_DEVICE_STATUS_ERROR_INVALID_FORMAT) - return "invalid firmware format"; - if (status == FU_UEFI_DEVICE_STATUS_ERROR_AUTH_ERROR) - return "authentication signing error"; - if (status == FU_UEFI_DEVICE_STATUS_ERROR_PWR_EVT_AC) - return "AC power required"; - if (status == FU_UEFI_DEVICE_STATUS_ERROR_PWR_EVT_BATT) - return "battery level is too low"; - return NULL; -} - -static void -fu_uefi_device_to_string (FuDevice *device, guint idt, GString *str) -{ - FuUefiDevice *self = FU_UEFI_DEVICE (device); - fu_common_string_append_kv (str, idt, "Kind", fu_uefi_device_kind_to_string (self->kind)); - fu_common_string_append_kv (str, idt, "FwClass", self->fw_class); - fu_common_string_append_kx (str, idt, "CapsuleFlags", self->capsule_flags); - fu_common_string_append_kx (str, idt, "FwVersion", self->fw_version); - fu_common_string_append_kx (str, idt, "FwVersionLowest", self->fw_version_lowest); - fu_common_string_append_kv (str, idt, "LastAttemptStatus", - fu_uefi_device_status_to_string (self->last_attempt_status)); - fu_common_string_append_kx (str, idt, "LastAttemptVersion", self->last_attempt_version); - fu_common_string_append_kv (str, idt, "EspPath", - fu_device_get_metadata (device, "EspPath")); - fu_common_string_append_ku (str, idt, "RequireESPFreeSpace", - fu_device_get_metadata_integer (device, "RequireESPFreeSpace")); - fu_common_string_append_kb (str, idt, "RequireShimForSecureBoot", - fu_device_get_metadata_boolean (device, "RequireShimForSecureBoot")); -} - -FuUefiDeviceKind -fu_uefi_device_get_kind (FuUefiDevice *self) -{ - g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), 0); - return self->kind; -} - -guint32 -fu_uefi_device_get_version (FuUefiDevice *self) -{ - g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), 0x0); - return self->fw_version; -} - -guint32 -fu_uefi_device_get_version_lowest (FuUefiDevice *self) -{ - g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), 0x0); - return self->fw_version_lowest; -} - -guint32 -fu_uefi_device_get_version_error (FuUefiDevice *self) -{ - g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), 0x0); - return self->last_attempt_version; -} - -guint64 -fu_uefi_device_get_hardware_instance (FuUefiDevice *self) -{ - g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), 0x0); - return self->fmp_hardware_instance; -} - -FuUefiDeviceStatus -fu_uefi_device_get_status (FuUefiDevice *self) -{ - g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), 0); - return self->last_attempt_status; -} - -guint32 -fu_uefi_device_get_capsule_flags (FuUefiDevice *self) -{ - g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), 0x0); - return self->capsule_flags; -} - -const gchar * -fu_uefi_device_get_guid (FuUefiDevice *self) -{ - g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), NULL); - return self->fw_class; -} - -static gchar * -fu_uefi_device_build_varname (FuUefiDevice *self) -{ - return g_strdup_printf ("fwupd-%s-%"G_GUINT64_FORMAT, - self->fw_class, - self->fmp_hardware_instance); -} - -FuUefiUpdateInfo * -fu_uefi_device_load_update_info (FuUefiDevice *self, GError **error) -{ - gsize datasz = 0; - g_autofree gchar *varname = fu_uefi_device_build_varname (self); - g_autofree guint8 *data = NULL; - g_autoptr(FuUefiUpdateInfo) info = fu_uefi_update_info_new (); - - g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - /* get the existing status */ - if (!fu_efivar_get_data (FU_EFIVAR_GUID_FWUPDATE, varname, - &data, &datasz, NULL, error)) - return NULL; - if (!fu_uefi_update_info_parse (info, data, datasz, error)) - return NULL; - return g_steal_pointer (&info); -} - -gboolean -fu_uefi_device_clear_status (FuUefiDevice *self, GError **error) -{ - efi_update_info_t info; - gsize datasz = 0; - g_autofree gchar *varname = fu_uefi_device_build_varname (self); - g_autofree guint8 *data = NULL; - - g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* get the existing status */ - if (!fu_efivar_get_data (FU_EFIVAR_GUID_FWUPDATE, varname, - &data, &datasz, NULL, error)) - return FALSE; - if (datasz < sizeof(efi_update_info_t)) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "EFI variable is corrupt"); - return FALSE; - } - - /* just copy the efi_update_info_t, ignore devpath then save it back */ - memcpy (&info, data, sizeof(info)); - info.status = FU_UEFI_DEVICE_STATUS_SUCCESS; - memcpy (data, &info, sizeof(info)); - return fu_efivar_set_data (FU_EFIVAR_GUID_FWUPDATE, varname, - data, datasz, - FU_EFIVAR_ATTR_NON_VOLATILE | - FU_EFIVAR_ATTR_BOOTSERVICE_ACCESS | - FU_EFIVAR_ATTR_RUNTIME_ACCESS, - error); -} - -static guint8 * -fu_uefi_device_build_dp_buf (const gchar *path, gsize *bufsz, GError **error) -{ - gssize req; - gssize sz; - g_autofree guint8 *dp_buf = NULL; - g_autoptr(GPtrArray) dps = NULL; - - /* get the size of the path first */ - req = efi_generate_file_device_path (NULL, 0, path, - EFIBOOT_OPTIONS_IGNORE_FS_ERROR | - EFIBOOT_ABBREV_HD); - if (req < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "failed to efi_generate_file_device_path(%s)", - path); - return NULL; - } - - /* if we just have an end device path, it's not going to work */ - if (req <= 4) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "failed to get valid device_path for (%s)", - path); - return NULL; - } - - /* actually get the path this time */ - dp_buf = g_malloc0 (req); - sz = efi_generate_file_device_path (dp_buf, req, path, - EFIBOOT_OPTIONS_IGNORE_FS_ERROR | - EFIBOOT_ABBREV_HD); - if (sz < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "failed to efi_generate_file_device_path(%s)", - path); - return NULL; - } - - /* parse what we got back from efivar */ - dps = fu_uefi_devpath_parse (dp_buf, (gsize) sz, - FU_UEFI_DEVPATH_PARSE_FLAG_NONE, error); - if (dps == NULL) { - fu_common_dump_raw (G_LOG_DOMAIN, "dp_buf", dp_buf, (gsize) sz); - return NULL; - } - - /* success */ - if (bufsz != NULL) - *bufsz = sz; - return g_steal_pointer (&dp_buf); -} - -static GBytes * -fu_uefi_device_fixup_firmware (FuDevice *device, GBytes *fw, GError **error) -{ - FuUefiDevice *self = FU_UEFI_DEVICE (device); - gsize fw_length; - efi_guid_t esrt_guid; - efi_guid_t payload_guid; - const gchar *data = g_bytes_get_data (fw, &fw_length); - self->missing_header = FALSE; - - /* convert to EFI GUIDs */ - if (efi_str_to_guid (fu_uefi_device_get_guid (self), &esrt_guid) < 0) { - g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, - "Invalid ESRT GUID"); - return NULL; - } - if (fw_length < sizeof(efi_guid_t)) { - g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "Invalid payload"); - return NULL; - } - memcpy (&payload_guid, data, sizeof(efi_guid_t)); - - /* ESRT header matches payload */ - if (efi_guid_cmp (&esrt_guid, &payload_guid) == 0) { - g_debug ("ESRT matches payload GUID"); - return g_bytes_new_from_bytes (fw, 0, fw_length); - /* Type that doesn't require a header */ - } else if (!self->requires_header) { - return g_bytes_new_from_bytes (fw, 0, fw_length); - /* Missing, add a header */ - } else { - guint header_size = getpagesize(); - guint8 *new_data = g_malloc (fw_length + header_size); - guint8 *capsule = new_data + header_size; - efi_capsule_header_t *header = (efi_capsule_header_t *) new_data; - - g_warning ("missing or invalid embedded capsule header"); - self->missing_header = TRUE; - header->flags = self->capsule_flags; - header->header_size = header_size; - header->capsule_image_size = fw_length + header_size; - memcpy (&header->guid, &esrt_guid, sizeof (efi_guid_t)); - memcpy (capsule, data, fw_length); - - return g_bytes_new_take (new_data, fw_length + header_size); - } -} - -gboolean -fu_uefi_missing_capsule_header (FuDevice *device) -{ - FuUefiDevice *self = FU_UEFI_DEVICE (device); - return self->missing_header; -} - -gboolean -fu_uefi_device_write_update_info (FuUefiDevice *self, - const gchar *filename, - const gchar *varname, - const efi_guid_t *guid, - GError **error) -{ - gsize datasz = 0; - gsize dp_bufsz = 0; - g_autofree guint8 *data = NULL; - g_autofree guint8 *dp_buf = NULL; - efi_update_info_t info = { - .update_info_version = 0x7, - .guid = { 0x0 }, - .capsule_flags = self->capsule_flags, - .hw_inst = self->fmp_hardware_instance, - .time_attempted = { 0x0 }, - .status = FU_UEFI_UPDATE_INFO_STATUS_ATTEMPT_UPDATE, - }; - - /* set the body as the device path */ - if (g_getenv ("FWUPD_UEFI_TEST") != NULL) { - g_debug ("not building device path, in tests...."); - return TRUE; - } - - /* convert to EFI device path */ - dp_buf = fu_uefi_device_build_dp_buf (filename, &dp_bufsz, error); - if (dp_buf == NULL) { - fu_uefi_print_efivar_errors (); - return FALSE; - } - - /* save this header and body to the hardware */ - memcpy (&info.guid, guid, sizeof(efi_guid_t)); - datasz = sizeof(info) + dp_bufsz; - data = g_malloc0 (datasz); - memcpy (data, &info, sizeof(info)); - memcpy (data + sizeof(info), dp_buf, dp_bufsz); - if (!fu_efivar_set_data (FU_EFIVAR_GUID_FWUPDATE, varname, - data, datasz, - FU_EFIVAR_ATTR_NON_VOLATILE | - FU_EFIVAR_ATTR_BOOTSERVICE_ACCESS | - FU_EFIVAR_ATTR_RUNTIME_ACCESS, - error)) { - fu_uefi_print_efivar_errors (); - return FALSE; - } - return TRUE; -} - -static gboolean -fu_uefi_device_is_esp_mounted (FuDevice *device, GError **error) -{ - const gchar *esp_path = fu_device_get_metadata (device, "EspPath"); - g_autofree gchar *contents = NULL; - g_auto(GStrv) lines = NULL; - gsize length; - - if (esp_path == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "EFI System partition is not defined"); - return FALSE; - } - - if (!g_file_get_contents ("/proc/mounts", &contents, &length, error)) - return FALSE; - lines = g_strsplit (contents, "\n", 0); - - for (guint i = 0; lines[i] != NULL; i++) { - if (lines[i] != NULL && g_strrstr (lines[i], esp_path)) - return TRUE; - } - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "EFI System partition %s is not mounted", - esp_path); - return FALSE; -} - -static gboolean -fu_uefi_device_check_esp_free (FuDevice *device, GError **error) -{ - const gchar *esp_path = fu_device_get_metadata (device, "EspPath"); - guint64 sz_reqd = fu_device_get_metadata_integer (device, "RequireESPFreeSpace"); - if (sz_reqd == G_MAXUINT) { - g_debug ("maximum size is not configured"); - return TRUE; - } - return fu_uefi_check_esp_free_space (esp_path, sz_reqd, error); -} - -static gboolean -fu_uefi_check_asset (FuDevice *device, GError **error) -{ - g_autofree gchar *source_app = fu_uefi_get_built_app_path (error); - if (source_app == NULL) { - if (fu_efivar_secure_boot_enabled ()) - g_prefix_error (error, "missing signed bootloader for secure boot: "); - return FALSE; - } - - return TRUE; -} - -static gboolean -fu_uefi_device_cleanup_esp (FuDevice *device, GError **error) -{ - const gchar *esp_path = fu_device_get_metadata (device, "EspPath"); - g_autofree gchar *pattern = NULL; - g_autoptr(GPtrArray) files = NULL; - - /* in case we call capsule install twice before reboot */ - if (fu_efivar_exists (FU_EFIVAR_GUID_EFI_GLOBAL, "BootNext")) - return TRUE; - - /* delete any files matching the glob in the ESP */ - files = fu_common_get_files_recursive (esp_path, error); - if (files == NULL) - return FALSE; - pattern = g_build_filename (esp_path, "EFI/*/fw/fwupd*.cap", NULL); - for (guint i = 0; i < files->len; i++) { - const gchar *fn = g_ptr_array_index (files, i); - if (fu_common_fnmatch (pattern, fn)) { - g_autoptr(GFile) file = g_file_new_for_path (fn); - g_debug ("deleting %s", fn); - if (!g_file_delete (file, NULL, error)) - return FALSE; - } - } - - /* delete any old variables */ - if (!fu_efivar_delete_with_glob (FU_EFIVAR_GUID_FWUPDATE, "fwupd*-*", error)) - return FALSE; - - return TRUE; -} - -static gboolean -fu_uefi_device_prepare (FuDevice *device, - FwupdInstallFlags flags, - GError **error) -{ - /* not set in conf, figure it out */ - if (fu_device_get_metadata (device, "EspPath") == NULL) { - g_autofree gchar *guessed = NULL; - g_autofree gchar *detected_esp = NULL; - guessed = fu_uefi_guess_esp_path (error); - if (guessed == NULL) - return FALSE; - - /* udisks objpath */ - if (fu_uefi_udisks_objpath (guessed)) { - FuUefiDevice *self = FU_UEFI_DEVICE (device); - detected_esp = fu_uefi_udisks_objpath_is_mounted (guessed); - if (detected_esp != NULL) { - g_debug ("ESP already mounted @ %s", detected_esp); - /* not mounted */ - } else { - g_debug ("Mounting ESP @ %s", guessed); - detected_esp = fu_uefi_udisks_objpath_mount (guessed, error); - if (detected_esp == NULL) - return FALSE; - self->automounted_esp = TRUE; - } - /* already mounted */ - } else { - detected_esp = g_steal_pointer (&guessed); - } - fu_device_set_metadata (device, "EspPath", detected_esp); - } - - /* sanity checks */ - if (!fu_uefi_device_is_esp_mounted (device, error)) - return FALSE; - if (!fu_uefi_device_cleanup_esp (device, error)) - return FALSE; - if (!fu_uefi_device_check_esp_free (device, error)) - return FALSE; - if (!fu_uefi_check_asset (device, error)) - return FALSE; - - return TRUE; -} - -static gboolean -fu_uefi_device_cleanup (FuDevice *device, - FwupdInstallFlags flags, - GError **error) -{ - FuUefiDevice *self = FU_UEFI_DEVICE (device); - if (self->automounted_esp) { - g_autofree gchar *guessed = NULL; - guessed = fu_uefi_guess_esp_path (error); - if (guessed == NULL) - return FALSE; - g_debug ("Unmounting ESP @ %s", guessed); - if (!fu_uefi_udisks_objpath_umount (guessed, error)) - return FALSE; - self->automounted_esp = FALSE; - /* we will detect again if necessary */ - fu_device_remove_metadata (device, "EspPath"); - } - - return TRUE; -} - -static gboolean -fu_uefi_device_write_firmware (FuDevice *device, - FuFirmware *firmware, - FwupdInstallFlags install_flags, - GError **error) -{ - FuUefiDevice *self = FU_UEFI_DEVICE (device); - FuUefiBootmgrFlags flags = FU_UEFI_BOOTMGR_FLAG_NONE; - const gchar *bootmgr_desc = "Linux Firmware Updater"; - const gchar *esp_path = fu_device_get_metadata (device, "EspPath"); - efi_guid_t guid; - g_autoptr(GBytes) fixed_fw = NULL; - g_autoptr(GBytes) fw = NULL; - g_autofree gchar *basename = NULL; - g_autofree gchar *directory = NULL; - g_autofree gchar *fn = NULL; - g_autofree gchar *varname = fu_uefi_device_build_varname (self); - - /* ensure we have the existing state */ - if (self->fw_class == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "cannot update device info with no GUID"); - return FALSE; - } - - /* get default image */ - fw = fu_firmware_get_image_default_bytes (firmware, error); - if (fw == NULL) - return FALSE; - - /* save the blob to the ESP */ - directory = fu_uefi_get_esp_path_for_os (esp_path); - basename = g_strdup_printf ("fwupd-%s.cap", self->fw_class); - fn = g_build_filename (directory, "fw", basename, NULL); - if (!fu_common_mkdir_parent (fn, error)) - return FALSE; - fixed_fw = fu_uefi_device_fixup_firmware (device, fw, error); - if (fixed_fw == NULL) - return FALSE; - if (!fu_common_set_contents_bytes (fn, fixed_fw, error)) - return FALSE; - - /* set the blob header shared with fwupd.efi */ - if (efi_str_to_guid (self->fw_class, &guid) < 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "failed to get convert GUID"); - return FALSE; - } - if (!fu_uefi_device_write_update_info (self, fn, varname, &guid, error)) - return FALSE; - - /* update the firmware before the bootloader runs */ - if (fu_device_get_metadata_boolean (device, "RequireShimForSecureBoot")) - flags |= FU_UEFI_BOOTMGR_FLAG_USE_SHIM_FOR_SB; - if (fu_device_has_custom_flag (device, "use-shim-unique")) - flags |= FU_UEFI_BOOTMGR_FLAG_USE_SHIM_UNIQUE; - - /* some legacy devices use the old name to deduplicate boot entries */ - if (fu_device_has_custom_flag (device, "use-legacy-bootmgr-desc")) - bootmgr_desc = "Linux-Firmware-Updater"; - if (!fu_uefi_bootmgr_bootnext (esp_path, bootmgr_desc, flags, error)) - return FALSE; - - /* success! */ - return TRUE; -} - -static gboolean -fu_uefi_device_add_system_checksum (FuDevice *device, GError **error) -{ - g_autoptr(FuUefiPcrs) pcrs = fu_uefi_pcrs_new (); - g_autoptr(GError) error_local = NULL; - g_autoptr(GPtrArray) pcr0s = NULL; - - /* get all the PCRs */ - if (!fu_uefi_pcrs_setup (pcrs, &error_local)) { - if (g_error_matches (error_local, - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED) || - g_error_matches (error_local, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND)) { - g_debug ("%s", error_local->message); - return TRUE; - } - g_propagate_error (error, g_steal_pointer (&error_local)); - return FALSE; - } - - /* get all the PCR0s */ - pcr0s = fu_uefi_pcrs_get_checksums (pcrs, 0); - if (pcr0s->len == 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "no PCR0s detected"); - return FALSE; - } - for (guint i = 0; i < pcr0s->len; i++) { - const gchar *checksum = g_ptr_array_index (pcr0s, i); - fu_device_add_checksum (device, checksum); - } - - /* success */ - return TRUE; -} - -static gboolean -fu_uefi_device_probe (FuDevice *device, GError **error) -{ - FuUefiDevice *self = FU_UEFI_DEVICE (device); - FwupdVersionFormat version_format; - g_autofree gchar *devid = NULL; - g_autofree gchar *guid_strup = NULL; - g_autofree gchar *version_lowest = NULL; - g_autofree gchar *version = NULL; - - /* broken sysfs? */ - if (self->fw_class == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "failed to read fw_class"); - return FALSE; - } - - /* add GUID first, as quirks may set the version format */ - fu_device_add_guid (device, self->fw_class); - - /* set versions */ - version_format = fu_device_get_version_format (device); - version = fu_common_version_from_uint32 (self->fw_version, version_format); - fu_device_set_version_format (device, version_format); - fu_device_set_version_raw (device, self->fw_version); - fu_device_set_version (device, version); - if (self->fw_version_lowest != 0) { - version_lowest = fu_common_version_from_uint32 (self->fw_version_lowest, - version_format); - fu_device_set_version_lowest_raw (device, self->fw_version_lowest); - fu_device_set_version_lowest (device, version_lowest); - } - - /* set flags */ - fu_device_add_flag (device, FWUPD_DEVICE_FLAG_INTERNAL); - fu_device_add_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT); - fu_device_add_flag (device, FWUPD_DEVICE_FLAG_REQUIRE_AC); - fu_device_add_flag (device, FWUPD_DEVICE_FLAG_MD_SET_VERFMT); - - /* add icons */ - if (self->kind == FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE) { - /* nothing better in the icon naming spec */ - fu_device_add_icon (device, "audio-card"); - } else { - /* this is probably system firmware */ - fu_device_add_icon (device, "computer"); - fu_device_add_instance_id (device, "main-system-firmware"); - } - - /* set the PCR0 as the device checksum */ - if (self->kind == FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE) { - g_autoptr(GError) error_local = NULL; - fu_device_add_flag (device, FWUPD_DEVICE_FLAG_CAN_VERIFY); - if (!fu_uefi_device_add_system_checksum (device, &error_local)) - g_warning ("Failed to get PCR0s: %s", error_local->message); - } - - /* whether to create a missing header */ - if (self->kind == FU_UEFI_DEVICE_KIND_FMP || - self->kind == FU_UEFI_DEVICE_KIND_DELL_TPM_FIRMWARE) - self->requires_header = FALSE; - else - self->requires_header = TRUE; - - /* Windows seems to be case insensitive, but for convenience we'll - * match the upper case values typically specified in the .inf file */ - guid_strup = g_ascii_strup (self->fw_class, -1); - devid = g_strdup_printf ("UEFI\\RES_{%s}", guid_strup); - fu_device_add_instance_id (device, devid); - return TRUE; -} - -static void -fu_uefi_device_init (FuUefiDevice *self) -{ - fu_device_set_protocol (FU_DEVICE (self), "org.uefi.capsule"); - fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_NUMBER); -} - -static void -fu_uefi_device_finalize (GObject *object) -{ - FuUefiDevice *self = FU_UEFI_DEVICE (object); - - g_free (self->fw_class); - - G_OBJECT_CLASS (fu_uefi_device_parent_class)->finalize (object); -} - -static void -fu_uefi_device_class_init (FuUefiDeviceClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - object_class->finalize = fu_uefi_device_finalize; - klass_device->to_string = fu_uefi_device_to_string; - klass_device->probe = fu_uefi_device_probe; - klass_device->prepare = fu_uefi_device_prepare; - klass_device->write_firmware = fu_uefi_device_write_firmware; - klass_device->cleanup = fu_uefi_device_cleanup; -} - -FuUefiDevice * -fu_uefi_device_new_from_entry (const gchar *entry_path, GError **error) -{ - g_autoptr(FuUefiDevice) self = NULL; - g_autofree gchar *fw_class_fn = NULL; - g_autofree gchar *id = NULL; - - g_return_val_if_fail (entry_path != NULL, NULL); - - /* create object */ - self = g_object_new (FU_TYPE_UEFI_DEVICE, NULL); - - /* read values from sysfs */ - fw_class_fn = g_build_filename (entry_path, "fw_class", NULL); - if (g_file_get_contents (fw_class_fn, &self->fw_class, NULL, NULL)) - g_strdelimit (self->fw_class, "\n", '\0'); - self->capsule_flags = fu_uefi_read_file_as_uint64 (entry_path, "capsule_flags"); - self->kind = fu_uefi_read_file_as_uint64 (entry_path, "fw_type"); - self->fw_version = fu_uefi_read_file_as_uint64 (entry_path, "fw_version"); - self->last_attempt_status = fu_uefi_read_file_as_uint64 (entry_path, "last_attempt_status"); - self->last_attempt_version = fu_uefi_read_file_as_uint64 (entry_path, "last_attempt_version"); - self->fw_version_lowest = fu_uefi_read_file_as_uint64 (entry_path, "lowest_supported_fw_version"); - - /* the hardware instance is not in the ESRT table and we should really - * write the EFI stub to query with FMP -- but we still have not ever - * seen a PCIe device with FMP support... */ - self->fmp_hardware_instance = 0x0; - - /* set ID */ - id = g_strdup_printf ("UEFI-%s-dev%" G_GUINT64_FORMAT, - self->fw_class, self->fmp_hardware_instance); - fu_device_set_id (FU_DEVICE (self), id); - - /* this is invalid */ - if (!fwupd_guid_is_valid (self->fw_class)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "ESRT GUID '%s' was not valid", self->fw_class); - return NULL; - } - - return g_steal_pointer (&self); -} - -FuUefiDevice * -fu_uefi_device_new_from_dev (FuDevice *dev) -{ - const gchar *tmp; - FuUefiDevice *self; - - g_return_val_if_fail (fu_device_get_guid_default (dev) != NULL, NULL); - - /* create virtual object not backed by an ESRT entry */ - self = g_object_new (FU_TYPE_UEFI_DEVICE, NULL); - fu_device_incorporate (FU_DEVICE (self), dev); - self->fw_class = g_strdup (fu_device_get_guid_default (dev)); - tmp = fu_device_get_metadata (dev, FU_DEVICE_METADATA_UEFI_DEVICE_KIND); - self->kind = fu_uefi_device_kind_from_string (tmp); - self->capsule_flags = fu_device_get_metadata_integer (dev, FU_DEVICE_METADATA_UEFI_CAPSULE_FLAGS); - self->fw_version = fu_device_get_metadata_integer (dev, FU_DEVICE_METADATA_UEFI_FW_VERSION); - g_assert (self->fw_class != NULL); - return self; -} - -FuUefiDevice * -fu_uefi_device_new_from_guid (const gchar *guid) -{ - FuUefiDevice *self; - self = g_object_new (FU_TYPE_UEFI_DEVICE, NULL); - self->fw_class = g_strdup (guid); - return self; -} diff -Nru fwupd-1.4.5/plugins/uefi/fu-uefi-device.h fwupd-1.5.8/plugins/uefi/fu-uefi-device.h --- fwupd-1.4.5/plugins/uefi/fu-uefi-device.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/fu-uefi-device.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2018 Richard Hughes - * Copyright (C) 2015-2017 Peter Jones - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include "fu-plugin.h" -#include "fu-uefi-device.h" -#include "fu-uefi-update-info.h" - -#define FU_TYPE_UEFI_DEVICE (fu_uefi_device_get_type ()) -G_DECLARE_FINAL_TYPE (FuUefiDevice, fu_uefi_device, FU, UEFI_DEVICE, FuDevice) - -typedef enum { - FU_UEFI_DEVICE_KIND_UNKNOWN, - FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE, - FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE, - FU_UEFI_DEVICE_KIND_UEFI_DRIVER, - FU_UEFI_DEVICE_KIND_FMP, - FU_UEFI_DEVICE_KIND_DELL_TPM_FIRMWARE, - FU_UEFI_DEVICE_KIND_LAST -} FuUefiDeviceKind; - -typedef enum { - FU_UEFI_DEVICE_STATUS_SUCCESS = 0x00, - FU_UEFI_DEVICE_STATUS_ERROR_UNSUCCESSFUL = 0x01, - FU_UEFI_DEVICE_STATUS_ERROR_INSUFFICIENT_RESOURCES = 0x02, - FU_UEFI_DEVICE_STATUS_ERROR_INCORRECT_VERSION = 0x03, - FU_UEFI_DEVICE_STATUS_ERROR_INVALID_FORMAT = 0x04, - FU_UEFI_DEVICE_STATUS_ERROR_AUTH_ERROR = 0x05, - FU_UEFI_DEVICE_STATUS_ERROR_PWR_EVT_AC = 0x06, - FU_UEFI_DEVICE_STATUS_ERROR_PWR_EVT_BATT = 0x07, - FU_UEFI_DEVICE_STATUS_LAST -} FuUefiDeviceStatus; - -FuUefiDevice *fu_uefi_device_new_from_guid (const gchar *guid); -FuUefiDevice *fu_uefi_device_new_from_entry (const gchar *entry_path, - GError **error); -FuUefiDevice *fu_uefi_device_new_from_dev (FuDevice *dev); -gboolean fu_uefi_device_clear_status (FuUefiDevice *self, - GError **error); -FuUefiDeviceKind fu_uefi_device_get_kind (FuUefiDevice *self); -const gchar *fu_uefi_device_get_guid (FuUefiDevice *self); -guint32 fu_uefi_device_get_version (FuUefiDevice *self); -guint32 fu_uefi_device_get_version_lowest (FuUefiDevice *self); -guint32 fu_uefi_device_get_version_error (FuUefiDevice *self); -guint32 fu_uefi_device_get_capsule_flags (FuUefiDevice *self); -guint64 fu_uefi_device_get_hardware_instance (FuUefiDevice *self); -FuUefiDeviceStatus fu_uefi_device_get_status (FuUefiDevice *self); -const gchar *fu_uefi_device_kind_to_string (FuUefiDeviceKind kind); -const gchar *fu_uefi_device_status_to_string (FuUefiDeviceStatus status); -FuUefiUpdateInfo *fu_uefi_device_load_update_info (FuUefiDevice *self, - GError **error); -gboolean fu_uefi_missing_capsule_header (FuDevice *device); -gboolean fu_uefi_device_write_update_info (FuUefiDevice *self, - const gchar *filename, - const gchar *varname, - const efi_guid_t *guid, - GError **error); diff -Nru fwupd-1.4.5/plugins/uefi/fu-uefi-devpath.c fwupd-1.5.8/plugins/uefi/fu-uefi-devpath.c --- fwupd-1.4.5/plugins/uefi/fu-uefi-devpath.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/fu-uefi-devpath.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,128 +0,0 @@ -/* - * Copyright (C) 2018-2019 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include - -#include "fu-common.h" -#include "fu-uefi-devpath.h" - -#include "fwupd-error.h" - -typedef struct { - guint8 type; - guint8 subtype; - GBytes *data; -} FuUefiDevPath; - -static void -fu_uefi_efi_dp_free (FuUefiDevPath *dp) -{ - if (dp->data != NULL) - g_bytes_unref (dp->data); - g_free (dp); -} - -GBytes * -fu_uefi_devpath_find_data (GPtrArray *dps, guint8 type, guint8 subtype, GError **error) -{ - for (guint i = 0; i < dps->len; i++) { - FuUefiDevPath *dp = g_ptr_array_index (dps, i); - if (dp->type == type && dp->subtype == subtype) - return dp->data; - } - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "no DP with type 0x%02x and subtype 0x%02x", - type, subtype); - return NULL; -} - -GPtrArray * -fu_uefi_devpath_parse (const guint8 *buf, gsize sz, - FuUefiDevpathParseFlags flags, GError **error) -{ - guint16 offset = 0; - g_autoptr(GPtrArray) dps = NULL; - - /* sanity check */ - if (sz < sizeof(efidp_header)) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "const_efidp is corrupt"); - return NULL; - } - - dps = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_uefi_efi_dp_free); - while (1) { - FuUefiDevPath *dp; - const efidp_header *hdr = (efidp_header *) (buf + offset); - guint16 hdr_length = GUINT16_FROM_LE(hdr->length); - - /* check if last entry */ - g_debug ("DP type:0x%02x subtype:0x%02x size:0x%04x", - hdr->type, hdr->subtype, hdr->length); - if (hdr->type == EFIDP_END_TYPE && hdr->subtype == EFIDP_END_ENTIRE) - break; - - /* work around a bug in efi_va_generate_file_device_path_from_esp */ - if (offset + sizeof(efidp_header) + hdr->length > sz) { - hdr_length = 0; - fu_common_dump_full (G_LOG_DOMAIN, "efidp", - buf + offset, sz - offset, 32, - FU_DUMP_FLAGS_SHOW_ADDRESSES); - for (guint16 i = offset + 4; i <= sz - 4; i++) { - if (memcmp (buf + i, "\x7f\xff\x04\x00", 4) == 0) { - hdr_length = i - offset; - g_debug ("found END_ENTIRE at 0x%04x", - (guint) (i - offset)); - break; - } - } - if (hdr_length == 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "DP length invalid and no END_ENTIRE " - "found, possibly data truncation?"); - return NULL; - } - if ((flags & FU_UEFI_DEVPATH_PARSE_FLAG_REPAIR) == 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "DP length invalid, reported 0x%04x, maybe 0x%04x", - hdr->length, hdr_length); - return NULL; - } - g_debug ("DP length invalid! Truncating from 0x%04x to 0x%04x", - hdr->length, hdr_length); - } - - /* add new DP */ - dp = g_new0 (FuUefiDevPath, 1); - dp->type = hdr->type; - dp->subtype = hdr->subtype; - if (hdr_length > 0) - dp->data = g_bytes_new (buf + offset + 4, hdr_length); - g_ptr_array_add (dps, dp); - - /* advance to next DP */ - offset += hdr_length; - if (offset + sizeof(efidp_header) > sz) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "DP length invalid after fixing"); - return NULL; - } - - } - return g_steal_pointer (&dps); -} diff -Nru fwupd-1.4.5/plugins/uefi/fu-uefi-devpath.h fwupd-1.5.8/plugins/uefi/fu-uefi-devpath.h --- fwupd-1.4.5/plugins/uefi/fu-uefi-devpath.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/fu-uefi-devpath.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2018-2019 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include - -typedef enum { - FU_UEFI_DEVPATH_PARSE_FLAG_NONE = 0, - FU_UEFI_DEVPATH_PARSE_FLAG_REPAIR = 1 << 0, - FU_UEFI_DEVPATH_PARSE_FLAG_LAST -} FuUefiDevpathParseFlags; - -GPtrArray *fu_uefi_devpath_parse (const guint8 *buf, - gsize sz, - FuUefiDevpathParseFlags flags, - GError **error); -GBytes *fu_uefi_devpath_find_data (GPtrArray *dps, - guint8 type, - guint8 subtype, - GError **error); diff -Nru fwupd-1.4.5/plugins/uefi/fu-uefi-pcrs.c fwupd-1.5.8/plugins/uefi/fu-uefi-pcrs.c --- fwupd-1.4.5/plugins/uefi/fu-uefi-pcrs.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/fu-uefi-pcrs.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,271 +0,0 @@ -/* - * Copyright (C) 2018 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#ifdef HAVE_TSS2 -#include -#endif - -#include "fu-common.h" -#include "fu-uefi-pcrs.h" -#include "fwupd-error.h" - -typedef struct { - guint idx; - gchar *checksum; -} FuUefiPcrItem; - -struct _FuUefiPcrs { - GObject parent_instance; - GPtrArray *items; /* of FuUefiPcrItem */ -}; - -G_DEFINE_TYPE (FuUefiPcrs, fu_uefi_pcrs, G_TYPE_OBJECT) - -#ifdef HAVE_TSS2 -static void Esys_Finalize_autoptr_cleanup (ESYS_CONTEXT *esys_context) -{ - Esys_Finalize (&esys_context); -} -G_DEFINE_AUTOPTR_CLEANUP_FUNC (ESYS_CONTEXT, Esys_Finalize_autoptr_cleanup) -#endif - -static gboolean -_g_string_isxdigit (GString *str) -{ - for (gsize i = 0; i < str->len; i++) { - if (!g_ascii_isxdigit (str->str[i])) - return FALSE; - } - return TRUE; -} - -static void -fu_uefi_pcrs_parse_line (const gchar *line, gpointer user_data) -{ - FuUefiPcrs *self = FU_UEFI_PCRS (user_data); - FuUefiPcrItem *item; - guint64 idx; - g_autofree gchar *idxstr = NULL; - g_auto(GStrv) split = NULL; - g_autoptr(GString) str = NULL; - - /* split into index:hash */ - if (line == NULL || line[0] == '\0') - return; - split = g_strsplit (line, ":", -1); - if (g_strv_length (split) != 2) { - g_debug ("unexpected format, skipping: %s", line); - return; - } - - /* get index */ - idxstr = fu_common_strstrip (split[0]); - idx = fu_common_strtoull (idxstr); - if (idx > 64) { - g_debug ("unexpected index, skipping: %s", idxstr); - return; - } - - /* parse hash */ - str = g_string_new (split[1]); - fu_common_string_replace (str, " ", ""); - if ((str->len != 40 && str->len != 64) || !_g_string_isxdigit (str)) { - g_debug ("not SHA-1 or SHA-256, skipping: %s", split[1]); - return; - } - g_string_ascii_down (str); - item = g_new0 (FuUefiPcrItem, 1); - item->idx = idx; - item->checksum = g_string_free (g_steal_pointer (&str), FALSE); - g_ptr_array_add (self->items, item); - g_debug ("added PCR-%02u=%s", item->idx, item->checksum); -} - -static gboolean -fu_uefi_pcrs_setup_tpm12 (FuUefiPcrs *self, const gchar *fn_pcrs, GError **error) -{ - g_auto(GStrv) lines = NULL; - g_autofree gchar *buf_pcrs = NULL; - - /* get entire contents */ - if (!g_file_get_contents (fn_pcrs, &buf_pcrs, NULL, error)) - return FALSE; - - /* find PCR lines */ - lines = g_strsplit (buf_pcrs, "\n", -1); - for (guint i = 0; lines[i] != NULL; i++) { - if (g_str_has_prefix (lines[i], "PCR-")) - fu_uefi_pcrs_parse_line (lines[i] + 4, self); - } - return TRUE; -} - -static gboolean -fu_uefi_pcrs_setup_tpm20 (FuUefiPcrs *self, GError **error) -{ -#ifdef HAVE_TSS2 - TSS2_RC rc; - g_autoptr(ESYS_CONTEXT) ctx = NULL; - g_autofree TPMS_CAPABILITY_DATA *capability_data = NULL; - TPML_PCR_SELECTION pcr_selection_in = { 0, }; - g_autofree TPML_DIGEST *pcr_values = NULL; - - /* suppress warning messages about missing TCTI libraries for tpm2-tss <2.3 */ - if (g_getenv ("FWUPD_UEFI_VERBOSE") == NULL) { - g_setenv ("TSS2_LOG", "esys+error,tcti+none", FALSE); - } - - rc = Esys_Initialize (&ctx, NULL, NULL); - if (rc != TSS2_RC_SUCCESS) { - g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, - "failed to initialize TPM library"); - return FALSE; - } - rc = Esys_Startup (ctx, TPM2_SU_CLEAR); - if (rc != TSS2_RC_SUCCESS) { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - "failed to initialize TPM"); - return FALSE; - } - - /* get hash algorithms supported by the TPM */ - rc = Esys_GetCapability (ctx, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, - TPM2_CAP_PCRS, 0, 1, NULL, &capability_data); - if (rc != TSS2_RC_SUCCESS) { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - "failed to get hash algorithms supported by TPM"); - return FALSE; - } - - /* fetch PCR 0 for every supported hash algorithm */ - pcr_selection_in.count = capability_data->data.assignedPCR.count; - for (guint i = 0; i < pcr_selection_in.count; i++) { - pcr_selection_in.pcrSelections[i].hash = - capability_data->data.assignedPCR.pcrSelections[i].hash; - pcr_selection_in.pcrSelections[i].sizeofSelect = - capability_data->data.assignedPCR.pcrSelections[i].sizeofSelect; - pcr_selection_in.pcrSelections[i].pcrSelect[0] = 0b00000001; - } - - rc = Esys_PCR_Read (ctx, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, - &pcr_selection_in, NULL, NULL, &pcr_values); - if (rc != TSS2_RC_SUCCESS) { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - "failed to read PCR values from TPM"); - return FALSE; - } - - for (guint i = 0; i < pcr_values->count; i++) { - FuUefiPcrItem *item; - g_autoptr(GString) str = NULL; - - str = g_string_new (NULL); - for (guint j = 0; j < pcr_values->digests[i].size; j++) { - gint64 val = pcr_values->digests[i].buffer[j]; - if (val > 0) - g_string_append_printf (str, "%02x", pcr_values->digests[i].buffer[j]); - } - if (str->len > 0) { - item = g_new0 (FuUefiPcrItem, 1); - item->idx = 0; /* constant PCR index 0, since we only read this single PCR */ - item->checksum = g_string_free (g_steal_pointer (&str), FALSE); - g_ptr_array_add (self->items, item); - g_debug ("added PCR-%02u=%s", item->idx, item->checksum); - } - } -#endif - - /* success */ - return TRUE; -} - -gboolean -fu_uefi_pcrs_setup (FuUefiPcrs *self, GError **error) -{ - g_autofree gchar *devpath = NULL; - g_autofree gchar *sysfstpmdir = NULL; - g_autofree gchar *fn_pcrs = NULL; - - g_return_val_if_fail (FU_IS_UEFI_PCRS (self), FALSE); - - /* look for TPM 1.2 */ - sysfstpmdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_TPM); - devpath = g_build_filename (sysfstpmdir, "tpm0", NULL); - fn_pcrs = g_build_filename (devpath, "pcrs", NULL); - if (g_file_test (fn_pcrs, G_FILE_TEST_EXISTS) && - g_getenv ("FWUPD_FORCE_TPM2") == NULL) { - if (!fu_uefi_pcrs_setup_tpm12 (self, fn_pcrs, error)) - return FALSE; - - /* assume TPM 2.0 */ - } else { - if (!fu_uefi_pcrs_setup_tpm20 (self, error)) - return FALSE; - } - - /* check we got anything */ - if (self->items->len == 0) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - "no TPMxx measurements found"); - return FALSE; - } - - /* success */ - return TRUE; -} - -GPtrArray * -fu_uefi_pcrs_get_checksums (FuUefiPcrs *self, guint idx) -{ - g_autoptr(GPtrArray) array = g_ptr_array_new_with_free_func (g_free); - g_return_val_if_fail (FU_IS_UEFI_PCRS (self), NULL); - for (guint i = 0; i < self->items->len; i++) { - FuUefiPcrItem *item = g_ptr_array_index (self->items, i); - if (item->idx == idx) - g_ptr_array_add (array, g_strdup (item->checksum)); - } - return g_steal_pointer (&array); -} - -static void -fu_uefi_pcrs_item_free (FuUefiPcrItem *item) -{ - g_free (item->checksum); - g_free (item); -} - -static void -fu_uefi_pcrs_finalize (GObject *object) -{ - FuUefiPcrs *self = FU_UEFI_PCRS (object); - g_ptr_array_unref (self->items); - G_OBJECT_CLASS (fu_uefi_pcrs_parent_class)->finalize (object); -} - -static void -fu_uefi_pcrs_class_init (FuUefiPcrsClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - object_class->finalize = fu_uefi_pcrs_finalize; -} - -static void -fu_uefi_pcrs_init (FuUefiPcrs *self) -{ - self->items = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_uefi_pcrs_item_free); -} - -FuUefiPcrs * -fu_uefi_pcrs_new (void) -{ - FuUefiPcrs *self; - self = g_object_new (FU_TYPE_UEFI_PCRS, NULL); - return FU_UEFI_PCRS (self); -} diff -Nru fwupd-1.4.5/plugins/uefi/fu-uefi-pcrs.h fwupd-1.5.8/plugins/uefi/fu-uefi-pcrs.h --- fwupd-1.4.5/plugins/uefi/fu-uefi-pcrs.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/fu-uefi-pcrs.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -/* - * Copyright (C) 2017 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#define FU_TYPE_UEFI_PCRS (fu_uefi_pcrs_get_type ()) -G_DECLARE_FINAL_TYPE (FuUefiPcrs, fu_uefi_pcrs, FU, UEFI_PCRS, GObject) - -FuUefiPcrs *fu_uefi_pcrs_new (void); -gboolean fu_uefi_pcrs_setup (FuUefiPcrs *self, - GError **error); -GPtrArray *fu_uefi_pcrs_get_checksums (FuUefiPcrs *self, - guint idx); diff -Nru fwupd-1.4.5/plugins/uefi/fu-uefi-tool.c fwupd-1.5.8/plugins/uefi/fu-uefi-tool.c --- fwupd-1.4.5/plugins/uefi/fu-uefi-tool.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/fu-uefi-tool.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,347 +0,0 @@ -/* - * Copyright (C) 2018 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include - -#include "fu-ucs2.h" -#include "fu-uefi-common.h" -#include "fu-uefi-device.h" -#include "fu-uefi-update-info.h" -#include "fu-efivar.h" - -/* custom return code */ -#define EXIT_NOTHING_TO_DO 2 - -typedef struct { - GCancellable *cancellable; - GMainLoop *loop; - GOptionContext *context; -} FuUtilPrivate; - -static void -fu_util_ignore_cb (const gchar *log_domain, GLogLevelFlags log_level, - const gchar *message, gpointer user_data) -{ -} - -static void -fu_util_private_free (FuUtilPrivate *priv) -{ - if (priv->context != NULL) - g_option_context_free (priv->context); - g_free (priv); -} - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-function" -G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuUtilPrivate, fu_util_private_free) -#pragma clang diagnostic pop - -int -main (int argc, char *argv[]) -{ - gboolean action_enable = FALSE; - gboolean action_info = FALSE; - gboolean action_list = FALSE; - gboolean action_log = FALSE; - gboolean action_set_debug = FALSE; - gboolean action_supported = FALSE; - gboolean action_unset_debug = FALSE; - gboolean action_version = FALSE; - gboolean ret; - gboolean verbose = FALSE; - g_autofree gchar *apply = FALSE; - g_autofree gchar *esp_path = NULL; - g_autofree gchar *flags = FALSE; - g_autoptr(FuUtilPrivate) priv = g_new0 (FuUtilPrivate, 1); - g_autoptr(GError) error = NULL; - g_autoptr(GPtrArray) devices = NULL; - const GOptionEntry options[] = { - { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, - /* TRANSLATORS: command line option */ - _("Show extra debugging information"), NULL }, - { "version", '\0', 0, G_OPTION_ARG_NONE, &action_version, - /* TRANSLATORS: command line option */ - _("Display version"), NULL }, - { "log", 'L', 0, G_OPTION_ARG_NONE, &action_log, - /* TRANSLATORS: command line option */ - _("Show the debug log from the last attempted update"), NULL }, - { "list", 'l', 0, G_OPTION_ARG_NONE, &action_list, - /* TRANSLATORS: command line option */ - _("List supported firmware updates"), NULL }, - { "supported", 's', 0, G_OPTION_ARG_NONE, &action_supported, - /* TRANSLATORS: command line option */ - _("Query for firmware update support"), NULL }, - { "info", 'i', 0, G_OPTION_ARG_NONE, &action_info, - /* TRANSLATORS: command line option */ - _("Show the information of firmware update status"), NULL }, - { "enable", 'e', 0, G_OPTION_ARG_NONE, &action_enable, - /* TRANSLATORS: command line option */ - _("Enable firmware update support on supported systems"), NULL }, - { "esp-path", 'p', 0, G_OPTION_ARG_STRING, &esp_path, - /* TRANSLATORS: command line option */ - _("Override the default ESP path"), "PATH" }, - { "set-debug", 'd', 0, G_OPTION_ARG_NONE, &action_set_debug, - /* TRANSLATORS: command line option */ - _("Set the debugging flag during update"), NULL }, - { "unset-debug", 'D', 0, G_OPTION_ARG_NONE, &action_unset_debug, - /* TRANSLATORS: command line option */ - _("Unset the debugging flag during update"), NULL }, - { "apply", 'a', 0, G_OPTION_ARG_STRING, &apply, - /* TRANSLATORS: command line option */ - _("Apply firmware updates"), "GUID" }, - { "flags", 'f', 0, G_OPTION_ARG_STRING, &flags, - /* TRANSLATORS: command line option */ - _("Use quirk flags when installing firmware"), NULL }, - { NULL} - }; - - setlocale (LC_ALL, ""); - - bindtextdomain (GETTEXT_PACKAGE, FWUPD_LOCALEDIR); - bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); - textdomain (GETTEXT_PACKAGE); - - /* ensure root user */ -#ifdef HAVE_GETUID - if (getuid () != 0 || geteuid () != 0) - /* TRANSLATORS: we're poking around as a power user */ - g_printerr ("%s\n", _("This program may only work correctly as root")); -#endif - - /* get a action_list of the commands */ - priv->context = g_option_context_new (NULL); - g_option_context_set_description (priv->context, - "This tool allows an administrator to debug UpdateCapsule operation."); - - /* TRANSLATORS: program name */ - g_set_application_name (_("UEFI Firmware Utility")); - g_option_context_add_main_entries (priv->context, options, NULL); - ret = g_option_context_parse (priv->context, &argc, &argv, &error); - if (!ret) { - /* TRANSLATORS: the user didn't read the man page */ - g_print ("%s: %s\n", _("Failed to parse arguments"), - error->message); - return EXIT_FAILURE; - } - - /* set verbose? */ - if (verbose) { - g_setenv ("G_MESSAGES_DEBUG", "all", FALSE); - } else { - g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, - fu_util_ignore_cb, NULL); - } - - /* nothing specified */ - if (!action_enable && !action_info && !action_list && !action_log && - !action_set_debug && !action_supported && !action_unset_debug && - !action_version && apply == NULL) { - g_autofree gchar *tmp = NULL; - tmp = g_option_context_get_help (priv->context, TRUE, NULL); - g_printerr ("%s\n\n%s", _("No action specified!"), tmp); - return EXIT_FAILURE; - } - - /* action_version first */ - if (action_version) - g_print ("fwupd version: %s\n", PACKAGE_VERSION); - - /* override the default ESP path */ - if (esp_path != NULL) { - if (!fu_uefi_check_esp_path (esp_path, &error)) { - /* TRANSLATORS: ESP is EFI System Partition */ - g_print ("%s: %s\n", _("ESP specified was not valid"), - error->message); - return EXIT_FAILURE; - } - } - - /* show the debug action_log from the last attempted update */ - if (action_log) { - gsize sz = 0; - g_autofree guint8 *buf = NULL; - g_autofree guint16 *buf_ucs2 = NULL; - g_autofree gchar *str = NULL; - g_autoptr(GError) error_local = NULL; - if (!fu_efivar_get_data (FU_EFIVAR_GUID_FWUPDATE, - "FWUPDATE_DEBUG_LOG", - &buf, &sz, NULL, - &error_local)) { - g_printerr ("failed: %s\n", error_local->message); - return EXIT_FAILURE; - } - buf_ucs2 = g_new0 (guint16, (sz / 2) + 1); - memcpy (buf_ucs2, buf, sz); - str = fu_ucs2_to_uft8 (buf_ucs2, sz / 2); - g_print ("%s", str); - } - - if (action_list || action_supported || action_info) { - g_autoptr(GPtrArray) entries = NULL; - g_autofree gchar *esrt_path = NULL; - g_autofree gchar *sysfsfwdir = NULL; - g_autoptr(GError) error_local = NULL; - - /* get the directory of ESRT entries */ - sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); - esrt_path = g_build_filename (sysfsfwdir, "efi", "esrt", NULL); - entries = fu_uefi_get_esrt_entry_paths (esrt_path, &error_local); - if (entries == NULL) { - g_printerr ("failed: %s\n", error_local->message); - return EXIT_FAILURE; - } - - /* add each device */ - devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - for (guint i = 0; i < entries->len; i++) { - const gchar *path = g_ptr_array_index (entries, i); - g_autoptr(GError) error_parse = NULL; - g_autoptr(FuUefiDevice) dev = fu_uefi_device_new_from_entry (path, &error_parse); - if (dev == NULL) { - g_warning ("failed to parse %s: %s", - path, error_parse->message); - continue; - } - if (esp_path != NULL) - fu_device_set_metadata (FU_DEVICE (dev), "EspPath", esp_path); - g_ptr_array_add (devices, g_object_ref (dev)); - } - } - - /* action_list action_supported firmware updates */ - if (action_list) { - for (guint i = 0; i < devices->len; i++) { - FuUefiDevice *dev = g_ptr_array_index (devices, i); - g_print ("%s type, {%s} version %" G_GUINT32_FORMAT " can be updated " - "to any version above %" G_GUINT32_FORMAT "\n", - fu_uefi_device_kind_to_string (fu_uefi_device_get_kind (dev)), - fu_uefi_device_get_guid (dev), - fu_uefi_device_get_version (dev), - fu_uefi_device_get_version_lowest (dev) - 1); - } - } - - /* query for firmware update support */ - if (action_supported) { - if (devices->len > 0) { - g_print ("%s\n", _("Firmware updates are supported on this machine.")); - } else { - g_print ("%s\n", _("Firmware updates are not supported on this machine.")); - } - } - - /* show the information of firmware update status */ - if (action_info) { - for (guint i = 0; i < devices->len; i++) { - FuUefiDevice *dev = g_ptr_array_index (devices, i); - g_autoptr(FuUefiUpdateInfo) info = NULL; - g_autoptr(GError) error_local = NULL; - - /* load any existing update info */ - info = fu_uefi_device_load_update_info (dev, &error_local); - if (info == NULL) { - g_printerr ("failed: %s\n", error_local->message); - continue; - } - g_print ("Information for the update status entry %u:\n", i); - g_print (" Information Version: %" G_GUINT32_FORMAT "\n", - fu_uefi_update_info_get_version (info)); - g_print (" Firmware GUID: {%s}\n", - fu_uefi_update_info_get_guid (info)); - g_print (" Capsule Flags: 0x%08" G_GUINT32_FORMAT "x\n", - fu_uefi_update_info_get_capsule_flags (info)); - g_print (" Hardware Instance: %" G_GUINT64_FORMAT "\n", - fu_uefi_update_info_get_hw_inst (info)); - g_print (" Update Status: %s\n", - fu_uefi_update_info_status_to_string (fu_uefi_update_info_get_status (info))); - g_print (" Capsule File Path: %s\n\n", - fu_uefi_update_info_get_capsule_fn (info)); - } - } - - /* action_enable firmware update support on action_supported systems */ - if (action_enable) { - g_printerr ("Unsupported, use `fwupdmgr unlock`\n"); - return EXIT_FAILURE; - } - - /* set the debugging flag during update */ - if (action_set_debug) { - const guint8 data = 1; - g_autoptr(GError) error_local = NULL; - if (!fu_efivar_set_data (FU_EFIVAR_GUID_FWUPDATE, - "FWUPDATE_VERBOSE", - &data, sizeof(data), - EFI_VARIABLE_NON_VOLATILE | - EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS, - &error_local)) { - g_printerr ("failed: %s\n", error_local->message); - return EXIT_FAILURE; - } - g_print ("%s\n", _("Enabled fwupdate debugging")); - } - - /* unset the debugging flag during update */ - if (action_unset_debug) { - g_autoptr(GError) error_local = NULL; - if (!fu_efivar_delete (FU_EFIVAR_GUID_FWUPDATE, - "FWUPDATE_VERBOSE", - &error_local)) { - g_printerr ("failed: %s\n", error_local->message); - return EXIT_FAILURE; - } - g_print ("%s\n", _("Disabled fwupdate debugging")); - } - - /* apply firmware updates */ - if (apply != NULL) { - g_autoptr(FuUefiDevice) dev = fu_uefi_device_new_from_guid (apply); - g_autoptr(GError) error_local = NULL; - g_autoptr(GBytes) fw = NULL; - - if (argv[1] == NULL) { - g_printerr ("capsule filename required\n"); - return EXIT_FAILURE; - } - fw = fu_common_get_contents_bytes (argv[1], &error_local); - if (fw == NULL) { - g_printerr ("failed: %s\n", error_local->message); - return EXIT_FAILURE; - } - if (flags != NULL) - fu_device_set_custom_flags (FU_DEVICE (dev), flags); - if (!fu_device_prepare (FU_DEVICE (dev), - FWUPD_INSTALL_FLAG_NONE, - &error_local)) { - g_printerr ("failed: %s\n", error_local->message); - return EXIT_FAILURE; - } - if (!fu_device_write_firmware (FU_DEVICE (dev), fw, - FWUPD_INSTALL_FLAG_NONE, - &error_local)) { - g_printerr ("failed: %s\n", error_local->message); - return EXIT_FAILURE; - } - if (!fu_device_cleanup (FU_DEVICE (dev), - FWUPD_INSTALL_FLAG_NONE, - &error_local)) { - g_printerr ("failed: %s\n", error_local->message); - return EXIT_FAILURE; - } - } - - /* success */ - return EXIT_SUCCESS; -} diff -Nru fwupd-1.4.5/plugins/uefi/fu-uefi-udisks.c fwupd-1.5.8/plugins/uefi/fu-uefi-udisks.c --- fwupd-1.4.5/plugins/uefi/fu-uefi-udisks.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/fu-uefi-udisks.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,190 +0,0 @@ -/* - * Copyright (C) 2019 Mario Limonciello - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include - -#include "fu-uefi-udisks.h" -#include "fwupd-common.h" -#include "fwupd-error.h" - -#define UDISKS_DBUS_SERVICE "org.freedesktop.UDisks2" -#define UDISKS_DBUS_PATH "/org/freedesktop/UDisks2/Manager" -#define UDISKS_DBUS_MANAGER_INTERFACE "org.freedesktop.UDisks2.Manager" -#define UDISKS_DBUS_PART_INTERFACE "org.freedesktop.UDisks2.Partition" -#define UDISKS_DBUS_FILE_INTERFACE "org.freedesktop.UDisks2.Filesystem" -#define ESP_DISK_TYPE "c12a7328-f81f-11d2-ba4b-00a0c93ec93b" - -gboolean -fu_uefi_udisks_objpath (const gchar *path) -{ - return g_str_has_prefix (path, "/org/freedesktop/UDisks2/"); -} - -static GDBusProxy * -fu_uefi_udisks_get_dbus_proxy (const gchar *path, const gchar *interface, - GError **error) -{ - g_autoptr(GDBusConnection) connection = NULL; - g_autoptr(GDBusProxy) proxy = NULL; - - connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); - if (connection == NULL) { - g_prefix_error (error, "failed to get bus: "); - return NULL; - } - proxy = g_dbus_proxy_new_sync (connection, - G_DBUS_PROXY_FLAGS_NONE, NULL, - UDISKS_DBUS_SERVICE, - path, - interface, - NULL, error); - if (proxy == NULL) { - g_prefix_error (error, "failed to find %s: ", UDISKS_DBUS_SERVICE); - return NULL; - } - return g_steal_pointer (&proxy); -} - - -GPtrArray * -fu_uefi_udisks_get_block_devices (GError **error) -{ - g_autoptr(GVariant) output = NULL; - g_autoptr(GDBusProxy) proxy = NULL; - g_autoptr(GPtrArray) devices = NULL; - g_autoptr(GVariantIter) iter = NULL; - GVariant *input; - GVariantBuilder builder; - const gchar *obj; - - proxy = fu_uefi_udisks_get_dbus_proxy (UDISKS_DBUS_PATH, - UDISKS_DBUS_MANAGER_INTERFACE, - error); - if (proxy == NULL) - return NULL; - g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); - input = g_variant_new ("(a{sv})", &builder); - output = g_dbus_proxy_call_sync (proxy, - "GetBlockDevices", g_variant_ref (input), - G_DBUS_CALL_FLAGS_NONE, - -1, NULL, error); - if (output == NULL) - return NULL; - devices = g_ptr_array_new_with_free_func (g_free); - g_variant_get (output, "(ao)", &iter); - while (g_variant_iter_next (iter, "o", &obj)) - g_ptr_array_add (devices, g_strdup (obj)); - - return g_steal_pointer (&devices); -} - -gboolean -fu_uefi_udisks_objpath_is_esp (const gchar *obj) -{ - g_autoptr(GDBusProxy) proxy = NULL; - g_autoptr(GError) error_local = NULL; - g_autoptr(GVariant) val = NULL; - const gchar *str; - - proxy = fu_uefi_udisks_get_dbus_proxy (obj, - UDISKS_DBUS_PART_INTERFACE, - &error_local); - if (proxy == NULL) { - g_warning ("Failed to initialize d-bus proxy: %s", - error_local->message); - return FALSE; - } - val = g_dbus_proxy_get_cached_property (proxy, "Type"); - if (val == NULL) - return FALSE; - - g_variant_get (val, "s", &str); - return g_strcmp0 (str, ESP_DISK_TYPE) == 0; -} - -gboolean -fu_uefi_udisks_objpath_umount (const gchar *path, GError **error) -{ - GVariant *input; - GVariantBuilder builder; - g_autoptr(GDBusProxy) proxy = NULL; - g_autoptr(GVariant) val = NULL; - - g_return_val_if_fail (fu_uefi_udisks_objpath (path), FALSE); - - proxy = fu_uefi_udisks_get_dbus_proxy (path, - UDISKS_DBUS_FILE_INTERFACE, - error); - if (proxy == NULL) - return FALSE; - - g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); - input = g_variant_new ("(a{sv})", &builder); - val = g_dbus_proxy_call_sync (proxy, - "Unmount", input, - G_DBUS_CALL_FLAGS_NONE, - -1, NULL, error); - if (val == NULL) - return FALSE; - return TRUE; -} - -gchar * -fu_uefi_udisks_objpath_mount (const gchar *path, GError **error) -{ - GVariant *input; - GVariantBuilder builder; - const gchar *str; - g_autoptr(GDBusProxy) proxy = NULL; - g_autoptr(GVariant) val = NULL; - - g_return_val_if_fail (fu_uefi_udisks_objpath (path), NULL); - - proxy = fu_uefi_udisks_get_dbus_proxy (path, - UDISKS_DBUS_FILE_INTERFACE, - error); - if (proxy == NULL) - return NULL; - - g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); - input = g_variant_new ("(a{sv})", &builder); - val = g_dbus_proxy_call_sync (proxy, - "Mount", input, - G_DBUS_CALL_FLAGS_NONE, - -1, NULL, error); - if (val == NULL) - return NULL; - g_variant_get (val, "(s)", &str); - - return g_strdup (str); -} - -gchar * -fu_uefi_udisks_objpath_is_mounted (const gchar *path) -{ - const gchar **mountpoints = NULL; - g_autoptr(GDBusProxy) proxy = NULL; - g_autoptr(GVariant) val = NULL; - g_autoptr(GError) error_local = NULL; - - g_return_val_if_fail (fu_uefi_udisks_objpath (path), NULL); - - proxy = fu_uefi_udisks_get_dbus_proxy (path, - UDISKS_DBUS_FILE_INTERFACE, - &error_local); - if (proxy == NULL) { - g_warning ("%s", error_local->message); - return NULL; - } - val = g_dbus_proxy_get_cached_property (proxy, "MountPoints"); - if (val == NULL) - return NULL; - mountpoints = g_variant_get_bytestring_array (val, NULL); - - return g_strdup (mountpoints[0]); -} diff -Nru fwupd-1.4.5/plugins/uefi/fu-uefi-udisks.h fwupd-1.5.8/plugins/uefi/fu-uefi-udisks.h --- fwupd-1.4.5/plugins/uefi/fu-uefi-udisks.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/fu-uefi-udisks.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -/* - * Copyright (C) 2019 Mario Limonciello - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -GPtrArray *fu_uefi_udisks_get_block_devices (GError **error); -gboolean fu_uefi_udisks_objpath (const gchar *path); -gboolean fu_uefi_udisks_objpath_is_esp (const gchar *obj); -gchar *fu_uefi_udisks_objpath_mount (const gchar *path, - GError **error); -gboolean fu_uefi_udisks_objpath_umount (const gchar *path, - GError **error); -gchar *fu_uefi_udisks_objpath_is_mounted (const gchar *path); diff -Nru fwupd-1.4.5/plugins/uefi/fu-uefi-update-info.c fwupd-1.5.8/plugins/uefi/fu-uefi-update-info.c --- fwupd-1.4.5/plugins/uefi/fu-uefi-update-info.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/fu-uefi-update-info.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,186 +0,0 @@ -/* - * Copyright (C) 2018 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#include "config.h" - -#include "fu-common.h" -#include "fu-uefi-devpath.h" -#include "fu-uefi-update-info.h" -#include "fu-uefi-common.h" -#include "fu-ucs2.h" - -#include "fwupd-error.h" - -struct _FuUefiUpdateInfo { - GObject parent_instance; - guint32 version; - gchar *guid; - gchar *capsule_fn; - guint32 capsule_flags; - guint64 hw_inst; - FuUefiUpdateInfoStatus status; -}; - -G_DEFINE_TYPE (FuUefiUpdateInfo, fu_uefi_update_info, G_TYPE_OBJECT) - -const gchar * -fu_uefi_update_info_status_to_string (FuUefiUpdateInfoStatus status) -{ - if (status == FU_UEFI_UPDATE_INFO_STATUS_ATTEMPT_UPDATE) - return "attempt-update"; - if (status == FU_UEFI_UPDATE_INFO_STATUS_ATTEMPTED) - return "attempted"; - return "unknown"; -} - -static gchar * -fu_uefi_update_info_parse_dp (const guint8 *buf, gsize sz, GError **error) -{ - GBytes *dp_data; - const gchar *data; - gsize ucs2sz = 0; - g_autofree gchar *relpath = NULL; - g_autofree guint16 *ucs2file = NULL; - g_autoptr(GPtrArray) dps = NULL; - - g_return_val_if_fail (buf != NULL, NULL); - g_return_val_if_fail (sz != 0, NULL); - - /* get all headers */ - dps = fu_uefi_devpath_parse (buf, sz, FU_UEFI_DEVPATH_PARSE_FLAG_REPAIR, error); - if (dps == NULL) - return NULL; - dp_data = fu_uefi_devpath_find_data (dps, - EFIDP_MEDIA_TYPE, - EFIDP_MEDIA_FILE, - error); - if (dp_data == NULL) - return NULL; - - /* convert to UTF-8 */ - data = g_bytes_get_data (dp_data, &ucs2sz); - ucs2file = g_new0 (guint16, (ucs2sz / 2) + 1); - memcpy (ucs2file, data, ucs2sz); - relpath = fu_ucs2_to_uft8 (ucs2file, ucs2sz / sizeof (guint16)); - if (relpath == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "cannot convert to UTF-8"); - return NULL; - } - g_strdelimit (relpath, "\\", '/'); - return g_steal_pointer (&relpath); -} - -gboolean -fu_uefi_update_info_parse (FuUefiUpdateInfo *self, const guint8 *buf, gsize sz, GError **error) -{ - efi_update_info_t info; - efi_guid_t guid_tmp; - - g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), FALSE); - - if (sz < sizeof(efi_update_info_t)) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "EFI variable is corrupt"); - return FALSE; - } - memcpy (&info, buf, sizeof(info)); - self->version = info.update_info_version; - self->capsule_flags = info.capsule_flags; - self->hw_inst = info.hw_inst; - self->status = info.status; - memcpy (&guid_tmp, &info.guid, sizeof(efi_guid_t)); - if (efi_guid_to_str (&guid_tmp, &self->guid) < 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "failed to convert GUID"); - return FALSE; - } - if (sz > sizeof(efi_update_info_t)) { - self->capsule_fn = fu_uefi_update_info_parse_dp (buf + sizeof(efi_update_info_t), - sz - sizeof(efi_update_info_t), - error); - if (self->capsule_fn == NULL) - return FALSE; - } - return TRUE; -} - -const gchar * -fu_uefi_update_info_get_guid (FuUefiUpdateInfo *self) -{ - g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), NULL); - return self->guid; -} - -const gchar * -fu_uefi_update_info_get_capsule_fn (FuUefiUpdateInfo *self) -{ - g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), NULL); - return self->capsule_fn; -} - -guint32 -fu_uefi_update_info_get_version (FuUefiUpdateInfo *self) -{ - g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), 0); - return self->version; -} - -guint32 -fu_uefi_update_info_get_capsule_flags (FuUefiUpdateInfo *self) -{ - g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), 0); - return self->capsule_flags; -} - -guint64 -fu_uefi_update_info_get_hw_inst (FuUefiUpdateInfo *self) -{ - g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), 0); - return self->hw_inst; -} - -FuUefiUpdateInfoStatus -fu_uefi_update_info_get_status (FuUefiUpdateInfo *self) -{ - g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), 0); - return self->status; -} - -static void -fu_uefi_update_info_finalize (GObject *object) -{ - FuUefiUpdateInfo *self = FU_UEFI_UPDATE_INFO (object); - g_free (self->guid); - g_free (self->capsule_fn); - G_OBJECT_CLASS (fu_uefi_update_info_parent_class)->finalize (object); -} - -static void -fu_uefi_update_info_class_init (FuUefiUpdateInfoClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - object_class->finalize = fu_uefi_update_info_finalize; -} - -static void -fu_uefi_update_info_init (FuUefiUpdateInfo *self) -{ -} - -FuUefiUpdateInfo * -fu_uefi_update_info_new (void) -{ - FuUefiUpdateInfo *self; - self = g_object_new (FU_TYPE_UEFI_UPDATE_INFO, NULL); - return FU_UEFI_UPDATE_INFO (self); -} diff -Nru fwupd-1.4.5/plugins/uefi/fu-uefi-update-info.h fwupd-1.5.8/plugins/uefi/fu-uefi-update-info.h --- fwupd-1.4.5/plugins/uefi/fu-uefi-update-info.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/fu-uefi-update-info.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2018 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#define FU_TYPE_UEFI_UPDATE_INFO (fu_uefi_update_info_get_type ()) -G_DECLARE_FINAL_TYPE (FuUefiUpdateInfo, fu_uefi_update_info, FU, UEFI_UPDATE_INFO, GObject) - -typedef enum { - FU_UEFI_UPDATE_INFO_STATUS_ATTEMPT_UPDATE = 0x00000001, - FU_UEFI_UPDATE_INFO_STATUS_ATTEMPTED = 0x00000002, -} FuUefiUpdateInfoStatus; - -const gchar *fu_uefi_update_info_status_to_string (FuUefiUpdateInfoStatus status); - -FuUefiUpdateInfo *fu_uefi_update_info_new (void); -gboolean fu_uefi_update_info_parse (FuUefiUpdateInfo *self, - const guint8 *buf, - gsize sz, - GError **error); -guint32 fu_uefi_update_info_get_version (FuUefiUpdateInfo *self); -const gchar *fu_uefi_update_info_get_guid (FuUefiUpdateInfo *self); -const gchar *fu_uefi_update_info_get_capsule_fn (FuUefiUpdateInfo *self); -guint32 fu_uefi_update_info_get_capsule_flags (FuUefiUpdateInfo *self); -guint64 fu_uefi_update_info_get_hw_inst (FuUefiUpdateInfo *self); -FuUefiUpdateInfoStatus fu_uefi_update_info_get_status (FuUefiUpdateInfo *self); diff -Nru fwupd-1.4.5/plugins/uefi/meson.build fwupd-1.5.8/plugins/uefi/meson.build --- fwupd-1.4.5/plugins/uefi/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/meson.build 1970-01-01 00:00:00.000000000 +0000 @@ -1,143 +0,0 @@ -subdir('efi') - -cargs = ['-DG_LOG_DOMAIN="FuPluginUefi"'] - -efi_os_dir = get_option('efi_os_dir') -if efi_os_dir != '' - cargs += '-DEFI_OS_DIR="' + efi_os_dir + '"' -endif - -install_data(['uefi.quirk'], - install_dir: join_paths(datadir, 'fwupd', 'quirks.d')) - -shared_module('fu_plugin_uefi', - fu_hash, - sources : [ - 'fu-plugin-uefi.c', - 'fu-uefi-bgrt.c', - 'fu-ucs2.c', - 'fu-uefi-bootmgr.c', - 'fu-uefi-common.c', - 'fu-uefi-device.c', - 'fu-uefi-devpath.c', - 'fu-uefi-pcrs.c', - 'fu-uefi-update-info.c', - 'fu-uefi-udisks.c', - ], - include_directories : [ - root_incdir, - fwupd_incdir, - fwupdplugin_incdir, - ], - install : true, - install_dir: plugin_dir, - link_with : [ - fwupd, - fwupdplugin, - ], - c_args : cargs, - dependencies : [ - plugin_deps, - efivar, - efiboot, - tpm2tss, - ], -) - -fwupdate = executable( - 'fwupdate', - resources_src, - fu_hash, - sources : [ - 'fu-uefi-tool.c', - 'fu-uefi-bgrt.c', - 'fu-ucs2.c', - 'fu-uefi-bootmgr.c', - 'fu-uefi-common.c', - 'fu-uefi-device.c', - 'fu-uefi-devpath.c', - 'fu-uefi-pcrs.c', - 'fu-uefi-update-info.c', - 'fu-uefi-udisks.c', - ], - include_directories : [ - root_incdir, - fwupd_incdir, - fwupdplugin_incdir, - ], - dependencies : [ - libxmlb, - giounix, - gusb, - gudev, - efivar, - efiboot, - tpm2tss, - ], - link_with : [ - fwupd, - fwupdplugin, - ], - install : true, - install_dir : bindir, - c_args : cargs, -) - -if get_option('man') - custom_target('fwupdate-man', - input : fwupdate, - output : 'fwupdate.1', - command : [ - help2man, '@INPUT@', - '--no-info', - '--output', '@OUTPUT@', - '--name', 'Debugging utility for UEFI firmware updates', - '--manual', 'User Commands', - '--version-string', fwupd_version, - ], - install : true, - install_dir : join_paths(mandir, 'man1'), - ) -endif - -install_data(['uefi.conf'], - install_dir: join_paths(sysconfdir, 'fwupd') -) - -if get_option('tests') - testdatadir = join_paths(meson.current_source_dir(), 'tests') - cargs += '-DTESTDATADIR="' + testdatadir + '"' - e = executable( - 'uefi-self-test', - fu_hash, - sources : [ - 'fu-self-test.c', - 'fu-uefi-bgrt.c', - 'fu-uefi-bootmgr.c', - 'fu-uefi-common.c', - 'fu-uefi-device.c', - 'fu-uefi-devpath.c', - 'fu-uefi-pcrs.c', - 'fu-uefi-update-info.c', - 'fu-uefi-udisks.c', - 'fu-ucs2.c', - ], - include_directories : [ - root_incdir, - fwupd_incdir, - fwupdplugin_incdir, - ], - dependencies : [ - plugin_deps, - efivar, - efiboot, - tpm2tss, - ], - link_with : [ - fwupd, - fwupdplugin, - ], - c_args : cargs - ) - test('uefi-self-test', e) -endif diff -Nru fwupd-1.4.5/plugins/uefi/README.md fwupd-1.5.8/plugins/uefi/README.md --- fwupd-1.4.5/plugins/uefi/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/README.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -UEFI Support -============ - -Introduction ------------- - -The Unified Extensible Firmware Interface (UEFI) is a specification that -defines the software interface between an OS and platform firmware. -With the UpdateCapsule boot service it can be used to update system firmware. - -If you don't want or need this functionality you can use the -`-Dplugin_uefi=false` option. - -Firmware Format ---------------- - -The daemon will decompress the cabinet archive and extract a firmware blob in -EFI capsule file format. - -See https://www.uefi.org/sites/default/files/resources/UEFI%20Spec%202_6.pdf -for details. - -This plugin supports the following protocol ID: - - * org.uefi.capsule - -GUID Generation ---------------- - -These devices use the UEFI GUID as provided in the ESRT. Additionally, for the -system device the `main-system-firmware` GUID is also added. - -For compatibility with Windows 10, the plugin also adds GUIDs of the form -`UEFI\RES_{$(esrt)}`. - -Vendor ID Security ------------------- - -The vendor ID is set from the BIOS vendor, for example `DMI:LENOVO` for all -devices that are not marked as supporting Firmware Management Protocol. For FMP -device no vendor ID is set. - -UEFI Unlock Support -------------------- - -On some Dell systems it is possible to turn on and off UEFI capsule -support from within the BIOS. This functionality can also be adjusted -from within the OS by fwupd. This requires compiling with libsmbios support. - -When fwupd has been compiled with this support you will be able to enable UEFI -support on the device by using the `unlock` command. - -Custom EFI System Partition ---------------------------- - -Since version 1.1.0 fwupd will autodetect the ESP when it is mounted on -`/boot/efi`, `/boot`, or `/efi`. A custom EFI system partition location can be -used by modifying *OverrideESPMountPoint* in `/etc/fwupd/uefi.conf`. - -Setting an invalid directory will disable the fwupd plugin. Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/uefi/tests/acpi/bgrt/image and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/uefi/tests/acpi/bgrt/image differ diff -Nru fwupd-1.4.5/plugins/uefi/tests/acpi/bgrt/status fwupd-1.5.8/plugins/uefi/tests/acpi/bgrt/status --- fwupd-1.4.5/plugins/uefi/tests/acpi/bgrt/status 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/acpi/bgrt/status 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -1 diff -Nru fwupd-1.4.5/plugins/uefi/tests/acpi/bgrt/type fwupd-1.5.8/plugins/uefi/tests/acpi/bgrt/type --- fwupd-1.4.5/plugins/uefi/tests/acpi/bgrt/type 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/acpi/bgrt/type 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -0 diff -Nru fwupd-1.4.5/plugins/uefi/tests/acpi/bgrt/version fwupd-1.5.8/plugins/uefi/tests/acpi/bgrt/version --- fwupd-1.4.5/plugins/uefi/tests/acpi/bgrt/version 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/acpi/bgrt/version 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -1 diff -Nru fwupd-1.4.5/plugins/uefi/tests/acpi/bgrt/xoffset fwupd-1.5.8/plugins/uefi/tests/acpi/bgrt/xoffset --- fwupd-1.4.5/plugins/uefi/tests/acpi/bgrt/xoffset 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/acpi/bgrt/xoffset 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -123 diff -Nru fwupd-1.4.5/plugins/uefi/tests/acpi/bgrt/yoffset fwupd-1.5.8/plugins/uefi/tests/acpi/bgrt/yoffset --- fwupd-1.4.5/plugins/uefi/tests/acpi/bgrt/yoffset 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/acpi/bgrt/yoffset 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -456 Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/uefi/tests/efi/efivars/fwupd-ddc0ee61-e7f0-4e7d-acc5-c070a398838e-0-0abba7dc-e516-4167-bbf5-4d9d1c739416 and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/uefi/tests/efi/efivars/fwupd-ddc0ee61-e7f0-4e7d-acc5-c070a398838e-0-0abba7dc-e516-4167-bbf5-4d9d1c739416 differ diff -Nru fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry0/capsule_flags fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry0/capsule_flags --- fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry0/capsule_flags 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry0/capsule_flags 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -0xfe diff -Nru fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry0/fw_class fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry0/fw_class --- fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry0/fw_class 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry0/fw_class 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -ddc0ee61-e7f0-4e7d-acc5-c070a398838e diff -Nru fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry0/fw_type fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry0/fw_type --- fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry0/fw_type 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry0/fw_type 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -1 diff -Nru fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry0/fw_version fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry0/fw_version --- fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry0/fw_version 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry0/fw_version 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -65586 diff -Nru fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry0/last_attempt_status fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry0/last_attempt_status --- fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry0/last_attempt_status 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry0/last_attempt_status 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -1 diff -Nru fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry0/last_attempt_version fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry0/last_attempt_version --- fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry0/last_attempt_version 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry0/last_attempt_version 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -18472960 diff -Nru fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry0/lowest_supported_fw_version fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry0/lowest_supported_fw_version --- fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry0/lowest_supported_fw_version 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry0/lowest_supported_fw_version 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -65582 diff -Nru fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry1/capsule_flags fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry1/capsule_flags --- fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry1/capsule_flags 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry1/capsule_flags 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -0x8010 diff -Nru fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry1/fw_class fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry1/fw_class --- fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry1/fw_class 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry1/fw_class 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -671d19d0-d43c-4852-98d9-1ce16f9967e4 diff -Nru fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry1/fw_type fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry1/fw_type --- fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry1/fw_type 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry1/fw_type 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -2 diff -Nru fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry1/fw_version fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry1/fw_version --- fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry1/fw_version 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry1/fw_version 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -3090287969 diff -Nru fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry1/last_attempt_status fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry1/last_attempt_status --- fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry1/last_attempt_status 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry1/last_attempt_status 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -0 diff -Nru fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry1/last_attempt_version fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry1/last_attempt_version --- fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry1/last_attempt_version 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry1/last_attempt_version 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -0 diff -Nru fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry1/lowest_supported_fw_version fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry1/lowest_supported_fw_version --- fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry1/lowest_supported_fw_version 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry1/lowest_supported_fw_version 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -1 diff -Nru fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry2/capsule_flags fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry2/capsule_flags --- fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry2/capsule_flags 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry2/capsule_flags 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -0x8010 diff -Nru fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry2/fw_class fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry2/fw_class --- fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry2/fw_class 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry2/fw_class 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -00000000-0000-0000-0000-000000000000 diff -Nru fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry2/fw_type fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry2/fw_type --- fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry2/fw_type 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry2/fw_type 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -2 diff -Nru fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry2/fw_version fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry2/fw_version --- fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry2/fw_version 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry2/fw_version 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -3090287969 diff -Nru fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_status fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_status --- fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_status 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_status 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -0 diff -Nru fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_version fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_version --- fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_version 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_version 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -0 diff -Nru fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry2/lowest_supported_fw_version fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry2/lowest_supported_fw_version --- fwupd-1.4.5/plugins/uefi/tests/efi/esrt/entries/entry2/lowest_supported_fw_version 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/efi/esrt/entries/entry2/lowest_supported_fw_version 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -1 diff -Nru fwupd-1.4.5/plugins/uefi/tests/efi/fw_platform_size fwupd-1.5.8/plugins/uefi/tests/efi/fw_platform_size --- fwupd-1.4.5/plugins/uefi/tests/efi/fw_platform_size 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/efi/fw_platform_size 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -64 diff -Nru fwupd-1.4.5/plugins/uefi/tests/efi-framebuffer/efi-framebuffer.0/height fwupd-1.5.8/plugins/uefi/tests/efi-framebuffer/efi-framebuffer.0/height --- fwupd-1.4.5/plugins/uefi/tests/efi-framebuffer/efi-framebuffer.0/height 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/efi-framebuffer/efi-framebuffer.0/height 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -789 diff -Nru fwupd-1.4.5/plugins/uefi/tests/efi-framebuffer/efi-framebuffer.0/width fwupd-1.5.8/plugins/uefi/tests/efi-framebuffer/efi-framebuffer.0/width --- fwupd-1.4.5/plugins/uefi/tests/efi-framebuffer/efi-framebuffer.0/width 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/efi-framebuffer/efi-framebuffer.0/width 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -456 diff -Nru fwupd-1.4.5/plugins/uefi/tests/.gitignore fwupd-1.5.8/plugins/uefi/tests/.gitignore --- fwupd-1.4.5/plugins/uefi/tests/.gitignore 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/.gitignore 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -EFI -efi/efivars/fwupd-c34cb672-a81e-5d32-9d89-cbcabe8ec37b-0-0abba7dc-e516-4167-bbf5-4d9d1c739416 Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/uefi/tests/test.bmp and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/uefi/tests/test.bmp differ diff -Nru fwupd-1.4.5/plugins/uefi/tests/tpm0/active fwupd-1.5.8/plugins/uefi/tests/tpm0/active --- fwupd-1.4.5/plugins/uefi/tests/tpm0/active 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/tpm0/active 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -1 diff -Nru fwupd-1.4.5/plugins/uefi/tests/tpm0/caps fwupd-1.5.8/plugins/uefi/tests/tpm0/caps --- fwupd-1.4.5/plugins/uefi/tests/tpm0/caps 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/tpm0/caps 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -Manufacturer: 0x49465800 -TCG version: 1.2 -Firmware version: 6.40 diff -Nru fwupd-1.4.5/plugins/uefi/tests/tpm0/enabled fwupd-1.5.8/plugins/uefi/tests/tpm0/enabled --- fwupd-1.4.5/plugins/uefi/tests/tpm0/enabled 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/tpm0/enabled 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -1 diff -Nru fwupd-1.4.5/plugins/uefi/tests/tpm0/owned fwupd-1.5.8/plugins/uefi/tests/tpm0/owned --- fwupd-1.4.5/plugins/uefi/tests/tpm0/owned 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/tpm0/owned 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -1 diff -Nru fwupd-1.4.5/plugins/uefi/tests/tpm0/pcrs fwupd-1.5.8/plugins/uefi/tests/tpm0/pcrs --- fwupd-1.4.5/plugins/uefi/tests/tpm0/pcrs 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/tests/tpm0/pcrs 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -PCR-00: 3C 97 99 20 C9 00 99 60 09 27 D5 DA B3 81 EB 95 1E 7F C8 68 -PCR-01: CE 9F A4 B2 01 09 D8 81 14 EA 1A 6D 13 94 CD 45 5F 52 69 23 -PCR-02: 47 09 7A 9A AD C3 26 A4 93 91 26 63 A1 6F DF 53 D7 88 96 8E -PCR-03: B2 A8 3B 0E BF 2F 83 74 29 9A 5B 2B DF C3 1E A9 55 AD 72 36 -PCR-04: A4 A5 87 4C 59 94 8D 9B 93 66 0A F4 19 D8 6F F8 94 36 20 CC -PCR-05: 00 0B 58 00 89 72 EF 6C 2A AC 79 33 C4 AE 67 6B A6 EF CF 6A -PCR-06: B2 A8 3B 0E BF 2F 83 74 29 9A 5B 2B DF C3 1E A9 55 AD 72 36 -PCR-07: 0A 2A 68 15 85 0D AC B2 D1 F4 E0 C1 F4 56 D5 E2 81 08 6D EA -PCR-08: DB A7 29 4E 49 BA D7 9E 53 99 0A 6E 3A CB 52 97 B9 08 3A 66 -PCR-09: 19 F9 6F 10 83 F5 5B 50 98 26 C3 14 73 43 35 21 1F E6 39 E9 -PCR-10: 37 3D 89 9E 10 0D DD 2D 21 B5 F4 96 8D 4F DC A7 6D 1A C7 BD -PCR-11: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -PCR-12: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -PCR-13: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -PCR-14: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -PCR-15: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -PCR-16: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -PCR-17: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF -PCR-18: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF -PCR-19: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF -PCR-20: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF -PCR-21: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF -PCR-22: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF -PCR-23: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 diff -Nru fwupd-1.4.5/plugins/uefi/uefi.conf fwupd-1.5.8/plugins/uefi/uefi.conf --- fwupd-1.4.5/plugins/uefi/uefi.conf 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/uefi.conf 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -[uefi] - -# the shim loader is required to chainload the fwupd EFI binary unless -# the fwupd.efi file has been self-signed manually -#DisableShimForSecureBoot=true - -# the EFI system partition path used -# if this is is not /boot/efi, /boot, or /efi -#OverrideESPMountPoint= - -# amount of free space required on the ESP, for example using 0x2000000 for 32Mb -#RequireESPFreeSpace= diff -Nru fwupd-1.4.5/plugins/uefi/uefi.quirk fwupd-1.5.8/plugins/uefi/uefi.quirk --- fwupd-1.4.5/plugins/uefi/uefi.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi/uefi.quirk 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -# Star Labs LabTop (Mk III) -[Guid=8265d473-a6c2-42b4-897b-bc220faa2d32] -Flags = use-shim-unique - -# Star Labs Lite (Mk II) -[Guid=797f8bae-0ea2-4c0f-8a30-7d10ccfacbc0] -Flags = use-shim-unique,no-ux-capsule - -# Silicom Minnowboard Turbot D0/D1 PLATFORM -[HwId=386c2f52-44ec-55d3-b802-47631bfb8451] -Flags = uefi-force-enable - -# Dynabook (né Toshiba) X30, X40 -[Guid=28108d08-5027-42c2-a5b8-92d6ede9b97b] -VersionFormat = bcd diff -Nru fwupd-1.4.5/plugins/uefi-capsule/efi/fwup-cleanups.h fwupd-1.5.8/plugins/uefi-capsule/efi/fwup-cleanups.h --- fwupd-1.4.5/plugins/uefi-capsule/efi/fwup-cleanups.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/efi/fwup-cleanups.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#define _DEFINE_CLEANUP_FUNCTION0(Type, name, func) \ + static inline VOID name(VOID *v) \ + { \ + if (*(Type*)v) \ + func (*(Type*)v); \ + } +_DEFINE_CLEANUP_FUNCTION0(VOID *, _FreePool_p, FreePool) +#define _cleanup_free __attribute__ ((cleanup(_FreePool_p))) + +static inline VOID * +_steal_pointer(VOID *pp) +{ + VOID **ptr = (VOID **) pp; + VOID *ref = *ptr; + *ptr = NULL; + return ref; +} diff -Nru fwupd-1.4.5/plugins/uefi-capsule/efi/fwup-common.c fwupd-1.5.8/plugins/uefi-capsule/efi/fwup-common.c --- fwupd-1.4.5/plugins/uefi-capsule/efi/fwup-common.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/efi/fwup-common.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include +#include + +#include "fwup-debug.h" +#include "fwup-common.h" + +VOID +fwup_msleep(unsigned long msecs) +{ + BS->Stall(msecs); +} + +/* + * Allocate some raw pages that aren't part of the pool allocator. + */ +VOID * +fwup_malloc_raw(UINTN size) +{ + UINTN pages = size / 4096 + ((size % 4096) ? 1 : 0); /* page size is always 4096 */ + EFI_STATUS rc; + EFI_PHYSICAL_ADDRESS pageaddr = 0; + EFI_ALLOCATE_TYPE type = AllocateAnyPages; + + if (sizeof(VOID *) == 4) { + pageaddr = 0xffffffffULL - 8192; + type = AllocateMaxAddress; + } + + rc = uefi_call_wrapper(BS->AllocatePages, 4, type, + EfiLoaderData, pages, + &pageaddr); + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not allocate %d", size); + return NULL; + } + if (sizeof(VOID *) == 4 && pageaddr > 0xffffffffULL) { + uefi_call_wrapper(BS->FreePages, 2, pageaddr, pages); + fwup_warning(L"Got bad allocation at 0x%016x", (UINT64)pageaddr); + return NULL; + } + return (VOID *)(UINTN)pageaddr; +} + +/* + * Free our raw page allocations. + */ +static EFI_STATUS +fwup_free_raw(VOID *addr, UINTN size) +{ + UINTN pages = size / 4096 + ((size % 4096) ? 1 : 0); + return uefi_call_wrapper(BS->FreePages, 2, + (EFI_PHYSICAL_ADDRESS)(UINTN)addr, pages); +} + +VOID * +fwup_malloc (UINTN size) +{ + VOID *addr = AllocatePool(size); + if (addr == NULL) + fwup_warning(L"Could not allocate %d", size); + return addr; +} + +VOID * +fwup_malloc0 (UINTN size) +{ + VOID *addr = AllocateZeroPool(size); + if (addr == NULL) + fwup_warning(L"Could not allocate %d", size); + return addr; +} + +EFI_STATUS +fwup_time(EFI_TIME *ts) +{ + EFI_TIME_CAPABILITIES timecaps = { 0, }; + return uefi_call_wrapper(RT->GetTime, 2, ts, &timecaps); +} + +EFI_STATUS +fwup_read_file(EFI_FILE_HANDLE fh, UINT8 **buf_out, UINTN *buf_size_out) +{ + const UINTN bs = 512; + UINTN i = 0; + UINTN n_blocks = 4096; + UINT8 *buf = NULL; + + while (1) { + VOID *newb = NULL; + UINTN news = n_blocks * bs * 2; + + newb = fwup_malloc_raw(news); + if (newb == NULL) + return EFI_OUT_OF_RESOURCES; + if (buf != NULL) { + CopyMem(newb, buf, bs * n_blocks); + fwup_free_raw(buf, bs * n_blocks); + } + buf = newb; + n_blocks *= 2; + + for (; i < n_blocks; i++) { + EFI_STATUS rc; + UINTN sz = bs; + + rc = uefi_call_wrapper(fh->Read, 3, fh, &sz, &buf[i * bs]); + if (EFI_ERROR(rc)) { + fwup_free_raw(buf, bs * n_blocks); + fwup_warning(L"Could not read file: %r", rc); + return rc; + } + + if (sz != bs) { + *buf_size_out = bs * i + sz; + *buf_out = buf; + return EFI_SUCCESS; + } + } + } + return EFI_SUCCESS; +} diff -Nru fwupd-1.4.5/plugins/uefi-capsule/efi/fwup-common.h fwupd-1.5.8/plugins/uefi-capsule/efi/fwup-common.h --- fwupd-1.4.5/plugins/uefi-capsule/efi/fwup-common.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/efi/fwup-common.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2015-2016 Peter Jones + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fwup-efi.h" + +VOID fwup_msleep (unsigned long msecs); +EFI_STATUS fwup_time (EFI_TIME *ts); +EFI_STATUS fwup_read_file (EFI_FILE_HANDLE fh, + UINT8 **buf_out, + UINTN *buf_size_out); +VOID *fwup_malloc_raw (UINTN size); + +VOID *fwup_malloc (UINTN size); +VOID *fwup_malloc0 (UINTN size); + +#define fwup_new(struct_type, n) ((struct_type*)fwup_malloc((n)*sizeof(struct_type))) +#define fwup_new0(struct_type, n) ((struct_type*)fwup_malloc0((n)*sizeof(struct_type))) diff -Nru fwupd-1.4.5/plugins/uefi-capsule/efi/fwupdate.c fwupd-1.5.8/plugins/uefi-capsule/efi/fwupdate.c --- fwupd-1.4.5/plugins/uefi-capsule/efi/fwupdate.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/efi/fwupdate.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,620 @@ +/* + * Copyright (C) 2014 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include +#include + +#include "fwup-cleanups.h" +#include "fwup-common.h" +#include "fwup-efi.h" +#include "fwup-debug.h" + +#define UNUSED __attribute__((__unused__)) +#define GNVN_BUF_SIZE 1024 +#define FWUP_NUM_CAPSULE_UPDATES_MAX 128 + +typedef struct { + CHAR16 *name; + UINT32 attrs; + UINTN size; + FWUP_UPDATE_INFO *info; +} FWUP_UPDATE_TABLE; + +static VOID +fwup_update_table_free(FWUP_UPDATE_TABLE *update) +{ + FreePool(update->info); + FreePool(update->name); + FreePool(update); +} + +_DEFINE_CLEANUP_FUNCTION0(FWUP_UPDATE_TABLE *, _fwup_update_table_free_p, fwup_update_table_free) +#define _cleanup_update_table __attribute__ ((cleanup(_fwup_update_table_free_p))) + +#define SECONDS 1000000 + +static INTN +fwup_dp_size(EFI_DEVICE_PATH *dp, INTN limit) +{ + INTN ret = 0; + while (1) { + if (limit < 4) + break; + INTN nodelen = DevicePathNodeLength(dp); + if (nodelen > limit) + break; + limit -= nodelen; + ret += nodelen; + + if (IsDevicePathEnd(dp)) + return ret; + dp = NextDevicePathNode(dp); + } + return -1; +} + +static EFI_STATUS +fwup_populate_update_info(CHAR16 *name, FWUP_UPDATE_TABLE *info_out) +{ + EFI_STATUS rc; + FWUP_UPDATE_INFO *info = NULL; + UINTN info_size = 0; + UINT32 attrs = 0; + VOID *info_ptr = NULL; + + rc = fwup_get_variable(name, &fwupdate_guid, &info_ptr, &info_size, &attrs); + if (EFI_ERROR(rc)) + return rc; + info = (FWUP_UPDATE_INFO *)info_ptr; + + if (info_size < sizeof(*info)) { + fwup_warning(L"Update '%s' is is too small", name); + return EFI_INVALID_PARAMETER; + } + + if (info_size - sizeof(EFI_DEVICE_PATH) <= sizeof(*info)) { + fwup_warning(L"Update '%s' is malformed, " + L"and cannot hold a file path", name); + return EFI_INVALID_PARAMETER; + } + + EFI_DEVICE_PATH *hdr = (EFI_DEVICE_PATH *)&info->dp; + INTN is = EFI_FIELD_OFFSET(FWUP_UPDATE_INFO, dp); + if (is > (INTN)info_size) { + fwup_warning(L"Update '%s' has an invalid file path, " + L"device path offset is %d, but total size is %d", + name, is, info_size); + return EFI_INVALID_PARAMETER; + } + + is = info_size - is; + INTN sz = fwup_dp_size(hdr, info_size); + if (sz < 0 || is > (INTN)info_size || is != sz) { + fwup_warning(L"Update '%s' has an invalid file path, " + L"update info size: %d dp size: %d size for dp: %d", + name, info_size, sz, is); + return EFI_INVALID_PARAMETER; + } + + info_out->info = info; + info_out->size = info_size; + info_out->attrs = attrs; + info_out->name = StrDuplicate(name); + if (info_out->name == NULL) { + fwup_warning(L"Could not allocate %d", StrSize(name)); + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + +static EFI_STATUS +fwup_populate_update_table(FWUP_UPDATE_TABLE **updates, UINTN *n_updates_out) +{ + EFI_GUID vendor_guid = empty_guid; + EFI_STATUS rc; + UINTN n_updates = 0; + _cleanup_free CHAR16 *variable_name = NULL; + + /* How much do we trust "size of the VariableName buffer" to mean + * sizeof(vn) and not sizeof(vn)/sizeof(vn[0]) ? */ + variable_name = fwup_malloc0(GNVN_BUF_SIZE * 2); + if (variable_name == NULL) + return EFI_OUT_OF_RESOURCES; + + while (1) { + UINTN variable_name_size = GNVN_BUF_SIZE; + rc = uefi_call_wrapper(RT->GetNextVariableName, 3, + &variable_name_size, variable_name, + &vendor_guid); + if (rc == EFI_NOT_FOUND) + break; + + /* ignore any huge names */ + if (rc == EFI_BUFFER_TOO_SMALL) + continue; + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not get variable name: %r", rc); + return rc; + } + + /* not one of our state variables */ + if (CompareGuid(&vendor_guid, &fwupdate_guid)) + continue; + + /* ignore debugging settings */ + if (StrCmp(variable_name, L"FWUPDATE_VERBOSE") == 0 || + StrCmp(variable_name, L"FWUPDATE_DEBUG_LOG") == 0) + continue; + + if (n_updates > FWUP_NUM_CAPSULE_UPDATES_MAX) { + fwup_warning(L"Ignoring update %s", variable_name); + continue; + } + + fwup_debug(L"Found update %s", variable_name); + _cleanup_update_table FWUP_UPDATE_TABLE *update = fwup_malloc0(sizeof(FWUP_UPDATE_TABLE)); + if (update == NULL) + return EFI_OUT_OF_RESOURCES; + rc = fwup_populate_update_info(variable_name, update); + if (EFI_ERROR(rc)) { + fwup_delete_variable(variable_name, &fwupdate_guid); + fwup_warning(L"Could not populate update info for '%s'", variable_name); + return rc; + } + if (update->info->status & FWUPDATE_ATTEMPT_UPDATE) { + fwup_time(&update->info->time_attempted); + update->info->status = FWUPDATE_ATTEMPTED; + updates[n_updates++] = _steal_pointer(&update); + } + } + + *n_updates_out = n_updates; + return EFI_SUCCESS; +} + +static EFI_STATUS +fwup_search_file(EFI_DEVICE_PATH **file_dp, EFI_FILE_HANDLE *fh) +{ + EFI_DEVICE_PATH *dp, *parent_dp; + EFI_GUID sfsp = SIMPLE_FILE_SYSTEM_PROTOCOL; + EFI_GUID dpp = DEVICE_PATH_PROTOCOL; + UINTN n_handles, count; + EFI_STATUS rc; + _cleanup_free EFI_FILE_HANDLE *devices = NULL; + + rc = uefi_call_wrapper(BS->LocateHandleBuffer, 5, ByProtocol, &sfsp, + NULL, &n_handles, (EFI_HANDLE **)&devices); + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not find handles"); + return rc; + } + + dp = *file_dp; + + fwup_debug(L"Searching Device Path: %s...", DevicePathToStr(dp)); + parent_dp = DuplicateDevicePath(dp); + if (parent_dp == NULL) + return EFI_INVALID_PARAMETER; + + dp = parent_dp; + count = 0; + while (1) { + if (IsDevicePathEnd(dp)) + return EFI_INVALID_PARAMETER; + + if (DevicePathType(dp) == MEDIA_DEVICE_PATH && + DevicePathSubType(dp) == MEDIA_FILEPATH_DP) + break; + + dp = NextDevicePathNode(dp); + ++count; + } + + SetDevicePathEndNode(dp); + fwup_debug(L"Device Path prepared: %s", DevicePathToStr(parent_dp)); + + for (UINTN i = 0; i < n_handles; i++) { + EFI_DEVICE_PATH *path; + + rc = uefi_call_wrapper(BS->HandleProtocol, 3, devices[i], &dpp, + (VOID **)&path); + if (EFI_ERROR(rc)) + continue; + + fwup_debug(L"Device supporting SFSP: %s", DevicePathToStr(path)); + + while (!IsDevicePathEnd(path)) { + fwup_debug(L"Comparing: %s and %s", + DevicePathToStr(parent_dp), + DevicePathToStr(path)); + + if (LibMatchDevicePaths(path, parent_dp) == TRUE) { + *fh = devices[i]; + for (UINTN j = 0; j < count; j++) + *file_dp = NextDevicePathNode(*file_dp); + + fwup_debug(L"Match up! Returning %s", + DevicePathToStr(*file_dp)); + return EFI_SUCCESS; + } + + path = NextDevicePathNode(path); + } + } + + fwup_warning(L"Failed to find '%s' DevicePath", DevicePathToStr(*file_dp)); + return EFI_UNSUPPORTED; +} + +static EFI_STATUS +fwup_open_file(EFI_DEVICE_PATH *dp, EFI_FILE_HANDLE *fh) +{ + CONST UINTN devpath_max_size = 1024; /* arbitrary limit */ + EFI_DEVICE_PATH *file_dp = dp; + EFI_GUID sfsp = SIMPLE_FILE_SYSTEM_PROTOCOL; + EFI_FILE_HANDLE device; + EFI_FILE_IO_INTERFACE *drive; + EFI_FILE_HANDLE root; + EFI_STATUS rc; + + rc = uefi_call_wrapper(BS->LocateDevicePath, 3, &sfsp, &file_dp, + (EFI_HANDLE *)&device); + if (EFI_ERROR(rc)) { + rc = fwup_search_file(&file_dp, &device); + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not locate device handle: %r", rc); + return rc; + } + } + + if (DevicePathType(file_dp) != MEDIA_DEVICE_PATH || + DevicePathSubType(file_dp) != MEDIA_FILEPATH_DP) { + fwup_warning(L"Could not find appropriate device"); + return EFI_UNSUPPORTED; + } + + UINT16 sz16; + UINTN sz; + CopyMem(&sz16, &file_dp->Length[0], sizeof(sz16)); + sz = sz16; + sz -= 4; + if (sz <= 6 || sz % 2 != 0 || + sz > devpath_max_size * sizeof(CHAR16)) { + fwup_warning(L"Invalid file device path of size %d", sz); + return EFI_INVALID_PARAMETER; + } + + _cleanup_free CHAR16 *filename = fwup_malloc0(sz + sizeof(CHAR16)); + CopyMem(filename, (UINT8 *)file_dp + 4, sz); + + rc = uefi_call_wrapper(BS->HandleProtocol, 3, device, &sfsp, + (VOID **)&drive); + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not open device interface: %r", rc); + return rc; + } + fwup_debug(L"Found device"); + + rc = uefi_call_wrapper(drive->OpenVolume, 2, drive, &root); + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not open volume: %r", rc); + return rc; + } + fwup_debug(L"Found volume"); + + rc = uefi_call_wrapper(root->Open, 5, root, fh, filename, + EFI_FILE_MODE_READ, 0); + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not open file '%s': %r", filename, rc); + return rc; + } + fwup_debug(L"Found file"); + + return EFI_SUCCESS; +} + +static EFI_STATUS +fwup_get_gop_mode(UINT32 *mode, EFI_HANDLE loaded_image) +{ + EFI_HANDLE *handles, gop_handle; + UINTN num_handles; + EFI_STATUS status; + EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; + EFI_GRAPHICS_OUTPUT_PROTOCOL *gop; + VOID *iface; + + status = LibLocateHandle(ByProtocol, &gop_guid, NULL, &num_handles, + &handles); + if (EFI_ERROR(status)) + return status; + + if (handles == NULL || num_handles == 0) + return EFI_UNSUPPORTED; + + for (UINTN i = 0; i < num_handles; i++) { + gop_handle = handles[i]; + + status = uefi_call_wrapper(BS->OpenProtocol, 6, + gop_handle, &gop_guid, &iface, + loaded_image, 0, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(status)) + continue; + + gop = (EFI_GRAPHICS_OUTPUT_PROTOCOL *)iface; + + *mode = gop->Mode->Mode; + return EFI_SUCCESS; + } + + return EFI_UNSUPPORTED; +} + +static inline void +fwup_update_ux_capsule_checksum(UX_CAPSULE_HEADER *payload_hdr) +{ + UINT8 *buf = (UINT8 *)payload_hdr; + UINT8 sum = 0; + + payload_hdr->checksum = 0; + for (UINTN i = 0; i < sizeof(*payload_hdr); i++) + sum = (UINT8) (sum + buf[i]); + payload_hdr->checksum = sum; +} + +static EFI_STATUS +fwup_check_gop_for_ux_capsule(EFI_HANDLE loaded_image, + EFI_CAPSULE_HEADER *capsule) +{ + UX_CAPSULE_HEADER *payload_hdr; + EFI_STATUS rc; + + payload_hdr = (UX_CAPSULE_HEADER *) (((UINT8 *) capsule) + capsule->HeaderSize); + rc = fwup_get_gop_mode(&payload_hdr->mode, loaded_image); + if (EFI_ERROR(rc)) + return EFI_UNSUPPORTED; + + fwup_update_ux_capsule_checksum(payload_hdr); + + return EFI_SUCCESS; +} + +static EFI_STATUS +fwup_add_update_capsule(FWUP_UPDATE_TABLE *update, EFI_CAPSULE_HEADER **capsule_out, + EFI_CAPSULE_BLOCK_DESCRIPTOR *cbd_out, EFI_HANDLE loaded_image) +{ + EFI_STATUS rc; + EFI_FILE_HANDLE fh = NULL; + UINT8 *fbuf = NULL; + UINTN fsize = 0; + EFI_CAPSULE_HEADER *capsule; + + UINTN cbd_len; + EFI_PHYSICAL_ADDRESS cbd_data; + EFI_CAPSULE_HEADER *cap_out; + + rc = fwup_open_file((EFI_DEVICE_PATH *)update->info->dp_buf, &fh); + if (EFI_ERROR(rc)) + return rc; + + rc = fwup_read_file(fh, &fbuf, &fsize); + if (EFI_ERROR(rc)) + return rc; + + uefi_call_wrapper(fh->Close, 1, fh); + + if (fsize < sizeof(EFI_CAPSULE_HEADER)) { + fwup_warning(L"Invalid capsule size %d", fsize); + return EFI_INVALID_PARAMETER; + } + + fwup_debug(L"Read file; %d bytes", fsize); + fwup_debug(L"updates guid: %g", &update->info->guid); + fwup_debug(L"File guid: %g", fbuf); + + cbd_len = fsize; + cbd_data = (EFI_PHYSICAL_ADDRESS)(UINTN)fbuf; + capsule = cap_out = (EFI_CAPSULE_HEADER *)fbuf; + if (cap_out->Flags == 0 && + CompareGuid(&update->info->guid, &ux_capsule_guid) != 0) { +#if defined(__aarch64__) + cap_out->Flags |= update->info->capsule_flags; +#else + cap_out->Flags |= update->info->capsule_flags | + CAPSULE_FLAGS_PERSIST_ACROSS_RESET | + CAPSULE_FLAGS_INITIATE_RESET; +#endif + } + + if (CompareGuid(&update->info->guid, &ux_capsule_guid) == 0) { + fwup_debug(L"Checking GOP for ux capsule"); + rc = fwup_check_gop_for_ux_capsule(loaded_image, capsule); + if (EFI_ERROR(rc)) + return EFI_UNSUPPORTED; + } + + cbd_out->Length = cbd_len; + cbd_out->Union.DataBlock = cbd_data; + *capsule_out = cap_out; + + return EFI_SUCCESS; +} + +static EFI_STATUS +fwup_apply_capsules(EFI_CAPSULE_HEADER **capsules, + EFI_CAPSULE_BLOCK_DESCRIPTOR *cbd, + UINTN num_updates, EFI_RESET_TYPE *reset) +{ + UINT64 max_capsule_size; + EFI_STATUS rc; + + rc = uefi_call_wrapper(RT->QueryCapsuleCapabilities, 4, capsules, + num_updates, &max_capsule_size, reset); + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not query capsule capabilities: %r", rc); + return rc; + } + fwup_debug(L"QueryCapsuleCapabilities: %r max: %ld reset:%d", + rc, max_capsule_size, *reset); + fwup_debug(L"Capsules: %d", num_updates); + + fwup_msleep(1 * SECONDS); + rc = uefi_call_wrapper(RT->UpdateCapsule, 3, capsules, num_updates, + (EFI_PHYSICAL_ADDRESS)(UINTN)cbd); + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not apply capsule update: %r", rc); + return rc; + } + + return EFI_SUCCESS; +} + +static EFI_STATUS +fwup_set_update_statuses(FWUP_UPDATE_TABLE **updates) +{ + EFI_STATUS rc; + for (UINTN i = 0; i < FWUP_NUM_CAPSULE_UPDATES_MAX; i++) { + if (updates[i] == NULL || updates[i]->name == NULL) + break; + rc = fwup_set_variable(updates[i]->name, &fwupdate_guid, + updates[i]->info, updates[i]->size, + updates[i]->attrs); + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not update variable status for '%s': %r", + updates[i]->name, rc); + return rc; + } + } + return EFI_SUCCESS; +} + +EFI_GUID SHIM_LOCK_GUID = + {0x605dab50,0xe046,0x4300,{0xab,0xb6,0x3d,0xd8,0x10,0xdd,0x8b,0x23}}; + +static VOID +__attribute__((__optimize__("0"))) +fwup_debug_hook(VOID) +{ + EFI_GUID guid = SHIM_LOCK_GUID; + UINTN data = 0; + UINTN data_size = 1; + EFI_STATUS efi_status; + UINT32 attrs; + register volatile int x = 0; + extern char _text UNUSED, _data UNUSED; + + /* shim has done whatever is needed to get a debugger attached */ + efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"SHIM_DEBUG", + &guid, &attrs, &data_size, &data); + if (EFI_ERROR(efi_status) || data != 1) { + efi_status = uefi_call_wrapper(RT->GetVariable, 5, + L"FWUPDATE_VERBOSE", + &fwupdate_guid, &attrs, + &data_size, &data); + if (EFI_ERROR(efi_status) || data != 1) + return; + fwup_debug_set_enabled(TRUE); + return; + } + + fwup_debug_set_enabled(TRUE); + if (x) + return; + + x = 1; + fwup_info(L"add-symbol-file "DEBUGDIR + L"fwupdate.efi.debug %p -s .data %p", + &_text, &_data); +} + +EFI_STATUS +efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) +{ + EFI_STATUS rc; + UINTN i, n_updates = 0; + EFI_RESET_TYPE reset_type = EfiResetWarm; + _cleanup_free FWUP_UPDATE_TABLE **updates = NULL; + + InitializeLib(image, systab); + + /* if SHIM_DEBUG is set, fwup_info info for our attached debugger */ + fwup_debug_hook(); + + /* step 1: find and validate update state variables */ + /* XXX TODO: + * 1) survey the reset types first, and separate into groups + * according to them + * 2) if there's more than one, mirror BootCurrent back into BootNext + * so we can do multiple runs + * 3) only select the ones from one type for the first go + */ + updates = fwup_new0(FWUP_UPDATE_TABLE *, FWUP_NUM_CAPSULE_UPDATES_MAX); + if (updates == NULL) + return EFI_OUT_OF_RESOURCES; + rc = fwup_populate_update_table(updates, &n_updates); + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not find updates: %r", rc); + return rc; + } + if (n_updates == 0) { + fwup_warning(L"No updates to process. Called in error?"); + return EFI_INVALID_PARAMETER; + } + + /* step 2: Build our data structure and add the capsules to it */ + _cleanup_free EFI_CAPSULE_HEADER **capsules = NULL; + capsules = fwup_new0(EFI_CAPSULE_HEADER *, n_updates + 1); + EFI_CAPSULE_BLOCK_DESCRIPTOR *cbd_data; + UINTN j = 0; + cbd_data = fwup_malloc_raw(sizeof(EFI_CAPSULE_BLOCK_DESCRIPTOR)*(n_updates+1)); + if (cbd_data == NULL) + return EFI_OUT_OF_RESOURCES; + for (i = 0; i < n_updates; i++) { + fwup_debug(L"Adding new capsule"); + rc = fwup_add_update_capsule(updates[i], &capsules[j], &cbd_data[j], image); + if (EFI_ERROR(rc)) { + /* ignore a failing capsule */ + fwup_warning(L"Could not add capsule with guid %g for update: %r", + updates[i]->info->guid, rc); + continue; + } + j++; + } + + if (j == 0) { + fwup_warning(L"Could not build update list: %r\n", rc); + return rc; + } + n_updates = j; + fwup_debug(L"n_updates: %d", n_updates); + + cbd_data[i].Length = 0; + cbd_data[i].Union.ContinuationPointer = 0; + + /* step 3: update the state variables */ + rc = fwup_set_update_statuses(updates); + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not set update status: %r", rc); + return rc; + } + + /* step 4: apply the capsules */ + rc = fwup_apply_capsules(capsules, cbd_data, n_updates, &reset_type); + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not apply capsules: %r", rc); + return rc; + } + + /* step 5: if #4 didn't reboot us, do it manually */ + fwup_info(L"Reset System"); + fwup_msleep(5 * SECONDS); + if (fwup_debug_get_enabled()) + fwup_msleep(30 * SECONDS); + uefi_call_wrapper(RT->ResetSystem, 4, reset_type, EFI_SUCCESS, 0, NULL); + + return EFI_SUCCESS; +} diff -Nru fwupd-1.4.5/plugins/uefi-capsule/efi/fwup-debug.c fwupd-1.5.8/plugins/uefi-capsule/efi/fwup-debug.c --- fwupd-1.4.5/plugins/uefi-capsule/efi/fwup-debug.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/efi/fwup-debug.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include +#include + +#include "fwup-cleanups.h" +#include "fwup-debug.h" +#include "fwup-efi.h" + +static BOOLEAN debugging = FALSE; + +BOOLEAN +fwup_debug_get_enabled(VOID) +{ + return debugging; +} + +VOID +fwup_debug_set_enabled(BOOLEAN val) +{ + debugging = val; +} + +static VOID +fwupd_debug_efivar_append(CHAR16 *out1) +{ + CHAR16 *name = L"FWUPDATE_DEBUG_LOG"; + UINT32 attrs = EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS; + static BOOLEAN once = TRUE; + if (once) { + once = FALSE; + fwup_delete_variable(name, &fwupdate_guid); + } else { + attrs |= EFI_VARIABLE_APPEND_WRITE; + } + fwup_set_variable(name, &fwupdate_guid, out1, StrSize(out1) - sizeof(CHAR16), attrs); +} + +VOID +fwup_log(FwupLogLevel level, const char *func, const char *file, const int line, CHAR16 *fmt, ...) +{ + va_list args; + _cleanup_free CHAR16 *tmp = NULL; + + va_start(args, fmt); + tmp = VPoolPrint(fmt, args); + va_end(args); + if (tmp == NULL) { + Print(L"fwupdate: Allocation for debug log failed!\n"); + return; + } + + if (debugging) { + _cleanup_free CHAR16 *out1 = NULL; + out1 = PoolPrint(L"%a:%d:%a(): %s\n", file, line, func, tmp); + if (out1 == NULL) { + Print(L"fwupdate: Allocation for debug log failed!\n"); + return; + } + Print(L"%s", out1); + fwupd_debug_efivar_append(out1); + } else { + switch (level) { + case FWUP_DEBUG_LEVEL_DEBUG: + break; + case FWUP_DEBUG_LEVEL_WARNING: + Print(L"WARNING: %s\n", tmp); + break; + default: + Print(L"%s\n", tmp); + break; + } + } +} diff -Nru fwupd-1.4.5/plugins/uefi-capsule/efi/fwup-debug.h fwupd-1.5.8/plugins/uefi-capsule/efi/fwup-debug.h --- fwupd-1.4.5/plugins/uefi-capsule/efi/fwup-debug.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/efi/fwup-debug.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2015-2016 Peter Jones + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +typedef enum { + FWUP_DEBUG_LEVEL_DEBUG, + FWUP_DEBUG_LEVEL_INFO, + FWUP_DEBUG_LEVEL_WARNING, + FWUP_DEBUG_LEVEL_LAST +} FwupLogLevel; + +VOID fwup_log (FwupLogLevel level, + const char *func, + const char *file, + const int line, + CHAR16 *fmt, + ...); + +BOOLEAN fwup_debug_get_enabled (VOID); +VOID fwup_debug_set_enabled (BOOLEAN val); + +#define fwup_debug(fmt, args...) fwup_log(FWUP_DEBUG_LEVEL_DEBUG, __func__, __FILE__, __LINE__, fmt, ## args ) +#define fwup_info(fmt, args...) fwup_log(FWUP_DEBUG_LEVEL_INFO, __func__, __FILE__, __LINE__, fmt, ## args ) +#define fwup_warning(fmt, args...) fwup_log(FWUP_DEBUG_LEVEL_WARNING, __func__, __FILE__, __LINE__, fmt, ## args ) diff -Nru fwupd-1.4.5/plugins/uefi-capsule/efi/fwup-efi.c fwupd-1.5.8/plugins/uefi-capsule/efi/fwup-efi.c --- fwupd-1.4.5/plugins/uefi-capsule/efi/fwup-efi.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/efi/fwup-efi.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include +#include + +#include "fwup-cleanups.h" +#include "fwup-common.h" +#include "fwup-debug.h" +#include "fwup-efi.h" + +EFI_STATUS +fwup_delete_variable(CHAR16 *name, EFI_GUID *guid) +{ + EFI_STATUS rc; + UINT32 attrs = 0; + + /* get the attrs so we can delete it */ + rc = uefi_call_wrapper(RT->GetVariable, 5, name, guid, &attrs, NULL, NULL); + if (EFI_ERROR(rc)) { + if (rc == EFI_NOT_FOUND) { + fwup_debug(L"Not deleting variable '%s' as not found", name); + return EFI_SUCCESS; + } + fwup_debug(L"Could not get variable '%s' for delete: %r", name, rc); + return rc; + } + return uefi_call_wrapper(RT->SetVariable, 5, name, guid, attrs, 0, NULL); +} + +EFI_STATUS +fwup_set_variable(CHAR16 *name, EFI_GUID *guid, VOID *data, UINTN size, UINT32 attrs) +{ + return uefi_call_wrapper(RT->SetVariable, 5, name, guid, attrs, size, data); +} + +EFI_STATUS +fwup_get_variable(CHAR16 *name, EFI_GUID *guid, VOID **buf_out, UINTN *buf_size_out, UINT32 *attrs_out) +{ + EFI_STATUS rc; + UINTN size = 0; + UINT32 attrs; + _cleanup_free VOID *buf = NULL; + + rc = uefi_call_wrapper(RT->GetVariable, 5, name, guid, &attrs, &size, NULL); + if (EFI_ERROR(rc)) { + if (rc == EFI_BUFFER_TOO_SMALL) { + buf = fwup_malloc(size); + if (buf == NULL) + return EFI_OUT_OF_RESOURCES; + } else if (rc != EFI_NOT_FOUND) { + fwup_debug(L"Could not get variable '%s': %r", name, rc); + return rc; + } + } else { + fwup_debug(L"GetVariable(%s) succeeded with size=0", name); + return EFI_INVALID_PARAMETER; + } + rc = uefi_call_wrapper(RT->GetVariable, 5, name, guid, &attrs, &size, buf); + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not get variable '%s': %r", name, rc); + return rc; + } + *buf_out = _steal_pointer(&buf); + *buf_size_out = size; + *attrs_out = attrs; + return EFI_SUCCESS; +} diff -Nru fwupd-1.4.5/plugins/uefi-capsule/efi/fwup-efi.h fwupd-1.5.8/plugins/uefi-capsule/efi/fwup-efi.h --- fwupd-1.4.5/plugins/uefi-capsule/efi/fwup-efi.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/efi/fwup-efi.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2015 Peter Jones + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#define FWUPDATE_ATTEMPT_UPDATE 0x00000001 +#define FWUPDATE_ATTEMPTED 0x00000002 + +#define UPDATE_INFO_VERSION 7 + +static __attribute__((__unused__)) EFI_GUID empty_guid = + {0x0,0x0,0x0,{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}}; +static __attribute__((__unused__))EFI_GUID fwupdate_guid = + {0x0abba7dc,0xe516,0x4167,{0xbb,0xf5,0x4d,0x9d,0x1c,0x73,0x94,0x16}}; +static __attribute__((__unused__))EFI_GUID ux_capsule_guid = + {0x3b8c8162,0x188c,0x46a4,{0xae,0xc9,0xbe,0x43,0xf1,0xd6,0x56,0x97}}; +static __attribute__((__unused__))EFI_GUID global_variable_guid = EFI_GLOBAL_VARIABLE; + +typedef struct { + UINT8 version; + UINT8 checksum; + UINT8 image_type; + UINT8 reserved; + UINT32 mode; + UINT32 x_offset; + UINT32 y_offset; +} __attribute__((__packed__)) UX_CAPSULE_HEADER; + +typedef struct { + UINT32 update_info_version; + + /* stuff we need to apply an update */ + EFI_GUID guid; + UINT32 capsule_flags; + UINT64 hw_inst; + + EFI_TIME time_attempted; + + /* our metadata */ + UINT32 status; + + /* variadic device path */ + union { + EFI_DEVICE_PATH dp; + UINT8 dp_buf[0]; + }; +} __attribute__((__packed__)) FWUP_UPDATE_INFO; + +typedef struct { + UINT32 attributes; + UINT16 file_path_list_length; + CHAR16 *description; +} __attribute__((__packed__)) EFI_LOAD_OPTION; + +EFI_STATUS fwup_delete_variable (CHAR16 *name, + EFI_GUID *guid); +EFI_STATUS fwup_set_variable (CHAR16 *name, + EFI_GUID *guid, + VOID *data, + UINTN size, + UINT32 attrs); +EFI_STATUS fwup_get_variable (CHAR16 *name, + EFI_GUID *guid, + VOID **buf_out, + UINTN *buf_size_out, + UINT32 *attrs_out); diff -Nru fwupd-1.4.5/plugins/uefi-capsule/efi/generate_binary.py fwupd-1.5.8/plugins/uefi-capsule/efi/generate_binary.py --- fwupd-1.4.5/plugins/uefi-capsule/efi/generate_binary.py 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/efi/generate_binary.py 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,93 @@ +#!/usr/bin/python3 +# +# Copyright (C) 2021 Javier Martinez Canillas +# Copyright (C) 2021 Richard Hughes +# +# SPDX-License-Identifier: LGPL-2.1+ +# +# pylint: disable=missing-docstring, invalid-name + +import subprocess +import sys +import argparse + + +def _run_objcopy(args): + + argv = [ + args.objcopy, + "-j", + ".text", + "-j", + ".sbat", + "-j", + ".sdata", + "-j", + ".data", + "-j", + ".dynamic", + "-j", + ".dynsym", + "-j", + ".rel*", + args.infile, + args.outfile, + ] + + # aarch64 and arm32 don't have an EFI capable objcopy + # Use 'binary' instead, and add required symbols manually + if args.arch in ["aarch64", "arm"]: + argv.extend(["-O", "binary"]) + else: + argv.extend(["--target", "efi-app-{}".format(args.arch)]) + try: + subprocess.run(argv, check=True) + except FileNotFoundError as e: + print(str(e)) + sys.exit(1) + + +def _run_genpeimg(args): + + # this is okay if it does not exist + argv = [ + "genpeimg", + "-d", + "+d", + "+n", + "-d", + "+s", + args.outfile, + ] + try: + subprocess.run(argv, check=True) + except FileNotFoundError as _: + pass + + +if __name__ == "__main__": + + parser = argparse.ArgumentParser() + parser.add_argument( + "--objcopy", + default="objcopy", + help="Binary file to use for objcopy", + ) + parser.add_argument( + "--arch", + default="x86_64", + help="EFI architecture", + ) + parser.add_argument( + "infile", + help="Input file", + ) + parser.add_argument( + "outfile", + help="Output file", + ) + _args = parser.parse_args() + _run_objcopy(_args) + _run_genpeimg(_args) + + sys.exit(0) diff -Nru fwupd-1.4.5/plugins/uefi-capsule/efi/generate_sbat.py fwupd-1.5.8/plugins/uefi-capsule/efi/generate_sbat.py --- fwupd-1.4.5/plugins/uefi-capsule/efi/generate_sbat.py 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/efi/generate_sbat.py 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,151 @@ +#!/usr/bin/python3 +# +# Copyright (C) 2021 Javier Martinez Canillas +# Copyright (C) 2021 Richard Hughes +# +# SPDX-License-Identifier: LGPL-2.1+ +# +# pylint: disable=missing-docstring, invalid-name + +import subprocess +import sys +import argparse +import tempfile + + +def _generate_sbat(args): + """ append SBAT metadata """ + FWUPD_SUMMARY = "Firmware update daemon" + FWUPD_URL = "https://github.com/fwupd/fwupd" + + subprocess.run( + [args.cc, "-x", "c", "-c", "-o", args.outfile, "/dev/null"], check=True + ) + + # not specified + if not args.sbat_distro_id: + return + + with tempfile.NamedTemporaryFile() as sfd: + + # spec + sfd.write( + "{0},{1},{2},{0},{1},{3}\n".format( + "sbat", + args.sbat_version, + "UEFI shim", + "https://github.com/rhboot/shim/blob/main/SBAT.md", + ).encode() + ) + + # fwupd + sfd.write( + "{0},{1},{2},{0},{3},{4}\n".format( + args.project_name, + args.sbat_generation, + "Firmware update daemon", + args.project_version, + FWUPD_URL, + ).encode() + ) + + # distro specifics, falling back to the project defaults + sfd.write( + "{0}.{1},{2},{3},{4},{5},{6}\n".format( + args.project_name, + args.sbat_distro_id, + args.sbat_distro_generation or args.sbat_generation, + args.sbat_distro_summary or FWUPD_SUMMARY, + args.sbat_distro_pkgname, + args.sbat_distro_version or args.project_version, + args.sbat_distro_url or FWUPD_URL, + ).encode() + ) + + # all written + sfd.seek(0) + + # add a section to the object; use `objdump -s -j .sbat` to verify + argv = [ + args.objcopy, + "--add-section", + ".sbat={}".format(sfd.name), + "--set-section-flags", + ".sbat=contents,alloc,load,readonly,data", + args.outfile, + ] + subprocess.run(argv, check=True) + + +if __name__ == "__main__": + + parser = argparse.ArgumentParser() + parser.add_argument( + "--cc", + default="gcc", + help="Compiler to use for generating sbat object", + ) + parser.add_argument( + "--objcopy", + default="objcopy", + help="Binary file to use for objcopy", + ) + parser.add_argument( + "--project-name", + help="SBAT project name", + ) + parser.add_argument( + "--project-version", + help="SBAT project version", + ) + parser.add_argument( + "--sbat-version", + default=1, + type=int, + help="SBAT version", + ) + parser.add_argument( + "--sbat-generation", + default=1, + type=int, + help="SBAT generation", + ) + parser.add_argument( + "--sbat-distro-id", + default=None, + help="SBAT distribution ID" + ) + parser.add_argument( + "--sbat-distro-generation", + default=None, + type=int, + help="SBAT distribution generation", + ) + parser.add_argument( + "--sbat-distro-summary", + default=None, + help="SBAT distribution summary", + ) + parser.add_argument( + "--sbat-distro-pkgname", + default=None, + help="SBAT distribution package name", + ) + parser.add_argument( + "--sbat-distro-version", + default=None, + help="SBAT distribution version", + ) + parser.add_argument( + "--sbat-distro-url", + default=None, + help="SBAT distribution URL", + ) + parser.add_argument( + "outfile", + help="Output file", + ) + _args = parser.parse_args() + _generate_sbat(_args) + + sys.exit(0) diff -Nru fwupd-1.4.5/plugins/uefi-capsule/efi/lds/elf_aarch64_efi.lds fwupd-1.5.8/plugins/uefi-capsule/efi/lds/elf_aarch64_efi.lds --- fwupd-1.4.5/plugins/uefi-capsule/efi/lds/elf_aarch64_efi.lds 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/efi/lds/elf_aarch64_efi.lds 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,87 @@ +OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64") +OUTPUT_ARCH(aarch64) +ENTRY(_start) +SECTIONS +{ + .text 0x0 : { + _text = .; + *(.text.head) + *(.text) + *(.text.*) + *(.gnu.linkonce.t.*) + *(.srodata) + *(.rodata*) + . = ALIGN(16); + _etext = .; + } + + . = ALIGN(4096); + .dynamic : { *(.dynamic) } + + . = ALIGN(4096); + .note.gnu.build-id : { + *(.note.gnu.build-id) + } + + . = ALIGN(4096); + .data.ident : { + *(.data.ident) + } + + . = ALIGN(4096); + .data : + { + _data = .; + *(.sdata) + *(.data) + *(.data1) + *(.data.*) + *(.got.plt) + *(.got) + + /* the EFI loader doesn't seem to like a .bss section, so we stick + it all into .data: */ + . = ALIGN(16); + _bss = .; + *(.sbss) + *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + . = ALIGN(16); + _bss_end = .; + } + + . = ALIGN(4096); + .sbat : + { + _sbat = .; + *(.sbat) + *(.sbat.*) + _esbat = .; + } + . = ALIGN(4096); + .rela : + { + *(.rela.dyn) + *(.rela.plt) + *(.rela.got) + *(.rela.data) + *(.rela.data*) + } + _edata = .; + _data_size = . - _data; + + . = ALIGN(4096); + .dynsym : { *(.dynsym) } + . = ALIGN(4096); + .dynstr : { *(.dynstr) } + . = ALIGN(4096); + /DISCARD/ : + { + *(.rel.reloc) + *(.eh_frame) + *(.note.GNU-stack) + } + .comment 0 : { *(.comment) } +} diff -Nru fwupd-1.4.5/plugins/uefi-capsule/efi/lds/elf_arm_efi.lds fwupd-1.5.8/plugins/uefi-capsule/efi/lds/elf_arm_efi.lds --- fwupd-1.4.5/plugins/uefi-capsule/efi/lds/elf_arm_efi.lds 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/efi/lds/elf_arm_efi.lds 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,73 @@ +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + .text 0x0 : { + _text = .; + *(.text.head) + *(.text) + *(.text.*) + *(.gnu.linkonce.t.*) + *(.srodata) + *(.rodata*) + . = ALIGN(16); + } + _etext = .; + _text_size = . - _text; + .dynamic : { *(.dynamic) } + .data : + { + _data = .; + *(.sdata) + *(.data) + *(.data1) + *(.data.*) + *(.got.plt) + *(.got) + + /* the EFI loader doesn't seem to like a .bss section, so we stick + it all into .data: */ + . = ALIGN(16); + _bss = .; + *(.sbss) + *(.scommon) + *(.dynbss) + *(.bss) + *(.bss.*) + *(COMMON) + . = ALIGN(16); + _bss_end = .; + } + + . = ALIGN(4096); + .sbat : + { + _sbat = .; + *(.sbat) + *(.sbat.*) + _esbat = .; + } + + . = ALIGN(4096); + .rel.dyn : { *(.rel.dyn) } + .rel.plt : { *(.rel.plt) } + .rel.got : { *(.rel.got) } + .rel.data : { *(.rel.data) *(.rel.data*) } + _edata = .; + _data_size = . - _etext; + + . = ALIGN(4096); + .dynsym : { *(.dynsym) } + . = ALIGN(4096); + .dynstr : { *(.dynstr) } + . = ALIGN(4096); + .note.gnu.build-id : { *(.note.gnu.build-id) } + /DISCARD/ : + { + *(.rel.reloc) + *(.eh_frame) + *(.note.GNU-stack) + } + .comment 0 : { *(.comment) } +} diff -Nru fwupd-1.4.5/plugins/uefi-capsule/efi/lds/elf_ia32_efi.lds fwupd-1.5.8/plugins/uefi-capsule/efi/lds/elf_ia32_efi.lds --- fwupd-1.4.5/plugins/uefi-capsule/efi/lds/elf_ia32_efi.lds 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/efi/lds/elf_ia32_efi.lds 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,87 @@ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) +SECTIONS +{ + . = 0; + ImageBase = .; + .hash : { *(.hash) } /* this MUST come first! */ + . = ALIGN(4096); + .text : + { + _text = .; + *(.text) + *(.text.*) + *(.gnu.linkonce.t.*) + _etext = .; + } + .reloc : + { + *(.reloc) + } + . = ALIGN(4096); + .note.gnu.build-id : { + *(.note.gnu.build-id) + } + . = ALIGN(4096); + .data.ident : { + *(.data.ident) + } + + . = ALIGN(4096); + .data : + { + _data = .; + *(.rodata*) + *(.data) + *(.data1) + *(.data.*) + *(.sdata) + *(.got.plt) + *(.got) + /* the EFI loader doesn't seem to like a .bss section, so we stick + it all into .data: */ + *(.sbss) + *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + } + + . = ALIGN(4096); + .sbat : + { + _sbat = .; + *(.sbat) + *(.sbat.*) + _esbat = .; + } + . = ALIGN(4096); + .dynamic : { *(.dynamic) } + . = ALIGN(4096); + .rel : + { + *(.rel.data) + *(.rel.data.*) + *(.rel.got) + *(.rel.stab) + *(.data.rel.ro.local) + *(.data.rel.local) + *(.data.rel.ro) + *(.data.rel*) + } + _edata = .; + _data_size = . - _data; + . = ALIGN(4096); + .dynsym : { *(.dynsym) } + . = ALIGN(4096); + .dynstr : { *(.dynstr) } + . = ALIGN(4096); + /DISCARD/ : + { + *(.rel.reloc) + *(.eh_frame) + *(.note.GNU-stack) + } + .comment 0 : { *(.comment) } +} diff -Nru fwupd-1.4.5/plugins/uefi-capsule/efi/lds/elf_x86_64_efi.lds fwupd-1.5.8/plugins/uefi-capsule/efi/lds/elf_x86_64_efi.lds --- fwupd-1.4.5/plugins/uefi-capsule/efi/lds/elf_x86_64_efi.lds 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/efi/lds/elf_x86_64_efi.lds 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,89 @@ +/* Same as elf_x86_64_fbsd_efi.lds, except for OUTPUT_FORMAT below - KEEP IN SYNC */ +OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") +OUTPUT_ARCH(i386:x86-64) +ENTRY(_start) +SECTIONS +{ + . = 0; + ImageBase = .; + .hash : { *(.hash) } /* this MUST come first! */ + . = ALIGN(4096); + .eh_frame : + { + *(.eh_frame) + } + . = ALIGN(4096); + .text : + { + _text = .; + *(.text) + _etext = .; + } + . = ALIGN(4096); + .reloc : + { + *(.reloc) + } + . = ALIGN(4096); + .note.gnu.build-id : { + *(.note.gnu.build-id) + } + + . = ALIGN(4096); + .data.ident : { + *(.data.ident) + } + + . = ALIGN(4096); + .data : + { + _data = .; + *(.rodata*) + *(.got.plt) + *(.got) + *(.data*) + *(.sdata) + /* the EFI loader doesn't seem to like a .bss section, so we stick + it all into .data: */ + *(.sbss) + *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + *(.rel.local) + } + + . = ALIGN(4096); + .sbat : + { + _sbat = .; + *(.sbat) + *(.sbat.*) + _esbat = .; + } + . = ALIGN(4096); + .dynamic : { *(.dynamic) } + . = ALIGN(4096); + .rela : + { + *(.rela.data*) + *(.rela.got*) + *(.rela.stab*) + } + _edata = .; + _data_size = . - _data; + + . = ALIGN(4096); + .dynsym : { *(.dynsym) } + . = ALIGN(4096); + .dynstr : { *(.dynstr) } + . = ALIGN(4096); + .ignored.reloc : + { + *(.rela.reloc) + *(.eh_frame) + *(.note.GNU-stack) + } + .comment 0 : { *(.comment) } + .note.gnu.build-id : { *(.note.gnu.build-id) } +} diff -Nru fwupd-1.4.5/plugins/uefi-capsule/efi/meson.build fwupd-1.5.8/plugins/uefi-capsule/efi/meson.build --- fwupd-1.4.5/plugins/uefi-capsule/efi/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/efi/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,223 @@ +efi_cc = get_option('efi-cc') +efi_ld = get_option('efi-ld') +efi_objcopy = get_option('efi-objcopy') +efi_ldsdir = get_option('efi-ldsdir') +efi_incdir = get_option('efi-includedir') + +gnu_efi_path_arch = '' +foreach name : [gnu_efi_arch, EFI_MACHINE_TYPE_NAME] + if (gnu_efi_path_arch == '' and name != '' and + cc.has_header('@0@/@1@/efibind.h'.format(efi_incdir, name))) + gnu_efi_path_arch = name + endif +endforeach + +if gnu_efi_path_arch != '' and EFI_MACHINE_TYPE_NAME == '' + error('gnu-efi is available, but EFI_MACHINE_TYPE_NAME is unknown') +endif + +efi_libdir = get_option('efi-libdir') +if efi_libdir == '' + cmd = 'cd /usr/lib/$(@0@ -print-multi-os-directory) && pwd'.format(efi_cc) + ret = run_command('sh', '-c', cmd) + if ret.returncode() == 0 + efi_libdir = ret.stdout().strip() + endif +endif + +have_gnu_efi = gnu_efi_path_arch != '' and efi_libdir != '' + +if not have_gnu_efi + error('gnu-efi support requested, but headers were not found') +endif + +arch_lds = 'efi.lds' +arch_crt = 'crt0.o' +if efi_ldsdir == '' + efi_ldsdir = join_paths(efi_libdir, 'gnuefi', gnu_efi_path_arch) + cmd = run_command('test', '-f', join_paths(efi_ldsdir, arch_lds)) + if cmd.returncode() != 0 + arch_lds = 'elf_@0@_efi.lds'.format(gnu_efi_path_arch) + arch_crt = 'crt0-efi-@0@.o'.format(gnu_efi_path_arch) + efi_ldsdir = join_paths(efi_libdir, 'gnuefi') + cmd = run_command('test', '-f', join_paths(efi_ldsdir, arch_lds)) + endif + if cmd.returncode() != 0 + efi_ldsdir = efi_libdir + cmd = run_command('test', '-f', join_paths(efi_ldsdir, arch_lds)) + if cmd.returncode() != 0 + error('Cannot find @0@'.format(arch_lds)) + endif + endif +else + cmd = run_command('test', '-f', join_paths(efi_ldsdir, arch_lds)) + if cmd.returncode() != 0 + arch_lds = 'elf_@0@_efi.lds'.format(gnu_efi_path_arch) + arch_crt = 'crt0-efi-@0@.o'.format(gnu_efi_path_arch) + cmd = run_command('test', '-f', join_paths(efi_ldsdir, arch_lds)) + endif + if cmd.returncode() != 0 + error('Cannot find @0@'.format(arch_lds)) + endif +endif + +# is the system linker script new enough to know about SBAT? +# i.e. gnu-efi with https://github.com/vathpela/gnu-efi/pull/14 has been installed +efi_crtdir = efi_ldsdir +if get_option('efi_sbat_distro_id') != '' + cmd = run_command('grep', '-q', 'sbat', join_paths(efi_ldsdir, arch_lds)) + if cmd.returncode() != 0 + warning('Cannot find SBAT section in @0@, using local copy'.format(join_paths(efi_ldsdir, arch_lds))) + efi_ldsdir = join_paths(meson.current_source_dir(), 'lds') + endif +endif + +message('efi-libdir: "@0@"'.format(efi_libdir)) +message('efi-ldsdir: "@0@"'.format(efi_ldsdir)) +message('efi-crtdir: "@0@"'.format(efi_crtdir)) +message('efi-includedir: "@0@"'.format(efi_incdir)) + +debugdir = join_paths (libdir, 'debug') +compile_args = ['-Og', + '-g3', + '--param=ssp-buffer-size=4', + '-fexceptions', + '-Wall', + '-Wextra', + '-Wvla', + '-std=gnu11', + '-fpic', + '-fshort-wchar', + '-ffreestanding', + '-fno-strict-aliasing', + '-fno-stack-protector', + '-fno-stack-check', + '-fno-merge-constants', + '-Wsign-compare', + '-Wno-missing-field-initializers', + '-Wno-address-of-packed-member', + '-grecord-gcc-switches', + '-DDEBUGDIR="@0@"'.format(debugdir), + '-isystem', efi_incdir, + '-isystem', join_paths(efi_incdir, gnu_efi_path_arch)] +if get_option('werror') + compile_args += '-Werror' +endif +if host_cpu == 'x86_64' + compile_args += ['-mno-red-zone', + '-mno-sse', + '-mno-mmx', + '-DEFI_FUNCTION_WRAPPER', + '-DGNU_EFI_USE_MS_ABI'] +elif host_cpu == 'x86' + compile_args += ['-mno-sse', + '-mno-mmx', + '-mno-red-zone', + '-m32'] +# no special cases for aarch64 or arm +endif + +efi_ldflags = ['-T', + join_paths(efi_ldsdir, arch_lds), + '-shared', + '-Bsymbolic', + '-nostdlib', + '-znocombreloc', + '-L', efi_crtdir, + '-L', efi_libdir, + join_paths(efi_crtdir, arch_crt)] +if host_cpu == 'aarch64' or host_cpu == 'arm' + # Aarch64 and ARM32 don't have an EFI capable objcopy. Use 'binary' + # instead, and add required symbols manually. + efi_ldflags += ['--defsym=EFI_SUBSYSTEM=0xa'] + efi_format = ['-O', 'binary'] +else + efi_format = ['--target=efi-app-@0@'.format(gnu_efi_arch)] +endif + +libgcc_file_name = run_command(efi_cc, '-print-libgcc-file-name').stdout().strip() +efi_name = 'fwupd@0@.efi'.format(EFI_MACHINE_TYPE_NAME) + +o_file1 = custom_target('fwupdate.o', + input : 'fwupdate.c', + output : 'fwupdate.o', + command : [efi_cc, '-c', '@INPUT@', '-o', '@OUTPUT@'] + + compile_args) +o_file2 = custom_target('fwup-debug.o', + input : 'fwup-debug.c', + output : 'fwup-debug.o', + command : [efi_cc, '-c', '@INPUT@', '-o', '@OUTPUT@'] + + compile_args) +o_file3 = custom_target('fwup-efi.o', + input : 'fwup-efi.c', + output : 'fwup-efi.o', + command : [efi_cc, '-c', '@INPUT@', '-o', '@OUTPUT@'] + + compile_args) +o_file4 = custom_target('fwup-common.o', + input : 'fwup-common.c', + output : 'fwup-common.o', + command : [efi_cc, '-c', '@INPUT@', '-o', '@OUTPUT@'] + + compile_args) + +o_file5 = custom_target('fwup-sbat.o', + output : 'fwup-sbat.o', + command : [ + join_paths(meson.current_source_dir(), 'generate_sbat.py'), + '@OUTPUT@', + '--cc', efi_cc, + '--objcopy', efi_objcopy, + '--project-name', meson.project_name(), + '--project-version', meson.project_version(), + '--sbat-version', '1', + '--sbat-generation', '@0@'.format(get_option('efi_sbat_fwupd_generation')), + '--sbat-distro-id', get_option('efi_sbat_distro_id'), + '--sbat-distro-generation', '0', + '--sbat-distro-summary', get_option('efi_sbat_distro_summary'), + '--sbat-distro-pkgname', get_option('efi_sbat_distro_pkgname'), + '--sbat-distro-version', get_option('efi_sbat_distro_version'), + '--sbat-distro-url', get_option('efi_sbat_distro_url'), + ]) + +so = custom_target('fwup.so', + input : [o_file1, o_file2, o_file3, o_file4, o_file5], + output : 'fwup.so', + command : [efi_ld, '-o', '@OUTPUT@'] + + efi_ldflags + ['@INPUT@'] + + ['-lefi', '-lgnuefi', libgcc_file_name]) + +# sanity check the packager set this to *SOMETHING* +if get_option('efi_sbat_distro_id') == '' and get_option('supported_build') + warning('-Defi_sbat_distro_id is unset, see plugins/uefi-capsule/README.md') +endif + +app = custom_target(efi_name, + input : so, + output : efi_name, + command : [ + join_paths(meson.current_source_dir(), 'generate_binary.py'), + '@INPUT@', '@OUTPUT@', + '--arch', gnu_efi_arch, + '--objcopy', efi_objcopy, + ], + install : true, + install_dir : efi_app_location) + +dbg = custom_target('efi_debug', + input : so, + output : efi_name + '.debug', + command : [efi_objcopy, + '-j', '.text', + '-j', '.sdata', + '-j', '.data', + '-j', '.dynamic', + '-j', '.dynsym', + '-j', '.rel*', + '-j', '.rela*', + '-j', '.reloc', + '-j', '.eh_frame', + '-j', '.debug*', + '-j', '.note.gnu.build-id'] + + efi_format + + ['@INPUT@', '@OUTPUT@'], + install : false, + install_dir : debugdir) diff -Nru fwupd-1.4.5/plugins/uefi-capsule/fu-plugin-uefi-capsule.c fwupd-1.5.8/plugins/uefi-capsule/fu-plugin-uefi-capsule.c --- fwupd-1.4.5/plugins/uefi-capsule/fu-plugin-uefi-capsule.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/fu-plugin-uefi-capsule.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,864 @@ +/* + * Copyright (C) 2016 Richard Hughes + * Copyright (C) 2015 Peter Jones + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include +#include + +#include "fu-archive.h" +#include "fu-device-metadata.h" +#include "fu-plugin-vfuncs.h" + +#include "fu-uefi-bgrt.h" +#include "fu-uefi-bootmgr.h" +#include "fu-uefi-common.h" +#include "fu-uefi-device.h" +#include "fu-efivar.h" + +#ifndef HAVE_GIO_2_55_0 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUnixMountEntry, g_unix_mount_free) +#pragma clang diagnostic pop +#endif + +struct FuPluginData { + FuUefiBgrt *bgrt; + FuVolume *esp; +}; + +void +fu_plugin_init (FuPlugin *plugin) +{ + FuPluginData *data = fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); + data->bgrt = fu_uefi_bgrt_new (); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_AFTER, "upower"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_METADATA_SOURCE, "tpm"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_METADATA_SOURCE, "tpm_eventlog"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_METADATA_SOURCE, "dell"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_METADATA_SOURCE, "linux_lockdown"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_CONFLICTS, "uefi"); /* old name */ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + +void +fu_plugin_destroy (FuPlugin *plugin) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + if (data->esp != NULL) + g_object_unref (data->esp); + g_object_unref (data->bgrt); +} + +gboolean +fu_plugin_clear_results (FuPlugin *plugin, FuDevice *device, GError **error) +{ + FuUefiDevice *device_uefi = FU_UEFI_DEVICE (device); + return fu_uefi_device_clear_status (device_uefi, error); +} + +gboolean +fu_plugin_get_results (FuPlugin *plugin, FuDevice *device, GError **error) +{ + FuUefiDevice *device_uefi = FU_UEFI_DEVICE (device); + FuUefiDeviceStatus status = fu_uefi_device_get_status (device_uefi); + const gchar *tmp; + g_autofree gchar *err_msg = NULL; + g_autofree gchar *version_str = NULL; + g_autoptr(GError) error_local = NULL; + + /* trivial case */ + if (status == FU_UEFI_DEVICE_STATUS_SUCCESS) { + fu_device_set_update_state (device, FWUPD_UPDATE_STATE_SUCCESS); + return TRUE; + } + + /* check if something rudely removed our BOOTXXXX entry */ + if (!fu_uefi_bootmgr_verify_fwupd (&error_local)) { + if (fu_plugin_has_custom_flag (plugin, "boot-order-lock")) { + g_prefix_error (&error_local, + "boot entry missing; " + "perhaps 'Boot Order Lock' enabled in the BIOS: "); + fu_device_set_update_state (device, FWUPD_UPDATE_STATE_FAILED_TRANSIENT); + } else { + g_prefix_error (&error_local, "boot entry missing: "); + fu_device_set_update_state (device, FWUPD_UPDATE_STATE_FAILED); + } + fu_device_set_update_error (device, error_local->message); + return TRUE; + } + + /* something went wrong */ + if (status == FU_UEFI_DEVICE_STATUS_ERROR_PWR_EVT_AC || + status == FU_UEFI_DEVICE_STATUS_ERROR_PWR_EVT_BATT) { + fu_device_set_update_state (device, FWUPD_UPDATE_STATE_FAILED_TRANSIENT); + } else { + fu_device_set_update_state (device, FWUPD_UPDATE_STATE_FAILED); + } + version_str = g_strdup_printf ("%u", fu_uefi_device_get_version_error (device_uefi)); + tmp = fu_uefi_device_status_to_string (status); + if (tmp == NULL) { + err_msg = g_strdup_printf ("failed to update to %s", + version_str); + } else { + err_msg = g_strdup_printf ("failed to update to %s: %s", + version_str, tmp); + } + fu_device_set_update_error (device, err_msg); + return TRUE; +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GError) error = NULL; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fu_security_attrs_append (attrs, attr); + + /* SB not available or disabled */ + if (!fu_efivar_secure_boot_enabled_full (&error)) { + if (g_error_matches (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED)) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND); + return; + } + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); +} + +static GBytes * +fu_plugin_uefi_capsule_get_splash_data (guint width, guint height, GError **error) +{ + const gchar * const *langs = g_get_language_names (); + g_autofree gchar *datadir_pkg = NULL; + g_autofree gchar *filename_archive = NULL; + g_autofree gchar *langs_str = NULL; + g_autoptr(FuArchive) archive = NULL; + g_autoptr(GBytes) blob_archive = NULL; + + /* load archive */ + datadir_pkg = fu_common_get_path (FU_PATH_KIND_DATADIR_PKG); + filename_archive = g_build_filename (datadir_pkg, "uefi-capsule-ux.tar.xz", NULL); + blob_archive = fu_common_get_contents_bytes (filename_archive, error); + if (blob_archive == NULL) + return NULL; + archive = fu_archive_new (blob_archive, FU_ARCHIVE_FLAG_NONE, error); + if (archive == NULL) + return NULL; + + /* find the closest locale match, falling back to `en` and `C` */ + for (guint i = 0; langs[i] != NULL; i++) { + GBytes *blob_tmp; + g_autofree gchar *fn = NULL; + if (g_str_has_suffix (langs[i], ".UTF-8")) + continue; + fn = g_strdup_printf ("fwupd-%s-%u-%u.bmp", langs[i], width, height); + blob_tmp = fu_archive_lookup_by_fn (archive, fn, NULL); + if (blob_tmp != NULL) { + g_debug ("using UX image %s", fn); + return g_bytes_ref (blob_tmp); + } + g_debug ("no %s found", fn); + } + + /* we found nothing */ + langs_str = g_strjoinv (",", (gchar **) langs); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to get splash file for %s in %s", + langs_str, datadir_pkg); + return NULL; +} + +static guint8 +fu_plugin_uefi_capsule_calc_checksum (const guint8 *buf, gsize sz) +{ + guint8 csum = 0; + for (gsize i = 0; i < sz; i++) + csum += buf[i]; + return csum; +} + +static gboolean +fu_plugin_uefi_capsule_write_splash_data (FuPlugin *plugin, + FuDevice *device, + GBytes *blob, + GError **error) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + guint32 screen_x, screen_y; + gsize buf_size = g_bytes_get_size (blob); + gssize size; + guint32 height, width; + guint8 csum = 0; + efi_ux_capsule_header_t header = { 0 }; + efi_capsule_header_t capsule_header = { + .flags = EFI_CAPSULE_HEADER_FLAGS_PERSIST_ACROSS_RESET, + .guid = { 0x0 }, + .header_size = sizeof(efi_capsule_header_t), + .capsule_image_size = 0 + }; + g_autofree gchar *esp_path = NULL; + g_autofree gchar *fn = NULL; + g_autofree gchar *directory = NULL; + g_autofree gchar *basename = NULL; + g_autoptr(GFile) ofile = NULL; + g_autoptr(GOutputStream) ostream = NULL; + + /* get screen dimensions */ + if (!fu_uefi_get_framebuffer_size (&screen_x, &screen_y, error)) + return FALSE; + if (!fu_uefi_get_bitmap_size ((const guint8 *) g_bytes_get_data (blob, NULL), + buf_size, &width, &height, error)) { + g_prefix_error (error, "splash invalid: "); + return FALSE; + } + + /* save to a predicatable filename */ + esp_path = fu_volume_get_mount_point (data->esp); + directory = fu_uefi_get_esp_path_for_os (device, esp_path); + basename = g_strdup_printf ("fwupd-%s.cap", FU_EFIVAR_GUID_UX_CAPSULE); + fn = g_build_filename (directory, "fw", basename, NULL); + if (!fu_common_mkdir_parent (fn, error)) + return FALSE; + ofile = g_file_new_for_path (fn); + ostream = G_OUTPUT_STREAM (g_file_replace (ofile, NULL, FALSE, + G_FILE_CREATE_NONE, NULL, error)); + if (ostream == NULL) + return FALSE; + + if (!fwupd_guid_from_string (FU_EFIVAR_GUID_UX_CAPSULE, + &capsule_header.guid, + FWUPD_GUID_FLAG_MIXED_ENDIAN, + error)) + return FALSE; + capsule_header.capsule_image_size = + g_bytes_get_size (blob) + + sizeof(efi_capsule_header_t) + + sizeof(efi_ux_capsule_header_t); + + header.version = 1; + header.image_type = 0; + header.reserved = 0; + header.x_offset = (screen_x / 2) - (width / 2); + header.y_offset = fu_uefi_bgrt_get_yoffset (data->bgrt) + + fu_uefi_bgrt_get_height (data->bgrt); + + /* header, payload and image has to add to zero */ + csum += fu_plugin_uefi_capsule_calc_checksum ((guint8 *) &capsule_header, + sizeof(capsule_header)); + csum += fu_plugin_uefi_capsule_calc_checksum ((guint8 *) &header, + sizeof(header)); + csum += fu_plugin_uefi_capsule_calc_checksum (g_bytes_get_data (blob, NULL), + g_bytes_get_size (blob)); + header.checksum = 0x100 - csum; + + /* write capsule file */ + size = g_output_stream_write (ostream, &capsule_header, + capsule_header.header_size, NULL, error); + if (size < 0) + return FALSE; + size = g_output_stream_write (ostream, &header, sizeof(header), NULL, error); + if (size < 0) + return FALSE; + size = g_output_stream_write_bytes (ostream, blob, NULL, error); + if (size < 0) + return FALSE; + + /* write display capsule location as UPDATE_INFO */ + return fu_uefi_device_write_update_info (FU_UEFI_DEVICE (device), fn, + "fwupd-ux-capsule", + FU_EFIVAR_GUID_UX_CAPSULE, + error); +} + +static gboolean +fu_plugin_uefi_capsule_update_splash (FuPlugin *plugin, FuDevice *device, GError **error) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + guint best_idx = G_MAXUINT; + guint32 lowest_border_pixels = G_MAXUINT; + guint32 screen_height = 768; + guint32 screen_width = 1024; + g_autoptr(GBytes) image_bmp = NULL; + + struct { + guint32 width; + guint32 height; + } sizes[] = { + { 640, 480 }, /* matching the sizes in po/make-images */ + { 800, 600 }, + { 1024, 768 }, + { 1920, 1080 }, + { 3840, 2160 }, + { 5120, 2880 }, + { 5688, 3200 }, + { 7680, 4320 }, + { 0, 0 } + }; + + /* no UX capsule support, so deleting var if it exists */ + if (fu_device_has_custom_flag (device, "no-ux-capsule")) { + g_debug ("not providing UX capsule"); + return fu_efivar_delete (FU_EFIVAR_GUID_FWUPDATE, + "fwupd-ux-capsule", error); + } + + /* get the boot graphics resource table data */ + if (!fu_uefi_bgrt_get_supported (data->bgrt)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "BGRT is not supported"); + return FALSE; + } + if (!fu_uefi_get_framebuffer_size (&screen_width, &screen_height, error)) + return FALSE; + g_debug ("framebuffer size %" G_GUINT32_FORMAT " x%" G_GUINT32_FORMAT, + screen_width, screen_height); + + /* find the 'best sized' pre-generated image */ + for (guint i = 0; sizes[i].width != 0; i++) { + guint32 border_pixels; + + /* disregard any images that are bigger than the screen */ + if (sizes[i].width > screen_width) + continue; + if (sizes[i].height > screen_height) + continue; + + /* is this the best fit for the display */ + border_pixels = (screen_width * screen_height) - + (sizes[i].width * sizes[i].height); + if (border_pixels < lowest_border_pixels) { + lowest_border_pixels = border_pixels; + best_idx = i; + } + } + if (best_idx == G_MAXUINT) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to find a suitable image to use"); + return FALSE; + } + + /* get the raw data */ + image_bmp = fu_plugin_uefi_capsule_get_splash_data (sizes[best_idx].width, + sizes[best_idx].height, + error); + if (image_bmp == NULL) + return FALSE; + + /* perform the upload */ + return fu_plugin_uefi_capsule_write_splash_data (plugin, device, image_bmp, error); +} + +gboolean +fu_plugin_update (FuPlugin *plugin, + FuDevice *device, + GBytes *blob_fw, + FwupdInstallFlags flags, + GError **error) +{ + const gchar *str; + guint32 flashes_left; + g_autoptr(GError) error_splash = NULL; + + /* test the flash counter */ + flashes_left = fu_device_get_flashes_left (device); + if (flashes_left > 0) { + g_debug ("%s has %" G_GUINT32_FORMAT " flashes left", + fu_device_get_name (device), + flashes_left); + if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0 && flashes_left <= 2) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "%s only has %" G_GUINT32_FORMAT " flashes left -- " + "see https://github.com/fwupd/fwupd/wiki/Dell-TPM:-flashes-left for more information.", + fu_device_get_name (device), flashes_left); + return FALSE; + } + } + + /* TRANSLATORS: this is shown when updating the firmware after the reboot */ + str = _("Installing firmware update…"); + g_assert (str != NULL); + + /* perform the update */ + fu_device_set_status (device, FWUPD_STATUS_SCHEDULING); + if (!fu_plugin_uefi_capsule_update_splash (plugin, device, &error_splash)) { + g_debug ("failed to upload UEFI UX capsule text: %s", + error_splash->message); + } + + return fu_device_write_firmware (device, blob_fw, flags, error); +} + +static void +fu_plugin_uefi_capsule_load_config (FuPlugin *plugin, FuDevice *device) +{ + gboolean disable_shim; + gboolean fallback_removable_path; + guint64 sz_reqd = FU_UEFI_COMMON_REQUIRED_ESP_FREE_SPACE; + g_autofree gchar *require_esp_free_space = NULL; + + /* parse free space needed for ESP */ + require_esp_free_space = fu_plugin_get_config_value (plugin, "RequireESPFreeSpace"); + if (require_esp_free_space != NULL) + sz_reqd = fu_common_strtoull (require_esp_free_space); + fu_device_set_metadata_integer (device, "RequireESPFreeSpace", sz_reqd); + + /* shim used for SB or not? */ + disable_shim = fu_plugin_get_config_value_boolean (plugin, "DisableShimForSecureBoot"); + fu_device_set_metadata_boolean (device, + "RequireShimForSecureBoot", + !disable_shim); + + /* check if using UEFI removeable path */ + fallback_removable_path = fu_plugin_get_config_value_boolean (plugin, "FallbacktoRemovablePath"); + fu_device_set_metadata_boolean (device, + "FallbacktoRemovablePath", + fallback_removable_path); +} + +static void +fu_plugin_uefi_capsule_register_proxy_device (FuPlugin *plugin, FuDevice *device) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + g_autoptr(FuUefiDevice) dev = fu_uefi_device_new_from_dev (device); + g_autoptr(GError) error_local = NULL; + + /* load all configuration variables */ + fu_plugin_uefi_capsule_load_config (plugin, FU_DEVICE (dev)); + if (data->esp == NULL) + data->esp = fu_common_get_esp_default (&error_local); + if (data->esp == NULL) { + fu_device_set_update_error (FU_DEVICE (dev), error_local->message); + fu_device_remove_flag (FU_DEVICE (dev), FWUPD_DEVICE_FLAG_UPDATABLE); + } else { + fu_uefi_device_set_esp (dev, data->esp); + } + fu_plugin_device_add (plugin, FU_DEVICE (dev)); +} + +void +fu_plugin_device_registered (FuPlugin *plugin, FuDevice *device) +{ + if (fu_device_get_metadata (device, FU_DEVICE_METADATA_UEFI_DEVICE_KIND) != NULL) { + if (fu_device_get_guid_default (device) == NULL) { + g_autofree gchar *dbg = fu_device_to_string (device); + g_warning ("cannot create proxy device as no GUID: %s", dbg); + return; + } + fu_plugin_uefi_capsule_register_proxy_device (plugin, device); + } +} + +static const gchar * +fu_plugin_uefi_capsule_uefi_type_to_string (FuUefiDeviceKind device_kind) +{ + if (device_kind == FU_UEFI_DEVICE_KIND_UNKNOWN) + return "Unknown Firmware"; + if (device_kind == FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE) + return "System Firmware"; + if (device_kind == FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE) + return "Device Firmware"; + if (device_kind == FU_UEFI_DEVICE_KIND_UEFI_DRIVER) + return "UEFI Driver"; + if (device_kind == FU_UEFI_DEVICE_KIND_FMP) + return "Firmware Management Protocol"; + return NULL; +} + +static gchar * +fu_plugin_uefi_capsule_get_name_for_type (FuPlugin *plugin, FuUefiDeviceKind device_kind) +{ + GString *display_name; + + /* set Display Name prefix for capsules that are not PCI cards */ + display_name = g_string_new (fu_plugin_uefi_capsule_uefi_type_to_string (device_kind)); + if (device_kind == FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE) + g_string_prepend (display_name, "UEFI "); + return g_string_free (display_name, FALSE); +} + +static gboolean +fu_plugin_uefi_capsule_coldplug_device (FuPlugin *plugin, FuUefiDevice *dev, GError **error) +{ + FuUefiDeviceKind device_kind; + + /* probe to get add GUIDs (and hence any quirk fixups) */ + if (!fu_device_probe (FU_DEVICE (dev), error)) + return FALSE; + if (!fu_device_setup (FU_DEVICE (dev), error)) + return FALSE; + + /* if not already set by quirks */ + if (fu_device_get_custom_flags (FU_DEVICE (dev)) == NULL && + fu_plugin_has_custom_flag (plugin, "use-legacy-bootmgr-desc")) { + fu_device_set_custom_flags (FU_DEVICE (dev), "use-legacy-bootmgr-desc"); + } + + /* set fallback name if nothing else is set */ + device_kind = fu_uefi_device_get_kind (dev); + if (fu_device_get_name (FU_DEVICE (dev)) == NULL) { + g_autofree gchar *name = NULL; + name = fu_plugin_uefi_capsule_get_name_for_type (plugin, device_kind); + if (name != NULL) + fu_device_set_name (FU_DEVICE (dev), name); + if (device_kind != FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE) { + fu_device_add_internal_flag (FU_DEVICE (dev), + FU_DEVICE_INTERNAL_FLAG_MD_SET_NAME_CATEGORY); + } + } + /* set fallback vendor if nothing else is set */ + if (fu_device_get_vendor (FU_DEVICE (dev)) == NULL && + device_kind == FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE) { + const gchar *vendor = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_MANUFACTURER); + if (vendor != NULL) + fu_device_set_vendor (FU_DEVICE (dev), vendor); + } + + /* set vendor ID as the BIOS vendor */ + if (device_kind != FU_UEFI_DEVICE_KIND_FMP) { + const gchar *dmi_vendor; + dmi_vendor = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_BIOS_VENDOR); + if (dmi_vendor != NULL) { + g_autofree gchar *vendor_id = g_strdup_printf ("DMI:%s", dmi_vendor); + fu_device_add_vendor_id (FU_DEVICE (dev), vendor_id); + } + } + + /* success */ + return TRUE; +} + +static void +fu_plugin_uefi_capsule_test_secure_boot (FuPlugin *plugin) +{ + const gchar *result_str = "Disabled"; + if (fu_efivar_secure_boot_enabled ()) + result_str = "Enabled"; + fu_plugin_add_report_metadata (plugin, "SecureBoot", result_str); +} + +static gboolean +fu_plugin_uefi_capsule_smbios_enabled (FuPlugin *plugin, GError **error) +{ + const guint8 *data; + gsize sz; + g_autoptr(GBytes) bios_information = fu_plugin_get_smbios_data (plugin, 0); + if (bios_information == NULL) { + const gchar *tmp = g_getenv ("FWUPD_DELL_FAKE_SMBIOS"); + if (tmp != NULL) + return TRUE; + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "SMBIOS not supported"); + return FALSE; + } + data = g_bytes_get_data (bios_information, &sz); + if (sz < 0x13) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "offset bigger than size %" G_GSIZE_FORMAT, sz); + return FALSE; + } + if (data[1] < 0x13) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "SMBIOS 2.3 not supported"); + return FALSE; + } + if (!(data[0x13] & (1 << 3))) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "System does not support UEFI mode"); + return FALSE; + } + return TRUE; +} + +gboolean +fu_plugin_startup (FuPlugin *plugin, GError **error) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + guint64 nvram_total; + g_autofree gchar *esp_path = NULL; + g_autofree gchar *nvram_total_str = NULL; + g_autoptr(GError) error_local = NULL; + + /* don't let user's environment influence test suite failures */ + if (g_getenv ("FWUPD_UEFI_TEST") != NULL) + return TRUE; + + /* for the uploaded report */ + if (fu_plugin_has_custom_flag (plugin, "use-legacy-bootmgr-desc")) + fu_plugin_add_report_metadata (plugin, "BootMgrDesc", "legacy"); + + /* some platforms have broken SMBIOS data */ + if (fu_plugin_has_custom_flag (plugin, "uefi-force-enable")) + return TRUE; + + /* check SMBIOS for 'UEFI Specification is supported' */ + if (!fu_plugin_uefi_capsule_smbios_enabled (plugin, &error_local)) { + g_autofree gchar *fw = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); + g_autofree gchar *fn = g_build_filename (fw, "efi", NULL); + if (g_file_test (fn, G_FILE_TEST_EXISTS)) { + g_warning ("SMBIOS BIOS Characteristics Extension Byte 2 is invalid -- " + "UEFI Specification is unsupported, but %s exists: %s", + fn, error_local->message); + return TRUE; + } + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; + } + + /* are the EFI dirs set up so we can update each device */ + if (!fu_efivar_supported (error)) + return FALSE; + nvram_total = fu_efivar_space_used (error); + if (nvram_total == G_MAXUINT64) + return FALSE; + nvram_total_str = g_strdup_printf ("%" G_GUINT64_FORMAT, nvram_total); + fu_plugin_add_report_metadata (plugin, "EfivarNvramUsed", nvram_total_str); + + /* override the default ESP path */ + esp_path = fu_plugin_get_config_value (plugin, "OverrideESPMountPoint"); + if (esp_path != NULL) { + data->esp = fu_common_get_esp_for_path (esp_path, error); + if (data->esp == NULL) { + g_prefix_error (error, "invalid OverrideESPMountPoint=%s " + "specified in config: ", esp_path); + return FALSE; + } + } + + /* test for invalid ESP in coldplug, and set the update-error rather + * than showing no output if the plugin had self-disabled here */ + return TRUE; +} + +static gboolean +fu_plugin_uefi_capsule_ensure_efivarfs_rw (GError **error) +{ + g_autofree gchar *sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); + g_autofree gchar *sysfsefivardir = g_build_filename (sysfsfwdir, "efi", "efivars", NULL); + g_autoptr(GUnixMountEntry) mount = g_unix_mount_at (sysfsefivardir, NULL); + + if (mount == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "%s was not mounted", sysfsefivardir); + return FALSE; + } + if (g_unix_mount_is_readonly (mount)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "%s is read only", sysfsefivardir); + return FALSE; + } + + return TRUE; +} + +gboolean +fu_plugin_unlock (FuPlugin *plugin, FuDevice *device, GError **error) +{ + FuUefiDevice *device_uefi = FU_UEFI_DEVICE (device); + FuDevice *device_alt = NULL; + FwupdDeviceFlags device_flags_alt = 0; + guint flashes_left = 0; + guint flashes_left_alt = 0; + + if (fu_uefi_device_get_kind (device_uefi) != + FU_UEFI_DEVICE_KIND_DELL_TPM_FIRMWARE) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Unable to unlock %s", + fu_device_get_name (device)); + return FALSE; + } + + /* for unlocking TPM1.2 <-> TPM2.0 switching */ + g_debug ("Unlocking upgrades for: %s (%s)", fu_device_get_name (device), + fu_device_get_id (device)); + device_alt = fu_device_get_alternate (device); + if (device_alt == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "No alternate device for %s", + fu_device_get_name (device)); + return FALSE; + } + g_debug ("Preventing upgrades for: %s (%s)", fu_device_get_name (device_alt), + fu_device_get_id (device_alt)); + + flashes_left = fu_device_get_flashes_left (device); + flashes_left_alt = fu_device_get_flashes_left (device_alt); + if (flashes_left == 0) { + /* flashes left == 0 on both means no flashes left */ + if (flashes_left_alt == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "ERROR: %s has no flashes left.", + fu_device_get_name (device)); + /* flashes left == 0 on just unlocking device is ownership */ + } else { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "ERROR: %s is currently OWNED. " + "Ownership must be removed to switch modes.", + fu_device_get_name (device_alt)); + } + return FALSE; + } + + /* clone the info from real device but prevent it from being flashed */ + device_flags_alt = fu_device_get_flags (device_alt); + fu_device_set_flags (device, device_flags_alt); + fu_device_remove_flag (device_alt, FWUPD_DEVICE_FLAG_UPDATABLE); + + /* make sure that this unlocked device can be updated */ + fu_device_set_version_format (device, FWUPD_VERSION_FORMAT_QUAD); + fu_device_set_version (device, "0.0.0.0"); + return TRUE; +} + +static void +fu_plugin_uefi_update_state_notify_cb (GObject *object, + GParamSpec *pspec, + FuPlugin *plugin) +{ + FuDevice *device = FU_DEVICE (object); + GPtrArray *devices; + g_autofree gchar *msg = NULL; + + /* device is not in needs-reboot state */ + if (fu_device_get_update_state (device) != FWUPD_UPDATE_STATE_NEEDS_REBOOT) + return; + + /* only do this on hardware that cannot coalesce multiple capsules */ + if (!fu_plugin_has_custom_flag (plugin, "no-coalesce")) + return; + + /* mark every other device for this plugin as non-updatable */ + msg = g_strdup_printf ("Cannot update as %s [%s] needs reboot", + fu_device_get_name (device), + fu_device_get_id (device)); + devices = fu_plugin_get_devices (plugin); + for (guint i = 0; i < devices->len; i++) { + FuDevice *device_tmp = g_ptr_array_index (devices, i); + if (device_tmp == device) + continue; + fu_device_remove_flag (device_tmp, FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_flag (device_tmp, FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN); + fu_device_set_update_error (device_tmp, msg); + } +} + +gboolean +fu_plugin_coldplug (FuPlugin *plugin, GError **error) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + const gchar *str; + g_autofree gchar *esrt_path = NULL; + g_autofree gchar *sysfsfwdir = NULL; + g_autoptr(GError) error_udisks2 = NULL; + g_autoptr(GError) error_efivarfs = NULL; + g_autoptr(GError) error_local = NULL; + g_autoptr(GPtrArray) entries = NULL; + + /* get the directory of ESRT entries */ + sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); + esrt_path = g_build_filename (sysfsfwdir, "efi", "esrt", NULL); + entries = fu_uefi_get_esrt_entry_paths (esrt_path, error); + if (entries == NULL) + return FALSE; + + /* make sure that efivarfs is rw */ + if (!fu_plugin_uefi_capsule_ensure_efivarfs_rw (&error_efivarfs)) { + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_EFIVAR_NOT_MOUNTED); + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE); + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_USER_WARNING); + g_warning ("%s", error_efivarfs->message); + } + + if (data->esp == NULL) { + data->esp = fu_common_get_esp_default (&error_udisks2); + if (data->esp == NULL) { + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_ESP_NOT_FOUND); + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE); + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_USER_WARNING); + g_warning ("cannot find default ESP: %s", error_udisks2->message); + } + } + + /* add each device */ + for (guint i = 0; i < entries->len; i++) { + const gchar *path = g_ptr_array_index (entries, i); + g_autoptr(GError) error_parse = NULL; + g_autoptr(FuUefiDevice) dev = fu_uefi_device_new_from_entry (path, &error_parse); + if (dev == NULL) { + g_warning ("failed to add %s: %s", path, error_parse->message); + continue; + } + fu_device_set_quirks (FU_DEVICE (dev), fu_plugin_get_quirks (plugin)); + if (data->esp != NULL) + fu_uefi_device_set_esp (FU_UEFI_DEVICE (dev), data->esp); + if (!fu_plugin_uefi_capsule_coldplug_device (plugin, dev, error)) + return FALSE; + fu_device_add_flag (FU_DEVICE (dev), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_flag (FU_DEVICE (dev), FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE); + + /* load all configuration variables */ + fu_plugin_uefi_capsule_load_config (plugin, FU_DEVICE (dev)); + + /* watch in case we set needs-reboot in the engine */ + g_signal_connect (dev, "notify::update-state", + G_CALLBACK (fu_plugin_uefi_update_state_notify_cb), + plugin); + + fu_plugin_device_add (plugin, FU_DEVICE (dev)); + } + + /* for debugging problems later */ + fu_plugin_uefi_capsule_test_secure_boot (plugin); + if (!fu_uefi_bgrt_setup (data->bgrt, &error_local)) + g_debug ("BGRT setup failed: %s", error_local->message); + str = fu_uefi_bgrt_get_supported (data->bgrt) ? "Enabled" : "Disabled"; + g_debug ("UX Capsule support : %s", str); + fu_plugin_add_report_metadata (plugin, "UEFIUXCapsule", str); + + return TRUE; +} diff -Nru fwupd-1.4.5/plugins/uefi-capsule/fu-self-test.c fwupd-1.5.8/plugins/uefi-capsule/fu-self-test.c --- fwupd-1.4.5/plugins/uefi-capsule/fu-self-test.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/fu-self-test.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-ucs2.h" +#include "fu-uefi-bgrt.h" +#include "fu-uefi-common.h" +#include "fu-uefi-device.h" +#include "fu-uefi-pcrs.h" + +#include "fwupd-error.h" + +static void +fu_uefi_pcrs_1_2_func (void) +{ + gboolean ret; + g_autoptr(FuUefiPcrs) pcrs = fu_uefi_pcrs_new (); + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) pcr0s = NULL; + g_autoptr(GPtrArray) pcrXs = NULL; + + g_setenv ("FWUPD_SYSFSTPMDIR", TESTDATADIR, TRUE); + + ret = fu_uefi_pcrs_setup (pcrs, &error); + g_assert_no_error (error); + g_assert_true (ret); + pcr0s = fu_uefi_pcrs_get_checksums (pcrs, 0); + g_assert_nonnull (pcr0s); + g_assert_cmpint (pcr0s->len, ==, 1); + pcrXs = fu_uefi_pcrs_get_checksums (pcrs, 999); + g_assert_nonnull (pcrXs); + g_assert_cmpint (pcrXs->len, ==, 0); + + g_unsetenv ("FWUPD_SYSFSTPMDIR"); +} + +static void +fu_uefi_pcrs_2_0_func (void) +{ + g_autoptr(FuUefiPcrs) pcrs = fu_uefi_pcrs_new (); + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) pcr0s = NULL; + g_autoptr(GPtrArray) pcrXs = NULL; + const gchar *tpm_server_running = g_getenv ("TPM_SERVER_RUNNING"); + g_setenv ("FWUPD_FORCE_TPM2", "1", TRUE); + +#ifndef HAVE_TSS2 + g_test_skip ("Compiled without TPM2.0 support"); + return; +#endif + +#ifdef HAVE_GETUID + if (tpm_server_running == NULL && + (getuid () != 0 || geteuid () != 0)) { + g_test_skip ("TPM2.0 tests require simulated TPM2.0 running or need root access with physical TPM"); + return; + } +#endif + + if (!fu_uefi_pcrs_setup (pcrs, &error)) { + if (tpm_server_running == NULL && + g_error_matches (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND)) { + g_test_skip ("no physical or simulated TPM 2.0 device available"); + return; + } + } + g_assert_no_error (error); + pcr0s = fu_uefi_pcrs_get_checksums (pcrs, 0); + g_assert_nonnull (pcr0s); + g_assert_cmpint (pcr0s->len, >=, 1); + pcrXs = fu_uefi_pcrs_get_checksums (pcrs, 999); + g_assert_nonnull (pcrXs); + g_assert_cmpint (pcrXs->len, ==, 0); + g_unsetenv ("FWUPD_FORCE_TPM2"); +} + +static void +fu_uefi_ucs2_func (void) +{ + g_autofree guint16 *str1 = NULL; + g_autofree gchar *str2 = NULL; + str1 = fu_uft8_to_ucs2 ("hw!", -1); + g_assert_cmpint (fu_ucs2_strlen (str1, -1), ==, 3); + str2 = fu_ucs2_to_uft8 (str1, -1); + g_assert_cmpstr ("hw!", ==, str2); +} + +static void +fu_uefi_bgrt_func (void) +{ + gboolean ret; + g_autoptr(GError) error = NULL; + g_autoptr(FuUefiBgrt) bgrt = fu_uefi_bgrt_new (); + ret = fu_uefi_bgrt_setup (bgrt, &error); + g_assert_no_error (error); + g_assert_true (ret); + g_assert_true (fu_uefi_bgrt_get_supported (bgrt)); + g_assert_cmpint (fu_uefi_bgrt_get_xoffset (bgrt), ==, 123); + g_assert_cmpint (fu_uefi_bgrt_get_yoffset (bgrt), ==, 456); + g_assert_cmpint (fu_uefi_bgrt_get_width (bgrt), ==, 54); + g_assert_cmpint (fu_uefi_bgrt_get_height (bgrt), ==, 24); +} + +static void +fu_uefi_framebuffer_func (void) +{ + gboolean ret; + guint32 height = 0; + guint32 width = 0; + g_autoptr(GError) error = NULL; + ret = fu_uefi_get_framebuffer_size (&width, &height, &error); + g_assert_no_error (error); + g_assert_true (ret); + g_assert_cmpint (width, ==, 456); + g_assert_cmpint (height, ==, 789); +} + +static void +fu_uefi_bitmap_func (void) +{ + gboolean ret; + gsize sz = 0; + guint32 height = 0; + guint32 width = 0; + g_autofree gchar *fn = NULL; + g_autofree gchar *buf = NULL; + g_autoptr(GError) error = NULL; + + fn = g_build_filename (TESTDATADIR, "test.bmp", NULL); + ret = g_file_get_contents (fn, &buf, &sz, &error); + g_assert_no_error (error); + g_assert_true (ret); + g_assert_nonnull (buf); + ret = fu_uefi_get_bitmap_size ((guint8 *)buf, sz, &width, &height, &error); + g_assert_no_error (error); + g_assert_true (ret); + g_assert_cmpint (width, ==, 54); + g_assert_cmpint (height, ==, 24); +} + +static void +fu_uefi_device_func (void) +{ + g_autofree gchar *fn = NULL; + g_autoptr(FuUefiDevice) dev = NULL; + g_autoptr(GError) error = NULL; + + fn = g_build_filename (TESTDATADIR, "efi/esrt/entries/entry0", NULL); + dev = fu_uefi_device_new_from_entry (fn, &error); + g_assert_nonnull (dev); + g_assert_no_error (error); + + g_assert_cmpint (fu_uefi_device_get_kind (dev), ==, FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE); + g_assert_cmpstr (fu_uefi_device_get_guid (dev), ==, "ddc0ee61-e7f0-4e7d-acc5-c070a398838e"); + g_assert_cmpint (fu_uefi_device_get_hardware_instance (dev), ==, 0x0); + g_assert_cmpint (fu_uefi_device_get_version (dev), ==, 65586); + g_assert_cmpint (fu_uefi_device_get_version_lowest (dev), ==, 65582); + g_assert_cmpint (fu_uefi_device_get_version_error (dev), ==, 18472960); + g_assert_cmpint (fu_uefi_device_get_capsule_flags (dev), ==, 0xfe); + g_assert_cmpint (fu_uefi_device_get_status (dev), ==, FU_UEFI_DEVICE_STATUS_ERROR_UNSUCCESSFUL); + + /* check enums all converted */ + for (guint i = 0; i < FU_UEFI_DEVICE_STATUS_LAST; i++) + g_assert_nonnull (fu_uefi_device_status_to_string (i)); +} + +static void +fu_uefi_plugin_func (void) +{ + FuUefiDevice *dev; + g_autofree gchar *esrt_path = NULL; + g_autofree gchar *sysfsfwdir = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) devices = NULL; + g_autoptr(GPtrArray) entries = NULL; + + /* add each device */ + sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); + esrt_path = g_build_filename (sysfsfwdir, "efi", "esrt", NULL); + entries = fu_uefi_get_esrt_entry_paths (esrt_path, &error); + g_assert_no_error (error); + g_assert_nonnull (entries); + devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + for (guint i = 0; i < entries->len; i++) { + const gchar *path = g_ptr_array_index (entries, i); + g_autoptr(GError) error_local = NULL; + g_autoptr(FuUefiDevice) dev_tmp = fu_uefi_device_new_from_entry (path, &error_local); + if (dev_tmp == NULL) { + g_debug ("failed to add %s: %s", path, error_local->message); + continue; + } + g_ptr_array_add (devices, g_object_ref (dev_tmp)); + } + g_assert_cmpint (devices->len, ==, 2); + + /* system firmware */ + dev = g_ptr_array_index (devices, 0); + g_assert_cmpint (fu_uefi_device_get_kind (dev), ==, FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE); + g_assert_cmpstr (fu_uefi_device_get_guid (dev), ==, "ddc0ee61-e7f0-4e7d-acc5-c070a398838e"); + g_assert_cmpint (fu_uefi_device_get_version (dev), ==, 65586); + g_assert_cmpint (fu_uefi_device_get_version_lowest (dev), ==, 65582); + g_assert_cmpint (fu_uefi_device_get_version_error (dev), ==, 18472960); + g_assert_cmpint (fu_uefi_device_get_capsule_flags (dev), ==, 0xfe); + g_assert_cmpint (fu_uefi_device_get_status (dev), ==, FU_UEFI_DEVICE_STATUS_ERROR_UNSUCCESSFUL); + + /* system firmware */ + dev = g_ptr_array_index (devices, 1); + g_assert_cmpint (fu_uefi_device_get_kind (dev), ==, FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE); + g_assert_cmpstr (fu_uefi_device_get_guid (dev), ==, "671d19d0-d43c-4852-98d9-1ce16f9967e4"); + g_assert_cmpint (fu_uefi_device_get_version (dev), ==, 3090287969); + g_assert_cmpint (fu_uefi_device_get_version_lowest (dev), ==, 1); + g_assert_cmpint (fu_uefi_device_get_version_error (dev), ==, 0); + g_assert_cmpint (fu_uefi_device_get_capsule_flags (dev), ==, 32784); + g_assert_cmpint (fu_uefi_device_get_status (dev), ==, FU_UEFI_DEVICE_STATUS_SUCCESS); +} + +static void +fu_uefi_update_info_func (void) +{ + g_autofree gchar *fn = NULL; + g_autoptr(FuUefiDevice) dev = NULL; + g_autoptr(FuUefiUpdateInfo) info = NULL; + g_autoptr(GError) error = NULL; + + fn = g_build_filename (TESTDATADIR, "efi/esrt/entries/entry0", NULL); + dev = fu_uefi_device_new_from_entry (fn, &error); + g_assert_no_error (error); + g_assert_nonnull (dev); + g_assert_cmpint (fu_uefi_device_get_kind (dev), ==, FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE); + g_assert_cmpstr (fu_uefi_device_get_guid (dev), ==, "ddc0ee61-e7f0-4e7d-acc5-c070a398838e"); + info = fu_uefi_device_load_update_info (dev, &error); + g_assert_no_error (error); + g_assert_nonnull (info); + g_assert_cmpint (fu_uefi_update_info_get_version (info), ==, 0x7); + g_assert_cmpstr (fu_uefi_update_info_get_guid (info), ==, "697bd920-12cf-4da9-8385-996909bc6559"); + g_assert_cmpint (fu_uefi_update_info_get_capsule_flags (info), ==, 0x50000); + g_assert_cmpint (fu_uefi_update_info_get_hw_inst (info), ==, 0x0); + g_assert_cmpint (fu_uefi_update_info_get_status (info), ==, FU_UEFI_UPDATE_INFO_STATUS_ATTEMPT_UPDATE); + g_assert_cmpstr (fu_uefi_update_info_get_capsule_fn (info), ==, + "/EFI/fedora/fw/fwupd-697bd920-12cf-4da9-8385-996909bc6559.cap"); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + g_setenv ("FWUPD_SYSFSFWDIR", TESTDATADIR, TRUE); + g_setenv ("FWUPD_SYSFSDRIVERDIR", TESTDATADIR, TRUE); + + /* only critical and error are fatal */ + g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); + g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); + + /* tests go here */ + g_test_add_func ("/uefi/pcrs1.2", fu_uefi_pcrs_1_2_func); + g_test_add_func ("/uefi/pcrs2.0", fu_uefi_pcrs_2_0_func); + g_test_add_func ("/uefi/ucs2", fu_uefi_ucs2_func); + g_test_add_func ("/uefi/bgrt", fu_uefi_bgrt_func); + g_test_add_func ("/uefi/framebuffer", fu_uefi_framebuffer_func); + g_test_add_func ("/uefi/bitmap", fu_uefi_bitmap_func); + g_test_add_func ("/uefi/device", fu_uefi_device_func); + g_test_add_func ("/uefi/update-info", fu_uefi_update_info_func); + g_test_add_func ("/uefi/plugin", fu_uefi_plugin_func); + return g_test_run (); +} diff -Nru fwupd-1.4.5/plugins/uefi-capsule/fu-ucs2.c fwupd-1.5.8/plugins/uefi-capsule/fu-ucs2.c --- fwupd-1.4.5/plugins/uefi-capsule/fu-ucs2.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/fu-ucs2.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2018 Richard Hughes + * Copyright (C) 2015 Peter Jones + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-ucs2.h" + +#define ev_bits(val, mask, shift) (((val) & ((mask) << (shift))) >> (shift)) + +gchar * +fu_ucs2_to_uft8 (const guint16 *str, gssize max) +{ + gssize i, j; + gchar *ret; + + if (max < 0) + max = fu_ucs2_strlen (str, max); + ret = g_malloc0 (max * 3 + 1); /* would be s/3/6 if this were UCS-4 */ + for (i = 0, j = 0; i < max && str[i]; i++, j++) { + if (str[i] <= 0x7f) { + ret[j] = str[i]; + } else if (str[i] > 0x7f && str[i] <= 0x7ff) { + ret[j++] = 0xc0 | ev_bits(str[i], 0x1f, 6); + ret[j] = 0x80 | ev_bits(str[i], 0x3f, 0); + } else if (str[i] > 0x7ff /* && str[i] < 0x10000 */ ) { + ret[j++] = 0xe0 | ev_bits(str[i], 0xf, 12); + ret[j++] = 0x80 | ev_bits(str[i], 0x3f, 6); + ret[j] = 0x80 | ev_bits(str[i], 0x3f, 0); + } + } + return ret; +} + +guint16 * +fu_uft8_to_ucs2 (const gchar *str, gssize max) +{ + gssize i, j; + guint16 *ret = g_new0 (guint16, g_utf8_strlen (str, max) + 1); + for (i = 0, j = 0; i < (max >= 0 ? max : i + 1) && str[i] != '\0'; j++) { + guint32 val = 0; + if ((str[i] & 0xe0) == 0xe0 && !(str[i] & 0x10)) { + val = ((str[i+0] & 0x0f) << 10) + |((str[i+1] & 0x3f) << 6) + |((str[i+2] & 0x3f) << 0); + i += 3; + } else if ((str[i] & 0xc0) == 0xc0 && !(str[i] & 0x20)) { + val = ((str[i+0] & 0x1f) << 6) + |((str[i+1] & 0x3f) << 0); + i += 2; + } else { + val = str[i] & 0x7f; + i += 1; + } + ret[j] = val; + } + ret[j] = L'\0'; + return ret; +} + +gsize +fu_ucs2_strlen (const guint16 *str, gssize limit) +{ + gssize i; + for (i = 0; i < (limit >= 0 ? limit : i + 1) && str[i] != L'\0'; i++); + return i; +} diff -Nru fwupd-1.4.5/plugins/uefi-capsule/fu-ucs2.h fwupd-1.5.8/plugins/uefi-capsule/fu-ucs2.h --- fwupd-1.4.5/plugins/uefi-capsule/fu-ucs2.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/fu-ucs2.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2018 Richard Hughes + * Copyright (C) 2015 Peter Jones + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +gsize fu_ucs2_strlen (const guint16 *str, + gssize limit); +guint16 *fu_uft8_to_ucs2 (const gchar *str, + gssize max); +gchar *fu_ucs2_to_uft8 (const guint16 *str, + gssize max); diff -Nru fwupd-1.4.5/plugins/uefi-capsule/fu-uefi-bgrt.c fwupd-1.5.8/plugins/uefi-capsule/fu-uefi-bgrt.c --- fwupd-1.4.5/plugins/uefi-capsule/fu-uefi-bgrt.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/fu-uefi-bgrt.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-common.h" +#include "fu-uefi-bgrt.h" +#include "fu-uefi-common.h" + +struct _FuUefiBgrt { + GObject parent_instance; + guint32 xoffset; + guint32 yoffset; + guint32 width; + guint32 height; +}; + +G_DEFINE_TYPE (FuUefiBgrt, fu_uefi_bgrt, G_TYPE_OBJECT) + +gboolean +fu_uefi_bgrt_setup (FuUefiBgrt *self, GError **error) +{ + gsize sz = 0; + guint64 type; + guint64 version; + g_autofree gchar *bgrtdir = NULL; + g_autofree gchar *data = NULL; + g_autofree gchar *imagefn = NULL; + g_autofree gchar *sysfsfwdir = NULL; + + g_return_val_if_fail (FU_IS_UEFI_BGRT (self), FALSE); + + sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); + bgrtdir = g_build_filename (sysfsfwdir, "acpi", "bgrt", NULL); + if (!g_file_test (bgrtdir, G_FILE_TEST_EXISTS)) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "BGRT is not supported"); + return FALSE; + } + type = fu_uefi_read_file_as_uint64 (bgrtdir, "type"); + if (type != 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "BGRT type was %" G_GUINT64_FORMAT, type); + return FALSE; + } + version = fu_uefi_read_file_as_uint64 (bgrtdir, "version"); + if (version != 1) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "BGRT version was %" G_GUINT64_FORMAT, version); + return FALSE; + } + + /* load image */ + self->xoffset = fu_uefi_read_file_as_uint64 (bgrtdir, "xoffset"); + self->yoffset = fu_uefi_read_file_as_uint64 (bgrtdir, "yoffset"); + imagefn = g_build_filename (bgrtdir, "image", NULL); + if (!g_file_get_contents (imagefn, &data, &sz, error)) { + g_prefix_error (error, "failed to load BGRT image: "); + return FALSE; + } + if (!fu_uefi_get_bitmap_size ((guint8 *) data, sz, + &self->width, &self->height, error)) { + g_prefix_error (error, "BGRT image invalid: "); + return FALSE; + } + + /* success */ + return TRUE; +} + +gboolean +fu_uefi_bgrt_get_supported (FuUefiBgrt *self) +{ + g_return_val_if_fail (FU_IS_UEFI_BGRT (self), FALSE); + if (self->width == 0 || self->height == 0) + return FALSE; + return TRUE; +} + +guint32 +fu_uefi_bgrt_get_xoffset (FuUefiBgrt *self) +{ + g_return_val_if_fail (FU_IS_UEFI_BGRT (self), 0); + return self->xoffset; +} + +guint32 +fu_uefi_bgrt_get_yoffset (FuUefiBgrt *self) +{ + g_return_val_if_fail (FU_IS_UEFI_BGRT (self), 0); + return self->yoffset; +} + +guint32 +fu_uefi_bgrt_get_width (FuUefiBgrt *self) +{ + g_return_val_if_fail (FU_IS_UEFI_BGRT (self), 0); + return self->width; +} + +guint32 +fu_uefi_bgrt_get_height (FuUefiBgrt *self) +{ + g_return_val_if_fail (FU_IS_UEFI_BGRT (self), 0); + return self->height; +} + +static void +fu_uefi_bgrt_class_init (FuUefiBgrtClass *klass) +{ +} + +static void +fu_uefi_bgrt_init (FuUefiBgrt *self) +{ +} + +FuUefiBgrt * +fu_uefi_bgrt_new (void) +{ + FuUefiBgrt *self; + self = g_object_new (FU_TYPE_UEFI_BGRT, NULL); + return FU_UEFI_BGRT (self); +} diff -Nru fwupd-1.4.5/plugins/uefi-capsule/fu-uefi-bgrt.h fwupd-1.5.8/plugins/uefi-capsule/fu-uefi-bgrt.h --- fwupd-1.4.5/plugins/uefi-capsule/fu-uefi-bgrt.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/fu-uefi-bgrt.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2017 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#define FU_TYPE_UEFI_BGRT (fu_uefi_bgrt_get_type ()) +G_DECLARE_FINAL_TYPE (FuUefiBgrt, fu_uefi_bgrt, FU, UEFI_BGRT, GObject) + +FuUefiBgrt *fu_uefi_bgrt_new (void); +gboolean fu_uefi_bgrt_setup (FuUefiBgrt *self, + GError **error); +gboolean fu_uefi_bgrt_get_supported (FuUefiBgrt *self); +guint32 fu_uefi_bgrt_get_xoffset (FuUefiBgrt *self); +guint32 fu_uefi_bgrt_get_yoffset (FuUefiBgrt *self); +guint32 fu_uefi_bgrt_get_width (FuUefiBgrt *self); +guint32 fu_uefi_bgrt_get_height (FuUefiBgrt *self); diff -Nru fwupd-1.4.5/plugins/uefi-capsule/fu-uefi-bootmgr.c fwupd-1.5.8/plugins/uefi-capsule/fu-uefi-bootmgr.c --- fwupd-1.4.5/plugins/uefi-capsule/fu-uefi-bootmgr.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/fu-uefi-bootmgr.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,447 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include +#include + +#include "fwupd-error.h" + +#include "fu-ucs2.h" +#include "fu-uefi-bootmgr.h" +#include "fu-uefi-common.h" +#include "fu-efivar.h" + +/* XXX PJFIX: this should be in efiboot-loadopt.h in efivar */ +#define LOAD_OPTION_ACTIVE 0x00000001 + +static gboolean +fu_uefi_bootmgr_add_to_boot_order (guint16 boot_entry, GError **error) +{ + gsize boot_order_size = 0; + guint i = 0; + guint32 attr = 0; + g_autofree guint16 *boot_order = NULL; + g_autofree guint16 *new_boot_order = NULL; + + /* get the current boot order */ + if (!fu_efivar_get_data (FU_EFIVAR_GUID_EFI_GLOBAL, "BootOrder", + (guint8 **) &boot_order, &boot_order_size, + &attr, error)) + return FALSE; + + /* already set next */ + for (i = 0; i < boot_order_size / sizeof (guint16); i++) { + guint16 val = boot_order[i]; + if (val == boot_entry) + return TRUE; + } + + /* add the new boot index to the end of the list */ + new_boot_order = g_malloc0 (boot_order_size + sizeof (guint16)); + if (boot_order_size != 0) + memcpy (new_boot_order, boot_order, boot_order_size); + + attr |= FU_EFIVAR_ATTR_NON_VOLATILE | + FU_EFIVAR_ATTR_BOOTSERVICE_ACCESS | + FU_EFIVAR_ATTR_RUNTIME_ACCESS; + + i = boot_order_size / sizeof (guint16); + new_boot_order[i] = boot_entry; + boot_order_size += sizeof (guint16); + return fu_efivar_set_data (FU_EFIVAR_GUID_EFI_GLOBAL, "BootOrder", + (guint8 *)new_boot_order, boot_order_size, + attr, error); +} + +static guint16 +fu_uefi_bootmgr_parse_name (const gchar *name) +{ + gint rc; + gint scanned = 0; + guint16 entry = 0; + + /* BootXXXX */ + rc = sscanf (name, "Boot%hX%n", &entry, &scanned); + if (rc != 1 || scanned != 8) + return G_MAXUINT16; + return entry; +} + +gboolean +fu_uefi_bootmgr_verify_fwupd (GError **error) +{ + g_autoptr(GPtrArray) names = NULL; + + names = fu_efivar_get_names (FU_EFIVAR_GUID_EFI_GLOBAL, error); + if (names == NULL) + return FALSE; + for (guint i = 0; i < names->len; i++) { + const gchar *desc; + const gchar *name = g_ptr_array_index (names, i); + efi_load_option *loadopt; + gsize var_data_size = 0; + guint16 entry; + g_autofree guint8 *var_data_tmp = NULL; + g_autoptr(GError) error_local = NULL; + + /* not BootXXXX */ + entry = fu_uefi_bootmgr_parse_name (name); + if (entry == G_MAXUINT16) + continue; + + /* parse key */ + if (!fu_efivar_get_data (FU_EFIVAR_GUID_EFI_GLOBAL, name, + &var_data_tmp, &var_data_size, + NULL, &error_local)) { + g_debug ("failed to get data for name %s: %s", + name, error_local->message); + continue; + } + loadopt = (efi_load_option *) var_data_tmp; + if (!efi_loadopt_is_valid(loadopt, var_data_size)) { + g_debug ("%s -> load option was invalid", name); + continue; + } + + desc = (const gchar *) efi_loadopt_desc (loadopt, var_data_size); + if (g_strcmp0 (desc, "Linux Firmware Updater") == 0 || + g_strcmp0 (desc, "Linux-Firmware-Updater") == 0) { + g_debug ("found %s at Boot%04X", desc, entry); + return TRUE; + } + } + + /* did not find */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "no 'Linux Firmware Updater' entry found"); + return FALSE; +} + +static gboolean +fu_uefi_setup_bootnext_with_dp (const guint8 *dp_buf, guint8 *opt, gssize opt_size, GError **error) +{ + const gchar *desc; + const gchar *name; + efi_load_option *loadopt = NULL; + gsize var_data_size = 0; + guint32 attr; + guint16 boot_next = G_MAXUINT16; + g_autofree guint8 *var_data = NULL; + g_autofree guint8 *set_entries = g_malloc0 (G_MAXUINT16); + g_autoptr(GPtrArray) names = NULL; + + names = fu_efivar_get_names (FU_EFIVAR_GUID_EFI_GLOBAL, error); + if (names == NULL) + return FALSE; + for (guint i = 0; i < names->len; i++) { + guint16 entry = 0; + g_autofree guint8 *var_data_tmp = NULL; + g_autoptr(GError) error_local = NULL; + + /* not BootXXXX */ + name = g_ptr_array_index (names, i); + entry = fu_uefi_bootmgr_parse_name (name); + if (entry == G_MAXUINT16) + continue; + + /* mark this as used */ + set_entries[entry] = 1; + + if (!fu_efivar_get_data (FU_EFIVAR_GUID_EFI_GLOBAL, name, + &var_data_tmp, &var_data_size, + &attr, &error_local)) { + g_debug ("failed to get data for name %s: %s", + name, error_local->message); + continue; + } + + loadopt = (efi_load_option *)var_data_tmp; + if (!efi_loadopt_is_valid(loadopt, var_data_size)) { + g_debug ("%s -> load option was invalid", name); + continue; + } + + desc = (const gchar *) efi_loadopt_desc (loadopt, var_data_size); + if (g_strcmp0 (desc, "Linux Firmware Updater") != 0 && + g_strcmp0 (desc, "Linux-Firmware-Updater") != 0) { + g_debug ("%s -> '%s' : does not match", name, desc); + continue; + } + + var_data = g_steal_pointer (&var_data_tmp); + boot_next = entry; + break; + } + + /* already exists */ + if (var_data != NULL) { + /* is different than before */ + if (var_data_size != (gsize) opt_size || + memcmp (var_data, opt, opt_size) != 0) { + g_debug ("%s -> '%s' : updating existing boot entry", name, desc); + efi_loadopt_attr_set (loadopt, LOAD_OPTION_ACTIVE); + if (!fu_efivar_set_data (FU_EFIVAR_GUID_EFI_GLOBAL, + name, opt, opt_size, attr, error)) { + g_prefix_error (error, + "could not set boot variable active: "); + return FALSE; + } + } else { + g_debug ("%s -> %s : re-using existing boot entry", name, desc); + } + /* create a new one */ + } else { + g_autofree gchar *boot_next_name = NULL; + for (guint16 value = 0; value < G_MAXUINT16; value++) { + if (set_entries[value]) + continue; + boot_next = value; + break; + } + if (boot_next == G_MAXUINT16) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "no free boot variables (tried %x)", + boot_next); + return FALSE; + } + boot_next_name = g_strdup_printf ("Boot%04X", (guint) boot_next); + g_debug ("%s -> creating new entry", boot_next_name); + if (!fu_efivar_set_data (FU_EFIVAR_GUID_EFI_GLOBAL, + boot_next_name, opt, opt_size, + FU_EFIVAR_ATTR_NON_VOLATILE | + FU_EFIVAR_ATTR_BOOTSERVICE_ACCESS | + FU_EFIVAR_ATTR_RUNTIME_ACCESS, + error)) { + g_prefix_error (error, + "could not set boot variable %s: ", + boot_next_name); + return FALSE; + } + } + + /* TODO: conditionalize this on the UEFI version? */ + if(!fu_uefi_bootmgr_add_to_boot_order (boot_next, error)) + return FALSE; + + /* set the boot next */ + if (!fu_efivar_set_data (FU_EFIVAR_GUID_EFI_GLOBAL, + "BootNext", (guint8 *)&boot_next, 2, + FU_EFIVAR_ATTR_NON_VOLATILE | + FU_EFIVAR_ATTR_BOOTSERVICE_ACCESS | + FU_EFIVAR_ATTR_RUNTIME_ACCESS, + error)) { + g_prefix_error (error, + "could not set BootNext(%" G_GUINT16_FORMAT "): ", + boot_next); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_uefi_cmp_asset (const gchar *source, const gchar *target) +{ + gsize len = 0; + g_autofree gchar *source_checksum = NULL; + g_autofree gchar *source_data = NULL; + g_autofree gchar *target_checksum = NULL; + g_autofree gchar *target_data = NULL; + + /* nothing in target yet */ + if (!g_file_test (target, G_FILE_TEST_EXISTS)) + return FALSE; + + /* test if the file needs to be updated */ + if (!g_file_get_contents (source, &source_data, &len, NULL)) + return FALSE; + source_checksum = g_compute_checksum_for_data (G_CHECKSUM_SHA256, + (guchar *) source_data, len); + if (!g_file_get_contents (target, &target_data, &len, NULL)) + return FALSE; + target_checksum = g_compute_checksum_for_data (G_CHECKSUM_SHA256, + (guchar *) target_data, len); + return g_strcmp0 (target_checksum, source_checksum) == 0; +} + +static gboolean +fu_uefi_copy_asset (const gchar *source, const gchar *target, GError **error) +{ + g_autoptr(GFile) source_file = g_file_new_for_path (source); + g_autoptr(GFile) target_file = g_file_new_for_path (target); + + if (!g_file_copy (source_file, + target_file, + G_FILE_COPY_OVERWRITE, + NULL, + NULL, + NULL, + error)) { + g_prefix_error (error, "Failed to copy %s to %s: ", + source, target); + return FALSE; + } + + return TRUE; +} + +gboolean +fu_uefi_bootmgr_bootnext (FuDevice *device, + const gchar *esp_path, + const gchar *description, + FuUefiBootmgrFlags flags, + GError **error) +{ + const gchar *filepath; + gboolean use_fwup_path = TRUE; + gboolean secure_boot = FALSE; + gsize loader_sz = 0; + gssize opt_size = 0; + gssize sz, dp_size = 0; + guint32 attributes = LOAD_OPTION_ACTIVE; + g_autofree guint16 *loader_str = NULL; + g_autofree gchar *label = NULL; + g_autofree gchar *shim_app = NULL; + g_autofree gchar *shim_cpy = NULL; + g_autofree guint8 *dp_buf = NULL; + g_autofree guint8 *opt = NULL; + g_autofree gchar *source_app = NULL; + g_autofree gchar *target_app = NULL; + + /* skip for self tests */ + if (g_getenv ("FWUPD_UEFI_TEST") != NULL) + return TRUE; + + /* if secure boot was turned on this might need to be installed separately */ + source_app = fu_uefi_get_built_app_path (error); + if (source_app == NULL) + return FALSE; + + /* test if we should use shim */ + secure_boot = fu_efivar_secure_boot_enabled (); + if (secure_boot) { + /* test to make sure shim is there if we need it */ + shim_app = fu_uefi_get_esp_app_path (device, esp_path, "shim", error); + if (shim_app == NULL) + return FALSE; + + /* try to fallback to use UEFI removable path if the shim path doesn't exist */ + if (!g_file_test (shim_app, G_FILE_TEST_EXISTS)) { + if (fu_device_get_metadata_boolean (device, "FallbacktoRemovablePath")) { + shim_app = fu_uefi_get_esp_app_path (device, esp_path, "boot", error); + if (shim_app == NULL) + return FALSE; + } + } + + if (g_file_test (shim_app, G_FILE_TEST_EXISTS)) { + /* use a custom copy of shim for firmware updates */ + if (flags & FU_UEFI_BOOTMGR_FLAG_USE_SHIM_UNIQUE) { + shim_cpy = fu_uefi_get_esp_app_path (device, esp_path, "shimfwupd", error); + if (shim_cpy == NULL) + return FALSE; + if (!fu_uefi_cmp_asset (shim_app, shim_cpy)) { + if (!fu_uefi_copy_asset (shim_app, shim_cpy, error)) + return FALSE; + } + filepath = shim_cpy; + } else { + filepath = shim_app; + } + use_fwup_path = FALSE; + } else if ((flags & FU_UEFI_BOOTMGR_FLAG_USE_SHIM_FOR_SB) > 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_BROKEN_SYSTEM, + "Secure boot is enabled, but shim isn't installed to the EFI system partition"); + return FALSE; + } + } + + /* test if correct asset in place */ + target_app = fu_uefi_get_esp_app_path (device, esp_path, "fwupd", error); + if (target_app == NULL) + return FALSE; + if (!fu_uefi_cmp_asset (source_app, target_app)) { + if (!fu_uefi_copy_asset (source_app, target_app, error)) + return FALSE; + } + + /* no shim, so use this directly */ + if (use_fwup_path) + filepath = target_app; + + /* generate device path for target */ + sz = efi_generate_file_device_path (dp_buf, dp_size, filepath, + EFIBOOT_OPTIONS_IGNORE_FS_ERROR| + EFIBOOT_ABBREV_HD); + if (sz < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "efi_generate_file_device_path(%s) failed", + filepath); + return FALSE; + } + + /* add the fwupdx64.efi ESP path as the shim loadopt data */ + dp_size = sz; + dp_buf = g_malloc0 (dp_size); + if (!use_fwup_path) { + g_autofree gchar *fwup_fs_basename = g_path_get_basename (target_app); + g_autofree gchar *fwup_esp_path = g_strdup_printf ("\\%s", fwup_fs_basename); + loader_str = fu_uft8_to_ucs2 (fwup_esp_path, -1); + loader_sz = fu_ucs2_strlen (loader_str, -1) * 2; + if (loader_sz) + loader_sz += 2; + } + + sz = efi_generate_file_device_path (dp_buf, dp_size, filepath, + EFIBOOT_OPTIONS_IGNORE_FS_ERROR| + EFIBOOT_ABBREV_HD); + if (sz != dp_size) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "efi_generate_file_device_path(%s) failed", + filepath); + return FALSE; + } + + label = g_strdup (description); + sz = efi_loadopt_create (opt, opt_size, attributes, + (efidp)dp_buf, dp_size, + (guint8 *)label, + (guint8 *)loader_str, loader_sz); + if (sz < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "efi_loadopt_create(%s) failed", + label); + return FALSE; + } + opt = g_malloc0 (sz); + opt_size = sz; + sz = efi_loadopt_create (opt, opt_size, attributes, + (efidp)dp_buf, dp_size, + (guint8 *)label, + (guint8 *)loader_str, loader_sz); + if (sz != opt_size) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "loadopt size was unreasonable."); + return FALSE; + } + return fu_uefi_setup_bootnext_with_dp (dp_buf, opt, opt_size, error); +} diff -Nru fwupd-1.4.5/plugins/uefi-capsule/fu-uefi-bootmgr.h fwupd-1.5.8/plugins/uefi-capsule/fu-uefi-bootmgr.h --- fwupd-1.4.5/plugins/uefi-capsule/fu-uefi-bootmgr.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/fu-uefi-bootmgr.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2018 Richard Hughes + * Copyright (C) 2015 Peter Jones + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include +#include + +#include "fu-device.h" + +typedef enum { + FU_UEFI_BOOTMGR_FLAG_NONE = 0, + FU_UEFI_BOOTMGR_FLAG_USE_SHIM_FOR_SB = 1 << 0, + FU_UEFI_BOOTMGR_FLAG_USE_SHIM_UNIQUE = 1 << 1, + FU_UEFI_BOOTMGR_FLAG_LAST +} FuUefiBootmgrFlags; + +gboolean fu_uefi_bootmgr_verify_fwupd (GError **error); +gboolean fu_uefi_bootmgr_bootnext (FuDevice *device, + const gchar *esp_path, + const gchar *description, + FuUefiBootmgrFlags flags, + GError **error); diff -Nru fwupd-1.4.5/plugins/uefi-capsule/fu-uefi-common.c fwupd-1.5.8/plugins/uefi-capsule/fu-uefi-common.c --- fwupd-1.4.5/plugins/uefi-capsule/fu-uefi-common.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/fu-uefi-common.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2018 Richard Hughes + * Copyright (C) 2015 Peter Jones + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" +#include "fu-uefi-common.h" +#include "fu-efivar.h" + +#include "fwupd-common.h" +#include "fwupd-error.h" + +static const gchar * +fu_uefi_bootmgr_get_suffix (GError **error) +{ + guint64 firmware_bits; + struct { + guint64 bits; + const gchar *arch; + } suffixes[] = { +#if defined(__x86_64__) + { 64, "x64" }, +#elif defined(__aarch64__) + { 64, "aa64" }, +#endif +#if defined(__x86_64__) || defined(__i386__) || defined(__i686__) + { 32, "ia32" }, +#endif + { 0, NULL } + }; + g_autofree gchar *sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); + g_autofree gchar *sysfsefidir = g_build_filename (sysfsfwdir, "efi", NULL); + firmware_bits = fu_uefi_read_file_as_uint64 (sysfsefidir, "fw_platform_size"); + if (firmware_bits == 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "%s/fw_platform_size cannot be found", + sysfsefidir); + return NULL; + } + for (guint i = 0; suffixes[i].arch != NULL; i++) { + if (firmware_bits != suffixes[i].bits) + continue; + return suffixes[i].arch; + } + + /* this should exist */ + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "%s/fw_platform_size has unknown value %" G_GUINT64_FORMAT, + sysfsefidir, firmware_bits); + return NULL; +} + +gchar * +fu_uefi_get_esp_app_path (FuDevice *device, + const gchar *esp_path, + const gchar *cmd, + GError **error) +{ + const gchar *suffix = fu_uefi_bootmgr_get_suffix (error); + g_autofree gchar *base = NULL; + if (suffix == NULL) + return NULL; + base = fu_uefi_get_esp_path_for_os (device, esp_path); + return g_strdup_printf ("%s/%s%s.efi", base, cmd, suffix); +} + +gchar * +fu_uefi_get_built_app_path (GError **error) +{ + const gchar *extension = ""; + const gchar *suffix; + g_autofree gchar *source_path = NULL; + g_autofree gchar *prefix = NULL; + if (fu_efivar_secure_boot_enabled ()) + extension = ".signed"; + suffix = fu_uefi_bootmgr_get_suffix (error); + if (suffix == NULL) + return NULL; + prefix = fu_common_get_path (FU_PATH_KIND_EFIAPPDIR); + source_path = g_strdup_printf ("%s/fwupd%s.efi%s", + prefix, + suffix, + extension); + if (!g_file_test (source_path, G_FILE_TEST_EXISTS)) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "%s cannot be found", + source_path); + return NULL; + } + return g_steal_pointer (&source_path); +} + +gboolean +fu_uefi_get_framebuffer_size (guint32 *width, guint32 *height, GError **error) +{ + guint32 height_tmp; + guint32 width_tmp; + g_autofree gchar *sysfsdriverdir = NULL; + g_autofree gchar *fbdir = NULL; + + sysfsdriverdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_DRIVERS); + fbdir = g_build_filename (sysfsdriverdir, "efi-framebuffer", "efi-framebuffer.0", NULL); + if (!g_file_test (fbdir, G_FILE_TEST_EXISTS)) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "EFI framebuffer not found"); + return FALSE; + } + height_tmp = fu_uefi_read_file_as_uint64 (fbdir, "height"); + width_tmp = fu_uefi_read_file_as_uint64 (fbdir, "width"); + if (width_tmp == 0 || height_tmp == 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "EFI framebuffer has invalid size " + "%"G_GUINT32_FORMAT"x%"G_GUINT32_FORMAT, + width_tmp, height_tmp); + return FALSE; + } + if (width != NULL) + *width = width_tmp; + if (height != NULL) + *height = height_tmp; + return TRUE; +} + +gboolean +fu_uefi_get_bitmap_size (const guint8 *buf, + gsize bufsz, + guint32 *width, + guint32 *height, + GError **error) +{ + guint32 ui32; + + g_return_val_if_fail (buf != NULL, FALSE); + + /* check header */ + if (bufsz < 26 || memcmp (buf, "BM", 2) != 0) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid BMP header signature"); + return FALSE; + } + + /* starting address */ + if (!fu_common_read_uint32_safe (buf, bufsz, 10, &ui32, G_LITTLE_ENDIAN, error)) + return FALSE; + if (ui32 < 26) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "BMP header invalid @ %"G_GUINT32_FORMAT"x", ui32); + return FALSE; + } + + /* BITMAPINFOHEADER header */ + if (!fu_common_read_uint32_safe (buf, bufsz, 14, &ui32, G_LITTLE_ENDIAN, error)) + return FALSE; + if (ui32 < 26 - 14) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "BITMAPINFOHEADER invalid @ %"G_GUINT32_FORMAT"x", ui32); + return FALSE; + } + + /* dimensions */ + if (width != NULL) { + if (!fu_common_read_uint32_safe (buf, bufsz, 18, width, + G_LITTLE_ENDIAN, error)) + return FALSE; + } + if (height != NULL) { + if (!fu_common_read_uint32_safe (buf, bufsz, 22, height, + G_LITTLE_ENDIAN, error)) + return FALSE; + } + return TRUE; +} + +static gint +fu_uefi_strcmp_sort_cb (gconstpointer a, gconstpointer b) +{ + const gchar *stra = *((const gchar **) a); + const gchar *strb = *((const gchar **) b); + return g_strcmp0 (stra, strb); +} + +GPtrArray * +fu_uefi_get_esrt_entry_paths (const gchar *esrt_path, GError **error) +{ + GPtrArray *entries = g_ptr_array_new_with_free_func (g_free); + const gchar *fn; + g_autofree gchar *esrt_entries = NULL; + g_autoptr(GDir) dir = NULL; + + /* search ESRT */ + esrt_entries = g_build_filename (esrt_path, "entries", NULL); + dir = g_dir_open (esrt_entries, 0, error); + if (dir == NULL) + return NULL; + while ((fn = g_dir_read_name (dir)) != NULL) + g_ptr_array_add (entries, g_build_filename (esrt_entries, fn, NULL)); + + /* sort by name */ + g_ptr_array_sort (entries, fu_uefi_strcmp_sort_cb); + return entries; +} + +gchar * +fu_uefi_get_esp_path_for_os (FuDevice *device, const gchar *base) +{ +#ifndef EFI_OS_DIR + const gchar *os_release_id = NULL; + const gchar *id_like_id = NULL; + g_autofree gchar *esp_path = NULL; + g_autoptr(GError) error_local = NULL; + g_autoptr(GHashTable) os_release = fwupd_get_os_release (&error_local); + /* try to lookup /etc/os-release ID key */ + if (os_release != NULL) { + os_release_id = g_hash_table_lookup (os_release, "ID"); + } else { + g_debug ("failed to get ID: %s", error_local->message); + } + if (os_release_id == NULL) + os_release_id = "unknown"; + /* if ID key points at something existing return it */ + esp_path = g_build_filename (base, "EFI", os_release_id, NULL); + if (g_file_test (esp_path, G_FILE_TEST_IS_DIR) || os_release == NULL) + return g_steal_pointer (&esp_path); + /* if ID key doesn't exist, try ID_LIKE */ + id_like_id = g_hash_table_lookup (os_release, "ID_LIKE"); + if (id_like_id != NULL) { + g_autofree gchar* id_like_path = g_build_filename (base, "EFI", id_like_id, NULL); + if (g_file_test (id_like_path, G_FILE_TEST_IS_DIR)) { + g_debug ("Using ID_LIKE key from os-release"); + return g_steal_pointer (&id_like_path); + } + } + /* try to fallback to use UEFI removable path if ID_LIKE path doesn't exist */ + if (fu_device_get_metadata_boolean (device, "FallbacktoRemovablePath")) { + esp_path = g_build_filename (base, "EFI", "boot", NULL); + if (!g_file_test (esp_path, G_FILE_TEST_IS_DIR)) + g_debug ("failed to fallback due to missing %s", esp_path); + } + return g_steal_pointer (&esp_path); +#else + return g_build_filename (base, "EFI", EFI_OS_DIR, NULL); +#endif +} + +guint64 +fu_uefi_read_file_as_uint64 (const gchar *path, const gchar *attr_name) +{ + g_autofree gchar *data = NULL; + g_autofree gchar *fn = g_build_filename (path, attr_name, NULL); + if (!g_file_get_contents (fn, &data, NULL, NULL)) + return 0x0; + return fu_common_strtoull (data); +} diff -Nru fwupd-1.4.5/plugins/uefi-capsule/fu-uefi-common.h fwupd-1.5.8/plugins/uefi-capsule/fu-uefi-common.h --- fwupd-1.4.5/plugins/uefi-capsule/fu-uefi-common.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/fu-uefi-common.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2018 Richard Hughes + * Copyright (C) 2015 Peter Jones + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#include "fwupd-common.h" + +#include "fu-device.h" + +#define EFI_CAPSULE_HEADER_FLAGS_PERSIST_ACROSS_RESET 0x00010000 +#define EFI_CAPSULE_HEADER_FLAGS_POPULATE_SYSTEM_TABLE 0x00020000 +#define EFI_CAPSULE_HEADER_FLAGS_INITIATE_RESET 0x00040000 + +typedef struct __attribute__((__packed__)) { + guint16 year; + guint8 month; + guint8 day; + guint8 hour; + guint8 minute; + guint8 second; + guint8 pad1; + guint32 nanosecond; + guint16 timezone; + guint8 daylight; + guint8 pad2; +} efi_time_t; + +typedef struct __attribute__((__packed__)) { + fwupd_guid_t guid; + guint32 header_size; + guint32 flags; + guint32 capsule_image_size; +} efi_capsule_header_t; + +typedef struct __attribute__((__packed__)) { + guint8 version; + guint8 checksum; + guint8 image_type; + guint8 reserved; + guint32 mode; + guint32 x_offset; + guint32 y_offset; +} efi_ux_capsule_header_t; + +typedef struct __attribute__((__packed__)) { + guint32 update_info_version; + fwupd_guid_t guid; + guint32 capsule_flags; + guint64 hw_inst; + efi_time_t time_attempted; + guint32 status; +} efi_update_info_t; + +/* the biggest size SPI part currently seen */ +#define FU_UEFI_COMMON_REQUIRED_ESP_FREE_SPACE (32 * 1024 * 1024) + +gchar *fu_uefi_get_esp_app_path (FuDevice *device, + const gchar *esp_path, + const gchar *cmd, + GError **error); +gchar *fu_uefi_get_built_app_path (GError **error); +gboolean fu_uefi_get_bitmap_size (const guint8 *buf, + gsize bufsz, + guint32 *width, + guint32 *height, + GError **error); +gboolean fu_uefi_get_framebuffer_size (guint32 *width, + guint32 *height, + GError **error); +gchar *fu_uefi_get_esp_path_for_os (FuDevice *device, + const gchar *esp_path); +GPtrArray *fu_uefi_get_esrt_entry_paths (const gchar *esrt_path, + GError **error); +guint64 fu_uefi_read_file_as_uint64 (const gchar *path, + const gchar *attr_name); diff -Nru fwupd-1.4.5/plugins/uefi-capsule/fu-uefi-device.c fwupd-1.5.8/plugins/uefi-capsule/fu-uefi-device.c --- fwupd-1.4.5/plugins/uefi-capsule/fu-uefi-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/fu-uefi-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,832 @@ +/* + * Copyright (C) 2018 Richard Hughes + * Copyright (C) 2015 Peter Jones + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include +#include + +#include "fu-device-metadata.h" + +#include "fu-common.h" + +#include "fu-uefi-common.h" +#include "fu-uefi-device.h" +#include "fu-uefi-devpath.h" +#include "fu-uefi-bootmgr.h" +#include "fu-uefi-pcrs.h" +#include "fu-efivar.h" + +struct _FuUefiDevice { + FuDevice parent_instance; + FuVolume *esp; + FuDeviceLocker *esp_locker; + gchar *fw_class; + FuUefiDeviceKind kind; + guint32 capsule_flags; + guint32 fw_version; + guint32 fw_version_lowest; + FuUefiDeviceStatus last_attempt_status; + guint32 last_attempt_version; + guint64 fmp_hardware_instance; + gboolean missing_header; + gboolean automounted_esp; + gboolean requires_header; +}; + +G_DEFINE_TYPE (FuUefiDevice, fu_uefi_device, FU_TYPE_DEVICE) + +void +fu_uefi_device_set_esp (FuUefiDevice *self, FuVolume *esp) +{ + g_return_if_fail (FU_IS_UEFI_DEVICE (self)); + g_return_if_fail (FU_IS_VOLUME (esp)); + g_set_object (&self->esp, esp); +} + +const gchar * +fu_uefi_device_kind_to_string (FuUefiDeviceKind kind) +{ + if (kind == FU_UEFI_DEVICE_KIND_UNKNOWN) + return "unknown"; + if (kind == FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE) + return "system-firmware"; + if (kind == FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE) + return "device-firmware"; + if (kind == FU_UEFI_DEVICE_KIND_UEFI_DRIVER) + return "uefi-driver"; + if (kind == FU_UEFI_DEVICE_KIND_FMP) + return "fmp"; + if (kind == FU_UEFI_DEVICE_KIND_DELL_TPM_FIRMWARE) + return "dell-tpm-firmware"; + return NULL; +} + +static FuUefiDeviceKind +fu_uefi_device_kind_from_string (const gchar *kind) +{ + if (g_strcmp0 (kind, "system-firmware") == 0) + return FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE; + if (g_strcmp0 (kind, "device-firmware") == 0) + return FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE; + if (g_strcmp0 (kind, "uefi-driver") == 0) + return FU_UEFI_DEVICE_KIND_UEFI_DRIVER; + if (g_strcmp0 (kind, "fmp") == 0) + return FU_UEFI_DEVICE_KIND_FMP; + if (g_strcmp0 (kind, "dell-tpm-firmware") == 0) + return FU_UEFI_DEVICE_KIND_DELL_TPM_FIRMWARE; + return FU_UEFI_DEVICE_KIND_UNKNOWN; +} + +const gchar * +fu_uefi_device_status_to_string (FuUefiDeviceStatus status) +{ + if (status == FU_UEFI_DEVICE_STATUS_SUCCESS) + return "success"; + if (status == FU_UEFI_DEVICE_STATUS_ERROR_UNSUCCESSFUL) + return "unsuccessful"; + if (status == FU_UEFI_DEVICE_STATUS_ERROR_INSUFFICIENT_RESOURCES) + return "insufficient resources"; + if (status == FU_UEFI_DEVICE_STATUS_ERROR_INCORRECT_VERSION) + return "incorrect version"; + if (status == FU_UEFI_DEVICE_STATUS_ERROR_INVALID_FORMAT) + return "invalid firmware format"; + if (status == FU_UEFI_DEVICE_STATUS_ERROR_AUTH_ERROR) + return "authentication signing error"; + if (status == FU_UEFI_DEVICE_STATUS_ERROR_PWR_EVT_AC) + return "AC power required"; + if (status == FU_UEFI_DEVICE_STATUS_ERROR_PWR_EVT_BATT) + return "battery level is too low"; + return NULL; +} + +static void +fu_uefi_device_to_string (FuDevice *device, guint idt, GString *str) +{ + FuUefiDevice *self = FU_UEFI_DEVICE (device); + fu_common_string_append_kv (str, idt, "Kind", fu_uefi_device_kind_to_string (self->kind)); + fu_common_string_append_kv (str, idt, "FwClass", self->fw_class); + fu_common_string_append_kx (str, idt, "CapsuleFlags", self->capsule_flags); + fu_common_string_append_kx (str, idt, "FwVersion", self->fw_version); + fu_common_string_append_kx (str, idt, "FwVersionLowest", self->fw_version_lowest); + fu_common_string_append_kv (str, idt, "LastAttemptStatus", + fu_uefi_device_status_to_string (self->last_attempt_status)); + fu_common_string_append_kx (str, idt, "LastAttemptVersion", self->last_attempt_version); + if (self->esp != NULL) { + fu_common_string_append_kv (str, idt, "EspId", + fu_volume_get_id (self->esp)); + } + fu_common_string_append_ku (str, idt, "RequireESPFreeSpace", + fu_device_get_metadata_integer (device, "RequireESPFreeSpace")); + fu_common_string_append_kb (str, idt, "RequireShimForSecureBoot", + fu_device_get_metadata_boolean (device, "RequireShimForSecureBoot")); +} + +static void +fu_uefi_device_report_metadata_pre (FuDevice *device, GHashTable *metadata) +{ + FuUefiDevice *self = FU_UEFI_DEVICE (device); + + /* record if we had an invalid header during update */ + g_hash_table_insert (metadata, + g_strdup ("MissingCapsuleHeader"), + g_strdup (self->missing_header ? "True" : "False")); + + /* where the ESP was mounted during installation */ + g_hash_table_insert (metadata, + g_strdup ("EspPath"), + fu_volume_get_mount_point (self->esp)); +} + +static void +fu_uefi_device_report_metadata_post (FuDevice *device, GHashTable *metadata) +{ + FuUefiDevice *self = FU_UEFI_DEVICE (device); + + /* the actual last_attempt values */ + g_hash_table_insert (metadata, + g_strdup ("LastAttemptStatus"), + g_strdup_printf ("0x%x", self->last_attempt_status)); + g_hash_table_insert (metadata, + g_strdup ("LastAttemptVersion"), + g_strdup_printf ("0x%x", self->last_attempt_version)); +} + +FuUefiDeviceKind +fu_uefi_device_get_kind (FuUefiDevice *self) +{ + g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), 0); + return self->kind; +} + +guint32 +fu_uefi_device_get_version (FuUefiDevice *self) +{ + g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), 0x0); + return self->fw_version; +} + +guint32 +fu_uefi_device_get_version_lowest (FuUefiDevice *self) +{ + g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), 0x0); + return self->fw_version_lowest; +} + +guint32 +fu_uefi_device_get_version_error (FuUefiDevice *self) +{ + g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), 0x0); + return self->last_attempt_version; +} + +guint64 +fu_uefi_device_get_hardware_instance (FuUefiDevice *self) +{ + g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), 0x0); + return self->fmp_hardware_instance; +} + +FuUefiDeviceStatus +fu_uefi_device_get_status (FuUefiDevice *self) +{ + g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), 0); + return self->last_attempt_status; +} + +guint32 +fu_uefi_device_get_capsule_flags (FuUefiDevice *self) +{ + g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), 0x0); + return self->capsule_flags; +} + +const gchar * +fu_uefi_device_get_guid (FuUefiDevice *self) +{ + g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), NULL); + return self->fw_class; +} + +static gchar * +fu_uefi_device_build_varname (FuUefiDevice *self) +{ + return g_strdup_printf ("fwupd-%s-%"G_GUINT64_FORMAT, + self->fw_class, + self->fmp_hardware_instance); +} + +FuUefiUpdateInfo * +fu_uefi_device_load_update_info (FuUefiDevice *self, GError **error) +{ + gsize datasz = 0; + g_autofree gchar *varname = fu_uefi_device_build_varname (self); + g_autofree guint8 *data = NULL; + g_autoptr(FuUefiUpdateInfo) info = fu_uefi_update_info_new (); + + g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* get the existing status */ + if (!fu_efivar_get_data (FU_EFIVAR_GUID_FWUPDATE, varname, + &data, &datasz, NULL, error)) + return NULL; + if (!fu_uefi_update_info_parse (info, data, datasz, error)) + return NULL; + return g_steal_pointer (&info); +} + +gboolean +fu_uefi_device_clear_status (FuUefiDevice *self, GError **error) +{ + efi_update_info_t info; + gsize datasz = 0; + g_autofree gchar *varname = fu_uefi_device_build_varname (self); + g_autofree guint8 *data = NULL; + + g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* get the existing status */ + if (!fu_efivar_get_data (FU_EFIVAR_GUID_FWUPDATE, varname, + &data, &datasz, NULL, error)) + return FALSE; + if (datasz < sizeof(efi_update_info_t)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "EFI variable is corrupt"); + return FALSE; + } + + /* just copy the efi_update_info_t, ignore devpath then save it back */ + memcpy (&info, data, sizeof(info)); + info.status = FU_UEFI_DEVICE_STATUS_SUCCESS; + memcpy (data, &info, sizeof(info)); + return fu_efivar_set_data (FU_EFIVAR_GUID_FWUPDATE, varname, + data, datasz, + FU_EFIVAR_ATTR_NON_VOLATILE | + FU_EFIVAR_ATTR_BOOTSERVICE_ACCESS | + FU_EFIVAR_ATTR_RUNTIME_ACCESS, + error); +} + +static guint8 * +fu_uefi_device_build_dp_buf (const gchar *path, gsize *bufsz, GError **error) +{ + gssize req; + gssize sz; + g_autofree guint8 *dp_buf = NULL; + g_autoptr(GPtrArray) dps = NULL; + + /* get the size of the path first */ + req = efi_generate_file_device_path (NULL, 0, path, + EFIBOOT_OPTIONS_IGNORE_FS_ERROR | + EFIBOOT_ABBREV_HD); + if (req < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to efi_generate_file_device_path(%s)", + path); + return NULL; + } + + /* if we just have an end device path, it's not going to work */ + if (req <= 4) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to get valid device_path for (%s)", + path); + return NULL; + } + + /* actually get the path this time */ + dp_buf = g_malloc0 (req); + sz = efi_generate_file_device_path (dp_buf, req, path, + EFIBOOT_OPTIONS_IGNORE_FS_ERROR | + EFIBOOT_ABBREV_HD); + if (sz < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to efi_generate_file_device_path(%s)", + path); + return NULL; + } + + /* parse what we got back from efivar */ + dps = fu_uefi_devpath_parse (dp_buf, (gsize) sz, + FU_UEFI_DEVPATH_PARSE_FLAG_NONE, error); + if (dps == NULL) { + fu_common_dump_raw (G_LOG_DOMAIN, "dp_buf", dp_buf, (gsize) sz); + return NULL; + } + + /* success */ + if (bufsz != NULL) + *bufsz = sz; + return g_steal_pointer (&dp_buf); +} + +static GBytes * +fu_uefi_device_fixup_firmware (FuDevice *device, GBytes *fw, GError **error) +{ + FuUefiDevice *self = FU_UEFI_DEVICE (device); + gsize fw_length; + const guint8 *data = g_bytes_get_data (fw, &fw_length); + g_autofree gchar *guid_new = NULL; + + self->missing_header = FALSE; + + /* GUID is the first 16 bytes */ + if (fw_length < sizeof(fwupd_guid_t)) { + g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, + "Invalid payload"); + return NULL; + } + guid_new = fwupd_guid_to_string ((fwupd_guid_t *) data, FWUPD_GUID_FLAG_MIXED_ENDIAN); + + /* ESRT header matches payload */ + if (g_strcmp0 (fu_uefi_device_get_guid (self), guid_new) == 0) { + g_debug ("ESRT matches payload GUID"); + return g_bytes_ref (fw); + /* Type that doesn't require a header */ + } else if (!self->requires_header) { + return g_bytes_ref (fw); + /* Missing, add a header */ + } else { + guint header_size = getpagesize(); + guint8 *new_data = g_malloc (fw_length + header_size); + guint8 *capsule = new_data + header_size; + fwupd_guid_t esrt_guid = { 0x0 }; + efi_capsule_header_t *header = (efi_capsule_header_t *) new_data; + + g_warning ("missing or invalid embedded capsule header"); + self->missing_header = TRUE; + header->flags = self->capsule_flags; + header->header_size = header_size; + header->capsule_image_size = fw_length + header_size; + if (!fwupd_guid_from_string (fu_uefi_device_get_guid (self), &esrt_guid, + FWUPD_GUID_FLAG_MIXED_ENDIAN, error)) { + g_prefix_error (error, "Invalid ESRT GUID: "); + return NULL; + } + memcpy (&header->guid, &esrt_guid, sizeof (fwupd_guid_t)); + memcpy (capsule, data, fw_length); + + return g_bytes_new_take (new_data, fw_length + header_size); + } +} + +gboolean +fu_uefi_device_write_update_info (FuUefiDevice *self, + const gchar *filename, + const gchar *varname, + const gchar *guid, + GError **error) +{ + gsize datasz = 0; + gsize dp_bufsz = 0; + g_autofree guint8 *data = NULL; + g_autofree guint8 *dp_buf = NULL; + efi_update_info_t info = { + .update_info_version = 0x7, + .guid = { 0x0 }, + .capsule_flags = self->capsule_flags, + .hw_inst = self->fmp_hardware_instance, + .time_attempted = { 0x0 }, + .status = FU_UEFI_UPDATE_INFO_STATUS_ATTEMPT_UPDATE, + }; + + /* set the body as the device path */ + if (g_getenv ("FWUPD_UEFI_TEST") != NULL) { + g_debug ("not building device path, in tests...."); + return TRUE; + } + + /* convert to EFI device path */ + dp_buf = fu_uefi_device_build_dp_buf (filename, &dp_bufsz, error); + if (dp_buf == NULL) + return FALSE; + + /* save this header and body to the hardware */ + if (!fwupd_guid_from_string (guid, &info.guid, FWUPD_GUID_FLAG_MIXED_ENDIAN, error)) + return FALSE; + datasz = sizeof(info) + dp_bufsz; + data = g_malloc0 (datasz); + memcpy (data, &info, sizeof(info)); + memcpy (data + sizeof(info), dp_buf, dp_bufsz); + return fu_efivar_set_data (FU_EFIVAR_GUID_FWUPDATE, varname, + data, datasz, + FU_EFIVAR_ATTR_NON_VOLATILE | + FU_EFIVAR_ATTR_BOOTSERVICE_ACCESS | + FU_EFIVAR_ATTR_RUNTIME_ACCESS, + error); +} + +static gboolean +fu_uefi_device_check_esp_free (FuDevice *device, GError **error) +{ + FuUefiDevice *self = FU_UEFI_DEVICE (device); + guint64 sz_reqd = fu_device_get_metadata_integer (device, "RequireESPFreeSpace"); + if (sz_reqd == G_MAXUINT) { + g_debug ("maximum size is not configured"); + return TRUE; + } + return fu_volume_check_free_space (self->esp, sz_reqd, error); +} + +static gboolean +fu_uefi_check_asset (FuDevice *device, GError **error) +{ + g_autofree gchar *source_app = fu_uefi_get_built_app_path (error); + if (source_app == NULL) { + if (fu_efivar_secure_boot_enabled ()) + g_prefix_error (error, "missing signed bootloader for secure boot: "); + return FALSE; + } + + return TRUE; +} + +static gboolean +fu_uefi_device_cleanup_esp (FuDevice *device, GError **error) +{ + FuUefiDevice *self = FU_UEFI_DEVICE (device); + g_autofree gchar *esp_path = fu_volume_get_mount_point (self->esp); + g_autofree gchar *pattern = NULL; + g_autoptr(GPtrArray) files = NULL; + + /* in case we call capsule install twice before reboot */ + if (fu_efivar_exists (FU_EFIVAR_GUID_EFI_GLOBAL, "BootNext")) + return TRUE; + + /* delete any files matching the glob in the ESP */ + files = fu_common_get_files_recursive (esp_path, error); + if (files == NULL) + return FALSE; + pattern = g_build_filename (esp_path, "EFI/*/fw/fwupd*.cap", NULL); + for (guint i = 0; i < files->len; i++) { + const gchar *fn = g_ptr_array_index (files, i); + if (fu_common_fnmatch (pattern, fn)) { + g_autoptr(GFile) file = g_file_new_for_path (fn); + g_debug ("deleting %s", fn); + if (!g_file_delete (file, NULL, error)) + return FALSE; + } + } + + /* delete any old variables */ + if (!fu_efivar_delete_with_glob (FU_EFIVAR_GUID_FWUPDATE, "fwupd*-*", error)) + return FALSE; + + return TRUE; +} + +static gboolean +fu_uefi_device_prepare (FuDevice *device, + FwupdInstallFlags flags, + GError **error) +{ + FuUefiDevice *self = FU_UEFI_DEVICE (device); + + /* mount if required */ + self->esp_locker = fu_volume_locker (self->esp, error); + if (self->esp_locker == NULL) + return FALSE; + + /* sanity checks */ + if (!fu_uefi_device_cleanup_esp (device, error)) + return FALSE; + if (!fu_uefi_device_check_esp_free (device, error)) + return FALSE; + if (!fu_uefi_check_asset (device, error)) + return FALSE; + + return TRUE; +} + +static gboolean +fu_uefi_device_cleanup (FuDevice *device, + FwupdInstallFlags flags, + GError **error) +{ + FuUefiDevice *self = FU_UEFI_DEVICE (device); + + /* unmount ESP if we opened it */ + if (!fu_device_locker_close (self->esp_locker, error)) + return FALSE; + g_clear_object (&self->esp_locker); + + return TRUE; +} + +static gboolean +fu_uefi_device_write_firmware (FuDevice *device, + FuFirmware *firmware, + FwupdInstallFlags install_flags, + GError **error) +{ + FuUefiDevice *self = FU_UEFI_DEVICE (device); + FuUefiBootmgrFlags flags = FU_UEFI_BOOTMGR_FLAG_NONE; + const gchar *bootmgr_desc = "Linux Firmware Updater"; + g_autofree gchar *esp_path = fu_volume_get_mount_point (self->esp); + g_autoptr(GBytes) fixed_fw = NULL; + g_autoptr(GBytes) fw = NULL; + g_autofree gchar *basename = NULL; + g_autofree gchar *directory = NULL; + g_autofree gchar *fn = NULL; + g_autofree gchar *varname = fu_uefi_device_build_varname (self); + + /* ensure we have the existing state */ + if (self->fw_class == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "cannot update device info with no GUID"); + return FALSE; + } + + /* get default image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + + /* save the blob to the ESP */ + directory = fu_uefi_get_esp_path_for_os (device, esp_path); + basename = g_strdup_printf ("fwupd-%s.cap", self->fw_class); + fn = g_build_filename (directory, "fw", basename, NULL); + if (!fu_common_mkdir_parent (fn, error)) + return FALSE; + fixed_fw = fu_uefi_device_fixup_firmware (device, fw, error); + if (fixed_fw == NULL) + return FALSE; + if (!fu_common_set_contents_bytes (fn, fixed_fw, error)) + return FALSE; + + /* delete the logs to save space; use fwupdate to debug the EFI binary */ + if (fu_efivar_exists (FU_EFIVAR_GUID_FWUPDATE, "FWUPDATE_VERBOSE")) { + if (!fu_efivar_delete (FU_EFIVAR_GUID_FWUPDATE, + "FWUPDATE_VERBOSE", error)) + return FALSE; + } + if (fu_efivar_exists (FU_EFIVAR_GUID_FWUPDATE, "FWUPDATE_DEBUG_LOG")) { + if (!fu_efivar_delete (FU_EFIVAR_GUID_FWUPDATE, + "FWUPDATE_DEBUG_LOG", error)) + return FALSE; + } + + /* set the blob header shared with fwupd.efi */ + if (!fu_uefi_device_write_update_info (self, fn, varname, self->fw_class, error)) + return FALSE; + + /* update the firmware before the bootloader runs */ + if (fu_device_get_metadata_boolean (device, "RequireShimForSecureBoot")) + flags |= FU_UEFI_BOOTMGR_FLAG_USE_SHIM_FOR_SB; + if (fu_device_has_custom_flag (device, "use-shim-unique")) + flags |= FU_UEFI_BOOTMGR_FLAG_USE_SHIM_UNIQUE; + + /* some legacy devices use the old name to deduplicate boot entries */ + if (fu_device_has_custom_flag (device, "use-legacy-bootmgr-desc")) + bootmgr_desc = "Linux-Firmware-Updater"; + if (!fu_uefi_bootmgr_bootnext (device, esp_path, bootmgr_desc, flags, error)) + return FALSE; + + /* success! */ + return TRUE; +} + +static gboolean +fu_uefi_device_add_system_checksum (FuDevice *device, GError **error) +{ + g_autoptr(FuUefiPcrs) pcrs = fu_uefi_pcrs_new (); + g_autoptr(GError) error_local = NULL; + g_autoptr(GPtrArray) pcr0s = NULL; + + /* get all the PCRs */ + if (!fu_uefi_pcrs_setup (pcrs, &error_local)) { + if (g_error_matches (error_local, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED) || + g_error_matches (error_local, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND)) { + g_debug ("%s", error_local->message); + return TRUE; + } + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; + } + + /* get all the PCR0s */ + pcr0s = fu_uefi_pcrs_get_checksums (pcrs, 0); + if (pcr0s->len == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "no PCR0s detected"); + return FALSE; + } + for (guint i = 0; i < pcr0s->len; i++) { + const gchar *checksum = g_ptr_array_index (pcr0s, i); + fu_device_add_checksum (device, checksum); + } + + /* success */ + return TRUE; +} + +static gboolean +fu_uefi_device_probe (FuDevice *device, GError **error) +{ + FuUefiDevice *self = FU_UEFI_DEVICE (device); + FwupdVersionFormat version_format; + g_autofree gchar *devid = NULL; + g_autofree gchar *guid_strup = NULL; + g_autofree gchar *version_lowest = NULL; + g_autofree gchar *version = NULL; + + /* broken sysfs? */ + if (self->fw_class == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to read fw_class"); + return FALSE; + } + + /* add GUID first, as quirks may set the version format */ + fu_device_add_guid (device, self->fw_class); + + /* set versions */ + version_format = fu_device_get_version_format (device); + version = fu_common_version_from_uint32 (self->fw_version, version_format); + fu_device_set_version_format (device, version_format); + fu_device_set_version_raw (device, self->fw_version); + fu_device_set_version (device, version); + if (self->fw_version_lowest != 0) { + version_lowest = fu_common_version_from_uint32 (self->fw_version_lowest, + version_format); + fu_device_set_version_lowest_raw (device, self->fw_version_lowest); + fu_device_set_version_lowest (device, version_lowest); + } + + /* set flags */ + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_INTERNAL); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_REQUIRE_AC); + fu_device_add_internal_flag (device, FU_DEVICE_INTERNAL_FLAG_MD_SET_VERFMT); + fu_device_add_internal_flag (device, FU_DEVICE_INTERNAL_FLAG_MD_SET_ICON); + + /* add icons */ + if (self->kind == FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE) { + /* nothing better in the icon naming spec */ + fu_device_add_icon (device, "audio-card"); + } else { + /* this is probably system firmware */ + fu_device_add_icon (device, "computer"); + fu_device_add_instance_id (device, "main-system-firmware"); + } + + /* set the PCR0 as the device checksum */ + if (self->kind == FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE) { + g_autoptr(GError) error_local = NULL; + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_CAN_VERIFY); + if (!fu_uefi_device_add_system_checksum (device, &error_local)) + g_warning ("Failed to get PCR0s: %s", error_local->message); + } + + /* whether to create a missing header */ + if (self->kind == FU_UEFI_DEVICE_KIND_FMP || + self->kind == FU_UEFI_DEVICE_KIND_DELL_TPM_FIRMWARE) + self->requires_header = FALSE; + else + self->requires_header = TRUE; + + /* Windows seems to be case insensitive, but for convenience we'll + * match the upper case values typically specified in the .inf file */ + guid_strup = g_ascii_strup (self->fw_class, -1); + devid = g_strdup_printf ("UEFI\\RES_{%s}", guid_strup); + fu_device_add_instance_id (device, devid); + return TRUE; +} + +static void +fu_uefi_device_init (FuUefiDevice *self) +{ + fu_device_add_protocol (FU_DEVICE (self), "org.uefi.capsule"); +} + +static void +fu_uefi_device_finalize (GObject *object) +{ + FuUefiDevice *self = FU_UEFI_DEVICE (object); + + g_free (self->fw_class); + if (self->esp != NULL) + g_object_unref (self->esp); + if (self->esp_locker != NULL) + g_object_unref (self->esp_locker); + + G_OBJECT_CLASS (fu_uefi_device_parent_class)->finalize (object); +} + +static void +fu_uefi_device_class_init (FuUefiDeviceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + object_class->finalize = fu_uefi_device_finalize; + klass_device->to_string = fu_uefi_device_to_string; + klass_device->probe = fu_uefi_device_probe; + klass_device->prepare = fu_uefi_device_prepare; + klass_device->write_firmware = fu_uefi_device_write_firmware; + klass_device->cleanup = fu_uefi_device_cleanup; + klass_device->report_metadata_pre = fu_uefi_device_report_metadata_pre; + klass_device->report_metadata_post = fu_uefi_device_report_metadata_post; +} + +FuUefiDevice * +fu_uefi_device_new_from_entry (const gchar *entry_path, GError **error) +{ + g_autoptr(FuUefiDevice) self = NULL; + g_autofree gchar *fw_class_fn = NULL; + g_autofree gchar *id = NULL; + + g_return_val_if_fail (entry_path != NULL, NULL); + + /* create object */ + self = g_object_new (FU_TYPE_UEFI_DEVICE, NULL); + + /* assume a uint64_t unless told otherwise by a quirk entry or metadata */ + fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_NUMBER); + + /* read values from sysfs */ + fw_class_fn = g_build_filename (entry_path, "fw_class", NULL); + if (g_file_get_contents (fw_class_fn, &self->fw_class, NULL, NULL)) + g_strdelimit (self->fw_class, "\n", '\0'); + self->capsule_flags = fu_uefi_read_file_as_uint64 (entry_path, "capsule_flags"); + self->kind = fu_uefi_read_file_as_uint64 (entry_path, "fw_type"); + self->fw_version = fu_uefi_read_file_as_uint64 (entry_path, "fw_version"); + self->last_attempt_status = fu_uefi_read_file_as_uint64 (entry_path, "last_attempt_status"); + self->last_attempt_version = fu_uefi_read_file_as_uint64 (entry_path, "last_attempt_version"); + self->fw_version_lowest = fu_uefi_read_file_as_uint64 (entry_path, "lowest_supported_fw_version"); + + /* the hardware instance is not in the ESRT table and we should really + * write the EFI stub to query with FMP -- but we still have not ever + * seen a PCIe device with FMP support... */ + self->fmp_hardware_instance = 0x0; + + /* set ID */ + id = g_strdup_printf ("UEFI-%s-dev%" G_GUINT64_FORMAT, + self->fw_class, self->fmp_hardware_instance); + fu_device_set_id (FU_DEVICE (self), id); + + /* this is invalid */ + if (!fwupd_guid_is_valid (self->fw_class)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "ESRT GUID '%s' was not valid", self->fw_class); + return NULL; + } + + return g_steal_pointer (&self); +} + +FuUefiDevice * +fu_uefi_device_new_from_dev (FuDevice *dev) +{ + const gchar *tmp; + FuUefiDevice *self; + + g_return_val_if_fail (fu_device_get_guid_default (dev) != NULL, NULL); + + /* create virtual object not backed by an ESRT entry */ + self = g_object_new (FU_TYPE_UEFI_DEVICE, NULL); + fu_device_incorporate (FU_DEVICE (self), dev); + self->fw_class = g_strdup (fu_device_get_guid_default (dev)); + tmp = fu_device_get_metadata (dev, FU_DEVICE_METADATA_UEFI_DEVICE_KIND); + self->kind = fu_uefi_device_kind_from_string (tmp); + self->capsule_flags = fu_device_get_metadata_integer (dev, FU_DEVICE_METADATA_UEFI_CAPSULE_FLAGS); + self->fw_version = fu_device_get_metadata_integer (dev, FU_DEVICE_METADATA_UEFI_FW_VERSION); + g_assert (self->fw_class != NULL); + return self; +} + +FuUefiDevice * +fu_uefi_device_new_from_guid (const gchar *guid) +{ + FuUefiDevice *self; + self = g_object_new (FU_TYPE_UEFI_DEVICE, NULL); + self->fw_class = g_strdup (guid); + fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_NUMBER); + return self; +} diff -Nru fwupd-1.4.5/plugins/uefi-capsule/fu-uefi-device.h fwupd-1.5.8/plugins/uefi-capsule/fu-uefi-device.h --- fwupd-1.4.5/plugins/uefi-capsule/fu-uefi-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/fu-uefi-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2018 Richard Hughes + * Copyright (C) 2015 Peter Jones + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" +#include "fu-uefi-device.h" +#include "fu-uefi-update-info.h" + +#define FU_TYPE_UEFI_DEVICE (fu_uefi_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuUefiDevice, fu_uefi_device, FU, UEFI_DEVICE, FuDevice) + +typedef enum { + FU_UEFI_DEVICE_KIND_UNKNOWN, + FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE, + FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE, + FU_UEFI_DEVICE_KIND_UEFI_DRIVER, + FU_UEFI_DEVICE_KIND_FMP, + FU_UEFI_DEVICE_KIND_DELL_TPM_FIRMWARE, + FU_UEFI_DEVICE_KIND_LAST +} FuUefiDeviceKind; + +typedef enum { + FU_UEFI_DEVICE_STATUS_SUCCESS = 0x00, + FU_UEFI_DEVICE_STATUS_ERROR_UNSUCCESSFUL = 0x01, + FU_UEFI_DEVICE_STATUS_ERROR_INSUFFICIENT_RESOURCES = 0x02, + FU_UEFI_DEVICE_STATUS_ERROR_INCORRECT_VERSION = 0x03, + FU_UEFI_DEVICE_STATUS_ERROR_INVALID_FORMAT = 0x04, + FU_UEFI_DEVICE_STATUS_ERROR_AUTH_ERROR = 0x05, + FU_UEFI_DEVICE_STATUS_ERROR_PWR_EVT_AC = 0x06, + FU_UEFI_DEVICE_STATUS_ERROR_PWR_EVT_BATT = 0x07, + FU_UEFI_DEVICE_STATUS_LAST +} FuUefiDeviceStatus; + +FuUefiDevice *fu_uefi_device_new_from_guid (const gchar *guid); +FuUefiDevice *fu_uefi_device_new_from_entry (const gchar *entry_path, + GError **error); +FuUefiDevice *fu_uefi_device_new_from_dev (FuDevice *dev); +void fu_uefi_device_set_esp (FuUefiDevice *self, + FuVolume *esp); +gboolean fu_uefi_device_clear_status (FuUefiDevice *self, + GError **error); +FuUefiDeviceKind fu_uefi_device_get_kind (FuUefiDevice *self); +const gchar *fu_uefi_device_get_guid (FuUefiDevice *self); +guint32 fu_uefi_device_get_version (FuUefiDevice *self); +guint32 fu_uefi_device_get_version_lowest (FuUefiDevice *self); +guint32 fu_uefi_device_get_version_error (FuUefiDevice *self); +guint32 fu_uefi_device_get_capsule_flags (FuUefiDevice *self); +guint64 fu_uefi_device_get_hardware_instance (FuUefiDevice *self); +FuUefiDeviceStatus fu_uefi_device_get_status (FuUefiDevice *self); +const gchar *fu_uefi_device_kind_to_string (FuUefiDeviceKind kind); +const gchar *fu_uefi_device_status_to_string (FuUefiDeviceStatus status); +FuUefiUpdateInfo *fu_uefi_device_load_update_info (FuUefiDevice *self, + GError **error); +gboolean fu_uefi_device_write_update_info (FuUefiDevice *self, + const gchar *filename, + const gchar *varname, + const gchar *guid, + GError **error); diff -Nru fwupd-1.4.5/plugins/uefi-capsule/fu-uefi-devpath.c fwupd-1.5.8/plugins/uefi-capsule/fu-uefi-devpath.c --- fwupd-1.4.5/plugins/uefi-capsule/fu-uefi-devpath.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/fu-uefi-devpath.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" +#include "fu-uefi-devpath.h" + +#include "fwupd-error.h" + +typedef struct { + guint8 type; + guint8 subtype; + GBytes *data; +} FuUefiDevPath; + +static void +fu_uefi_efi_dp_free (FuUefiDevPath *dp) +{ + if (dp->data != NULL) + g_bytes_unref (dp->data); + g_free (dp); +} + +GBytes * +fu_uefi_devpath_find_data (GPtrArray *dps, guint8 type, guint8 subtype, GError **error) +{ + for (guint i = 0; i < dps->len; i++) { + FuUefiDevPath *dp = g_ptr_array_index (dps, i); + if (dp->type == type && dp->subtype == subtype) + return dp->data; + } + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "no DP with type 0x%02x and subtype 0x%02x", + type, subtype); + return NULL; +} + +GPtrArray * +fu_uefi_devpath_parse (const guint8 *buf, gsize sz, + FuUefiDevpathParseFlags flags, GError **error) +{ + guint16 offset = 0; + g_autoptr(GPtrArray) dps = NULL; + + /* sanity check */ + if (sz < sizeof(efidp_header)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "const_efidp is corrupt"); + return NULL; + } + + dps = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_uefi_efi_dp_free); + while (1) { + FuUefiDevPath *dp; + const efidp_header *hdr = (efidp_header *) (buf + offset); + guint16 hdr_length = GUINT16_FROM_LE(hdr->length); + + /* check if last entry */ + g_debug ("DP type:0x%02x subtype:0x%02x size:0x%04x", + hdr->type, hdr->subtype, hdr->length); + if (hdr->type == EFIDP_END_TYPE && hdr->subtype == EFIDP_END_ENTIRE) + break; + + /* work around a bug in efi_va_generate_file_device_path_from_esp */ + if (offset + sizeof(efidp_header) + hdr->length > sz) { + hdr_length = 0; + fu_common_dump_full (G_LOG_DOMAIN, "efidp", + buf + offset, sz - offset, 32, + FU_DUMP_FLAGS_SHOW_ADDRESSES); + for (guint16 i = offset + 4; i <= sz - 4; i++) { + if (memcmp (buf + i, "\x7f\xff\x04\x00", 4) == 0) { + hdr_length = i - offset; + g_debug ("found END_ENTIRE at 0x%04x", + (guint) (i - offset)); + break; + } + } + if (hdr_length == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "DP length invalid and no END_ENTIRE " + "found, possibly data truncation?"); + return NULL; + } + if ((flags & FU_UEFI_DEVPATH_PARSE_FLAG_REPAIR) == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "DP length invalid, reported 0x%04x, maybe 0x%04x", + hdr->length, hdr_length); + return NULL; + } + g_debug ("DP length invalid! Truncating from 0x%04x to 0x%04x", + hdr->length, hdr_length); + } + + /* add new DP */ + dp = g_new0 (FuUefiDevPath, 1); + dp->type = hdr->type; + dp->subtype = hdr->subtype; + if (hdr_length > 0) + dp->data = g_bytes_new (buf + offset + 4, hdr_length); + g_ptr_array_add (dps, dp); + + /* advance to next DP */ + offset += hdr_length; + if (offset + sizeof(efidp_header) > sz) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "DP length invalid after fixing"); + return NULL; + } + + } + return g_steal_pointer (&dps); +} diff -Nru fwupd-1.4.5/plugins/uefi-capsule/fu-uefi-devpath.h fwupd-1.5.8/plugins/uefi-capsule/fu-uefi-devpath.h --- fwupd-1.4.5/plugins/uefi-capsule/fu-uefi-devpath.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/fu-uefi-devpath.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +typedef enum { + FU_UEFI_DEVPATH_PARSE_FLAG_NONE = 0, + FU_UEFI_DEVPATH_PARSE_FLAG_REPAIR = 1 << 0, + FU_UEFI_DEVPATH_PARSE_FLAG_LAST +} FuUefiDevpathParseFlags; + +GPtrArray *fu_uefi_devpath_parse (const guint8 *buf, + gsize sz, + FuUefiDevpathParseFlags flags, + GError **error); +GBytes *fu_uefi_devpath_find_data (GPtrArray *dps, + guint8 type, + guint8 subtype, + GError **error); diff -Nru fwupd-1.4.5/plugins/uefi-capsule/fu-uefi-pcrs.c fwupd-1.5.8/plugins/uefi-capsule/fu-uefi-pcrs.c --- fwupd-1.4.5/plugins/uefi-capsule/fu-uefi-pcrs.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/fu-uefi-pcrs.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#ifdef HAVE_TSS2 +#include +#endif + +#include "fu-common.h" +#include "fu-uefi-pcrs.h" +#include "fwupd-error.h" + +typedef struct { + guint idx; + gchar *checksum; +} FuUefiPcrItem; + +struct _FuUefiPcrs { + GObject parent_instance; + GPtrArray *items; /* of FuUefiPcrItem */ +}; + +G_DEFINE_TYPE (FuUefiPcrs, fu_uefi_pcrs, G_TYPE_OBJECT) + +#ifdef HAVE_TSS2 +static void Esys_Finalize_autoptr_cleanup (ESYS_CONTEXT *esys_context) +{ + Esys_Finalize (&esys_context); +} +G_DEFINE_AUTOPTR_CLEANUP_FUNC (ESYS_CONTEXT, Esys_Finalize_autoptr_cleanup) +#endif + +static gboolean +_g_string_isxdigit (GString *str) +{ + for (gsize i = 0; i < str->len; i++) { + if (!g_ascii_isxdigit (str->str[i])) + return FALSE; + } + return TRUE; +} + +static void +fu_uefi_pcrs_parse_line (const gchar *line, gpointer user_data) +{ + FuUefiPcrs *self = FU_UEFI_PCRS (user_data); + FuUefiPcrItem *item; + guint64 idx; + g_autofree gchar *idxstr = NULL; + g_auto(GStrv) split = NULL; + g_autoptr(GString) str = NULL; + + /* split into index:hash */ + if (line == NULL || line[0] == '\0') + return; + split = g_strsplit (line, ":", -1); + if (g_strv_length (split) != 2) { + g_debug ("unexpected format, skipping: %s", line); + return; + } + + /* get index */ + idxstr = fu_common_strstrip (split[0]); + idx = fu_common_strtoull (idxstr); + if (idx > 64) { + g_debug ("unexpected index, skipping: %s", idxstr); + return; + } + + /* parse hash */ + str = g_string_new (split[1]); + fu_common_string_replace (str, " ", ""); + if ((str->len != 40 && str->len != 64) || !_g_string_isxdigit (str)) { + g_debug ("not SHA-1 or SHA-256, skipping: %s", split[1]); + return; + } + g_string_ascii_down (str); + item = g_new0 (FuUefiPcrItem, 1); + item->idx = idx; + item->checksum = g_string_free (g_steal_pointer (&str), FALSE); + g_ptr_array_add (self->items, item); + g_debug ("added PCR-%02u=%s", item->idx, item->checksum); +} + +static gboolean +fu_uefi_pcrs_setup_tpm12 (FuUefiPcrs *self, const gchar *fn_pcrs, GError **error) +{ + g_auto(GStrv) lines = NULL; + g_autofree gchar *buf_pcrs = NULL; + + /* get entire contents */ + if (!g_file_get_contents (fn_pcrs, &buf_pcrs, NULL, error)) + return FALSE; + + /* find PCR lines */ + lines = g_strsplit (buf_pcrs, "\n", -1); + for (guint i = 0; lines[i] != NULL; i++) { + if (g_str_has_prefix (lines[i], "PCR-")) + fu_uefi_pcrs_parse_line (lines[i] + 4, self); + } + return TRUE; +} + +static gboolean +fu_uefi_pcrs_setup_tpm20 (FuUefiPcrs *self, GError **error) +{ +#ifdef HAVE_TSS2 + TSS2_RC rc; + g_autoptr(ESYS_CONTEXT) ctx = NULL; + g_autofree TPMS_CAPABILITY_DATA *capability_data = NULL; + TPML_PCR_SELECTION pcr_selection_in = { 0, }; + g_autofree TPML_DIGEST *pcr_values = NULL; + + /* suppress warning messages about missing TCTI libraries for tpm2-tss <2.3 */ + if (g_getenv ("FWUPD_UEFI_VERBOSE") == NULL) { + g_setenv ("TSS2_LOG", "esys+error,tcti+none", FALSE); + } + + rc = Esys_Initialize (&ctx, NULL, NULL); + if (rc != TSS2_RC_SUCCESS) { + g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, + "failed to initialize TPM library"); + return FALSE; + } + rc = Esys_Startup (ctx, TPM2_SU_CLEAR); + if (rc != TSS2_RC_SUCCESS) { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "failed to initialize TPM"); + return FALSE; + } + + /* get hash algorithms supported by the TPM */ + rc = Esys_GetCapability (ctx, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, + TPM2_CAP_PCRS, 0, 1, NULL, &capability_data); + if (rc != TSS2_RC_SUCCESS) { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "failed to get hash algorithms supported by TPM"); + return FALSE; + } + + /* fetch PCR 0 for every supported hash algorithm */ + pcr_selection_in.count = capability_data->data.assignedPCR.count; + for (guint i = 0; i < pcr_selection_in.count; i++) { + pcr_selection_in.pcrSelections[i].hash = + capability_data->data.assignedPCR.pcrSelections[i].hash; + pcr_selection_in.pcrSelections[i].sizeofSelect = + capability_data->data.assignedPCR.pcrSelections[i].sizeofSelect; + pcr_selection_in.pcrSelections[i].pcrSelect[0] = 0b00000001; + } + + rc = Esys_PCR_Read (ctx, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, + &pcr_selection_in, NULL, NULL, &pcr_values); + if (rc != TSS2_RC_SUCCESS) { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "failed to read PCR values from TPM"); + return FALSE; + } + + for (guint i = 0; i < pcr_values->count; i++) { + FuUefiPcrItem *item; + g_autoptr(GString) str = NULL; + gboolean valid = FALSE; + + str = g_string_new (NULL); + for (guint j = 0; j < pcr_values->digests[i].size; j++) { + gint64 val = pcr_values->digests[i].buffer[j]; + if (val > 0) + valid = TRUE; + g_string_append_printf (str, "%02x", pcr_values->digests[i].buffer[j]); + } + if (valid) { + item = g_new0 (FuUefiPcrItem, 1); + item->idx = 0; /* constant PCR index 0, since we only read this single PCR */ + item->checksum = g_string_free (g_steal_pointer (&str), FALSE); + g_ptr_array_add (self->items, item); + g_debug ("added PCR-%02u=%s", item->idx, item->checksum); + } + } +#endif + + /* success */ + return TRUE; +} + +gboolean +fu_uefi_pcrs_setup (FuUefiPcrs *self, GError **error) +{ + g_autofree gchar *devpath = NULL; + g_autofree gchar *sysfstpmdir = NULL; + g_autofree gchar *fn_pcrs = NULL; + + g_return_val_if_fail (FU_IS_UEFI_PCRS (self), FALSE); + + /* look for TPM 1.2 */ + sysfstpmdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_TPM); + devpath = g_build_filename (sysfstpmdir, "tpm0", NULL); + fn_pcrs = g_build_filename (devpath, "pcrs", NULL); + if (g_file_test (fn_pcrs, G_FILE_TEST_EXISTS) && + g_getenv ("FWUPD_FORCE_TPM2") == NULL) { + if (!fu_uefi_pcrs_setup_tpm12 (self, fn_pcrs, error)) + return FALSE; + + /* assume TPM 2.0 */ + } else { + if (!fu_uefi_pcrs_setup_tpm20 (self, error)) + return FALSE; + } + + /* check we got anything */ + if (self->items->len == 0) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "no TPMxx measurements found"); + return FALSE; + } + + /* success */ + return TRUE; +} + +GPtrArray * +fu_uefi_pcrs_get_checksums (FuUefiPcrs *self, guint idx) +{ + g_autoptr(GPtrArray) array = g_ptr_array_new_with_free_func (g_free); + g_return_val_if_fail (FU_IS_UEFI_PCRS (self), NULL); + for (guint i = 0; i < self->items->len; i++) { + FuUefiPcrItem *item = g_ptr_array_index (self->items, i); + if (item->idx == idx) + g_ptr_array_add (array, g_strdup (item->checksum)); + } + return g_steal_pointer (&array); +} + +static void +fu_uefi_pcrs_item_free (FuUefiPcrItem *item) +{ + g_free (item->checksum); + g_free (item); +} + +static void +fu_uefi_pcrs_finalize (GObject *object) +{ + FuUefiPcrs *self = FU_UEFI_PCRS (object); + g_ptr_array_unref (self->items); + G_OBJECT_CLASS (fu_uefi_pcrs_parent_class)->finalize (object); +} + +static void +fu_uefi_pcrs_class_init (FuUefiPcrsClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fu_uefi_pcrs_finalize; +} + +static void +fu_uefi_pcrs_init (FuUefiPcrs *self) +{ + self->items = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_uefi_pcrs_item_free); +} + +FuUefiPcrs * +fu_uefi_pcrs_new (void) +{ + FuUefiPcrs *self; + self = g_object_new (FU_TYPE_UEFI_PCRS, NULL); + return FU_UEFI_PCRS (self); +} diff -Nru fwupd-1.4.5/plugins/uefi-capsule/fu-uefi-pcrs.h fwupd-1.5.8/plugins/uefi-capsule/fu-uefi-pcrs.h --- fwupd-1.4.5/plugins/uefi-capsule/fu-uefi-pcrs.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/fu-uefi-pcrs.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2017 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#define FU_TYPE_UEFI_PCRS (fu_uefi_pcrs_get_type ()) +G_DECLARE_FINAL_TYPE (FuUefiPcrs, fu_uefi_pcrs, FU, UEFI_PCRS, GObject) + +FuUefiPcrs *fu_uefi_pcrs_new (void); +gboolean fu_uefi_pcrs_setup (FuUefiPcrs *self, + GError **error); +GPtrArray *fu_uefi_pcrs_get_checksums (FuUefiPcrs *self, + guint idx); diff -Nru fwupd-1.4.5/plugins/uefi-capsule/fu-uefi-tool.c fwupd-1.5.8/plugins/uefi-capsule/fu-uefi-tool.c --- fwupd-1.4.5/plugins/uefi-capsule/fu-uefi-tool.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/fu-uefi-tool.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,368 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "fu-ucs2.h" +#include "fu-uefi-common.h" +#include "fu-uefi-device.h" +#include "fu-uefi-update-info.h" +#include "fu-efivar.h" + +/* custom return code */ +#define EXIT_NOTHING_TO_DO 2 + +typedef struct { + GCancellable *cancellable; + GMainLoop *loop; + GOptionContext *context; +} FuUtilPrivate; + +static void +fu_util_ignore_cb (const gchar *log_domain, GLogLevelFlags log_level, + const gchar *message, gpointer user_data) +{ +} + +static void +fu_util_private_free (FuUtilPrivate *priv) +{ + if (priv->context != NULL) + g_option_context_free (priv->context); + g_free (priv); +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuUtilPrivate, fu_util_private_free) +#pragma clang diagnostic pop + +int +main (int argc, char *argv[]) +{ + gboolean action_enable = FALSE; + gboolean action_info = FALSE; + gboolean action_list = FALSE; + gboolean action_log = FALSE; + gboolean action_set_debug = FALSE; + gboolean action_supported = FALSE; + gboolean action_unset_debug = FALSE; + gboolean action_version = FALSE; + gboolean ret; + gboolean verbose = FALSE; + g_autofree gchar *apply = FALSE; + g_autofree gchar *esp_path = NULL; + g_autofree gchar *flags = FALSE; + g_autoptr(FuUtilPrivate) priv = g_new0 (FuUtilPrivate, 1); + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) devices = NULL; + g_autoptr(FuVolume) esp = NULL; + const GOptionEntry options[] = { + { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, + /* TRANSLATORS: command line option */ + _("Show extra debugging information"), NULL }, + { "version", '\0', 0, G_OPTION_ARG_NONE, &action_version, + /* TRANSLATORS: command line option */ + _("Display version"), NULL }, + { "log", 'L', 0, G_OPTION_ARG_NONE, &action_log, + /* TRANSLATORS: command line option */ + _("Show the debug log from the last attempted update"), NULL }, + { "list", 'l', 0, G_OPTION_ARG_NONE, &action_list, + /* TRANSLATORS: command line option */ + _("List supported firmware updates"), NULL }, + { "supported", 's', 0, G_OPTION_ARG_NONE, &action_supported, + /* TRANSLATORS: command line option */ + _("Query for firmware update support"), NULL }, + { "info", 'i', 0, G_OPTION_ARG_NONE, &action_info, + /* TRANSLATORS: command line option */ + _("Show the information of firmware update status"), NULL }, + { "enable", 'e', 0, G_OPTION_ARG_NONE, &action_enable, + /* TRANSLATORS: command line option */ + _("Enable firmware update support on supported systems"), NULL }, + { "esp-path", 'p', 0, G_OPTION_ARG_STRING, &esp_path, + /* TRANSLATORS: command line option */ + _("Override the default ESP path"), + /* TRANSLATORS: command argument: uppercase, spaces->dashes */ + _("PATH") }, + { "set-debug", 'd', 0, G_OPTION_ARG_NONE, &action_set_debug, + /* TRANSLATORS: command line option */ + _("Set the debugging flag during update"), NULL }, + { "unset-debug", 'D', 0, G_OPTION_ARG_NONE, &action_unset_debug, + /* TRANSLATORS: command line option */ + _("Unset the debugging flag during update"), NULL }, + { "apply", 'a', 0, G_OPTION_ARG_STRING, &apply, + /* TRANSLATORS: command line option */ + _("Apply firmware updates"), + /* TRANSLATORS: command argument: uppercase, spaces->dashes */ + C_("A single GUID", "GUID") }, + { "flags", 'f', 0, G_OPTION_ARG_STRING, &flags, + /* TRANSLATORS: command line option */ + _("Use quirk flags when installing firmware"), NULL }, + { NULL} + }; + + setlocale (LC_ALL, ""); + + bindtextdomain (GETTEXT_PACKAGE, FWUPD_LOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + /* ensure root user */ +#ifdef HAVE_GETUID + if (getuid () != 0 || geteuid () != 0) + /* TRANSLATORS: we're poking around as a power user */ + g_printerr ("%s\n", _("This program may only work correctly as root")); +#endif + + /* get a action_list of the commands */ + priv->context = g_option_context_new (NULL); + g_option_context_set_description (priv->context, + /* TRANSLATORS: CLI description */ + _("This tool allows an administrator to debug UpdateCapsule operation.")); + + /* TRANSLATORS: program name */ + g_set_application_name (_("UEFI Firmware Utility")); + g_option_context_add_main_entries (priv->context, options, NULL); + ret = g_option_context_parse (priv->context, &argc, &argv, &error); + if (!ret) { + /* TRANSLATORS: the user didn't read the man page */ + g_print ("%s: %s\n", _("Failed to parse arguments"), + error->message); + return EXIT_FAILURE; + } + + /* set verbose? */ + if (verbose) { + g_setenv ("G_MESSAGES_DEBUG", "all", FALSE); + } else { + g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, + fu_util_ignore_cb, NULL); + } + + /* nothing specified */ + if (!action_enable && !action_info && !action_list && !action_log && + !action_set_debug && !action_supported && !action_unset_debug && + !action_version && apply == NULL) { + g_autofree gchar *tmp = NULL; + tmp = g_option_context_get_help (priv->context, TRUE, NULL); + g_printerr ("%s\n\n%s", _("No action specified!"), tmp); + return EXIT_FAILURE; + } + + /* action_version first */ + if (action_version) + g_print ("fwupd version: %s\n", PACKAGE_VERSION); + + /* override the default ESP path */ + if (esp_path != NULL) { + esp = fu_common_get_esp_for_path (esp_path, &error); + if (esp == NULL) { + /* TRANSLATORS: ESP is EFI System Partition */ + g_print ("%s: %s\n", _("ESP specified was not valid"), + error->message); + return EXIT_FAILURE; + } + } else { + esp = fu_common_get_esp_default (&error); + if (esp == NULL) { + g_printerr ("failed: %s\n", error->message); + return EXIT_FAILURE; + } + } + + /* show the debug action_log from the last attempted update */ + if (action_log) { + gsize sz = 0; + g_autofree guint8 *buf = NULL; + g_autofree guint16 *buf_ucs2 = NULL; + g_autofree gchar *str = NULL; + g_autoptr(GError) error_local = NULL; + if (!fu_efivar_get_data (FU_EFIVAR_GUID_FWUPDATE, + "FWUPDATE_DEBUG_LOG", + &buf, &sz, NULL, + &error_local)) { + g_printerr ("failed: %s\n", error_local->message); + return EXIT_FAILURE; + } + buf_ucs2 = g_new0 (guint16, (sz / 2) + 1); + memcpy (buf_ucs2, buf, sz); + str = fu_ucs2_to_uft8 (buf_ucs2, sz / 2); + g_print ("%s", str); + } + + if (action_list || action_supported || action_info) { + g_autoptr(GPtrArray) entries = NULL; + g_autofree gchar *esrt_path = NULL; + g_autofree gchar *sysfsfwdir = NULL; + g_autoptr(GError) error_local = NULL; + + /* get the directory of ESRT entries */ + sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); + esrt_path = g_build_filename (sysfsfwdir, "efi", "esrt", NULL); + entries = fu_uefi_get_esrt_entry_paths (esrt_path, &error_local); + if (entries == NULL) { + g_printerr ("failed: %s\n", error_local->message); + return EXIT_FAILURE; + } + + /* add each device */ + devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + for (guint i = 0; i < entries->len; i++) { + const gchar *path = g_ptr_array_index (entries, i); + g_autoptr(GError) error_parse = NULL; + g_autoptr(FuUefiDevice) dev = fu_uefi_device_new_from_entry (path, &error_parse); + if (dev == NULL) { + g_warning ("failed to parse %s: %s", + path, error_parse->message); + continue; + } + fu_uefi_device_set_esp (dev, esp); + g_ptr_array_add (devices, g_object_ref (dev)); + } + } + + /* action_list action_supported firmware updates */ + if (action_list) { + for (guint i = 0; i < devices->len; i++) { + FuUefiDevice *dev = g_ptr_array_index (devices, i); + g_print ("%s type, {%s} version %" G_GUINT32_FORMAT " can be updated " + "to any version above %" G_GUINT32_FORMAT "\n", + fu_uefi_device_kind_to_string (fu_uefi_device_get_kind (dev)), + fu_uefi_device_get_guid (dev), + fu_uefi_device_get_version (dev), + fu_uefi_device_get_version_lowest (dev) - 1); + } + } + + /* query for firmware update support */ + if (action_supported) { + if (devices->len > 0) { + g_print ("%s\n", _("Firmware updates are supported on this machine.")); + } else { + g_print ("%s\n", _("Firmware updates are not supported on this machine.")); + } + } + + /* show the information of firmware update status */ + if (action_info) { + for (guint i = 0; i < devices->len; i++) { + FuUefiDevice *dev = g_ptr_array_index (devices, i); + g_autoptr(FuUefiUpdateInfo) info = NULL; + g_autoptr(GError) error_local = NULL; + + /* load any existing update info */ + info = fu_uefi_device_load_update_info (dev, &error_local); + g_print ("Information for the update status entry %u:\n", i); + if (info == NULL) { + if (g_error_matches (error_local, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND)) { + g_print (" Firmware GUID: {%s}\n", + fu_uefi_device_get_guid (dev)); + g_print (" Update Status: No update info found\n\n"); + } else { + g_printerr ("Failed: %s\n\n", error_local->message); + } + continue; + } + g_print (" Information Version: %" G_GUINT32_FORMAT "\n", + fu_uefi_update_info_get_version (info)); + g_print (" Firmware GUID: {%s}\n", + fu_uefi_update_info_get_guid (info)); + g_print (" Capsule Flags: 0x%08" G_GUINT32_FORMAT "x\n", + fu_uefi_update_info_get_capsule_flags (info)); + g_print (" Hardware Instance: %" G_GUINT64_FORMAT "\n", + fu_uefi_update_info_get_hw_inst (info)); + g_print (" Update Status: %s\n", + fu_uefi_update_info_status_to_string (fu_uefi_update_info_get_status (info))); + g_print (" Capsule File Path: %s\n\n", + fu_uefi_update_info_get_capsule_fn (info)); + } + } + + /* action_enable firmware update support on action_supported systems */ + if (action_enable) { + g_printerr ("Unsupported, use `fwupdmgr unlock`\n"); + return EXIT_FAILURE; + } + + /* set the debugging flag during update */ + if (action_set_debug) { + const guint8 data = 1; + g_autoptr(GError) error_local = NULL; + if (!fu_efivar_set_data (FU_EFIVAR_GUID_FWUPDATE, + "FWUPDATE_VERBOSE", + &data, sizeof(data), + FU_EFIVAR_ATTR_NON_VOLATILE | + FU_EFIVAR_ATTR_BOOTSERVICE_ACCESS | + FU_EFIVAR_ATTR_RUNTIME_ACCESS, + &error_local)) { + g_printerr ("failed: %s\n", error_local->message); + return EXIT_FAILURE; + } + g_print ("%s\n", _("Enabled fwupdate debugging")); + } + + /* unset the debugging flag during update */ + if (action_unset_debug) { + g_autoptr(GError) error_local = NULL; + if (!fu_efivar_delete (FU_EFIVAR_GUID_FWUPDATE, + "FWUPDATE_VERBOSE", + &error_local)) { + g_printerr ("failed: %s\n", error_local->message); + return EXIT_FAILURE; + } + g_print ("%s\n", _("Disabled fwupdate debugging")); + } + + /* apply firmware updates */ + if (apply != NULL) { + g_autoptr(FuUefiDevice) dev = fu_uefi_device_new_from_guid (apply); + g_autoptr(GError) error_local = NULL; + g_autoptr(GBytes) fw = NULL; + + if (argv[1] == NULL) { + g_printerr ("capsule filename required\n"); + return EXIT_FAILURE; + } + fw = fu_common_get_contents_bytes (argv[1], &error_local); + if (fw == NULL) { + g_printerr ("failed: %s\n", error_local->message); + return EXIT_FAILURE; + } + fu_uefi_device_set_esp (dev, esp); + if (flags != NULL) + fu_device_set_custom_flags (FU_DEVICE (dev), flags); + if (!fu_device_prepare (FU_DEVICE (dev), + FWUPD_INSTALL_FLAG_NONE, + &error_local)) { + g_printerr ("failed: %s\n", error_local->message); + return EXIT_FAILURE; + } + if (!fu_device_write_firmware (FU_DEVICE (dev), fw, + FWUPD_INSTALL_FLAG_NONE, + &error_local)) { + g_printerr ("failed: %s\n", error_local->message); + return EXIT_FAILURE; + } + if (!fu_device_cleanup (FU_DEVICE (dev), + FWUPD_INSTALL_FLAG_NONE, + &error_local)) { + g_printerr ("failed: %s\n", error_local->message); + return EXIT_FAILURE; + } + } + + /* success */ + return EXIT_SUCCESS; +} diff -Nru fwupd-1.4.5/plugins/uefi-capsule/fu-uefi-update-info.c fwupd-1.5.8/plugins/uefi-capsule/fu-uefi-update-info.c --- fwupd-1.4.5/plugins/uefi-capsule/fu-uefi-update-info.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/fu-uefi-update-info.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-common.h" +#include "fu-uefi-devpath.h" +#include "fu-uefi-update-info.h" +#include "fu-uefi-common.h" +#include "fu-ucs2.h" + +#include "fwupd-error.h" + +#define EFIDP_MEDIA_TYPE 0x04 +#define EFIDP_MEDIA_FILE 0x4 + +struct _FuUefiUpdateInfo { + GObject parent_instance; + guint32 version; + gchar *guid; + gchar *capsule_fn; + guint32 capsule_flags; + guint64 hw_inst; + FuUefiUpdateInfoStatus status; +}; + +G_DEFINE_TYPE (FuUefiUpdateInfo, fu_uefi_update_info, G_TYPE_OBJECT) + +const gchar * +fu_uefi_update_info_status_to_string (FuUefiUpdateInfoStatus status) +{ + if (status == FU_UEFI_UPDATE_INFO_STATUS_ATTEMPT_UPDATE) + return "attempt-update"; + if (status == FU_UEFI_UPDATE_INFO_STATUS_ATTEMPTED) + return "attempted"; + return "unknown"; +} + +static gchar * +fu_uefi_update_info_parse_dp (const guint8 *buf, gsize sz, GError **error) +{ + GBytes *dp_data; + const gchar *data; + gsize ucs2sz = 0; + g_autofree gchar *relpath = NULL; + g_autofree guint16 *ucs2file = NULL; + g_autoptr(GPtrArray) dps = NULL; + + g_return_val_if_fail (buf != NULL, NULL); + g_return_val_if_fail (sz != 0, NULL); + + /* get all headers */ + dps = fu_uefi_devpath_parse (buf, sz, FU_UEFI_DEVPATH_PARSE_FLAG_REPAIR, error); + if (dps == NULL) + return NULL; + dp_data = fu_uefi_devpath_find_data (dps, + EFIDP_MEDIA_TYPE, + EFIDP_MEDIA_FILE, + error); + if (dp_data == NULL) + return NULL; + + /* convert to UTF-8 */ + data = g_bytes_get_data (dp_data, &ucs2sz); + ucs2file = g_new0 (guint16, (ucs2sz / 2) + 1); + memcpy (ucs2file, data, ucs2sz); + relpath = fu_ucs2_to_uft8 (ucs2file, ucs2sz / sizeof (guint16)); + if (relpath == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "cannot convert to UTF-8"); + return NULL; + } + g_strdelimit (relpath, "\\", '/'); + return g_steal_pointer (&relpath); +} + +gboolean +fu_uefi_update_info_parse (FuUefiUpdateInfo *self, const guint8 *buf, gsize sz, GError **error) +{ + efi_update_info_t info; + fwupd_guid_t guid_tmp; + + g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), FALSE); + + if (sz < sizeof(efi_update_info_t)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "EFI variable is corrupt"); + return FALSE; + } + memcpy (&info, buf, sizeof(info)); + self->version = info.update_info_version; + self->capsule_flags = info.capsule_flags; + self->hw_inst = info.hw_inst; + self->status = info.status; + memcpy (&guid_tmp, &info.guid, sizeof(fwupd_guid_t)); + self->guid = fwupd_guid_to_string (&guid_tmp, FWUPD_GUID_FLAG_MIXED_ENDIAN); + if (sz > sizeof(efi_update_info_t)) { + self->capsule_fn = fu_uefi_update_info_parse_dp (buf + sizeof(efi_update_info_t), + sz - sizeof(efi_update_info_t), + error); + if (self->capsule_fn == NULL) + return FALSE; + } + return TRUE; +} + +const gchar * +fu_uefi_update_info_get_guid (FuUefiUpdateInfo *self) +{ + g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), NULL); + return self->guid; +} + +const gchar * +fu_uefi_update_info_get_capsule_fn (FuUefiUpdateInfo *self) +{ + g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), NULL); + return self->capsule_fn; +} + +guint32 +fu_uefi_update_info_get_version (FuUefiUpdateInfo *self) +{ + g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), 0); + return self->version; +} + +guint32 +fu_uefi_update_info_get_capsule_flags (FuUefiUpdateInfo *self) +{ + g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), 0); + return self->capsule_flags; +} + +guint64 +fu_uefi_update_info_get_hw_inst (FuUefiUpdateInfo *self) +{ + g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), 0); + return self->hw_inst; +} + +FuUefiUpdateInfoStatus +fu_uefi_update_info_get_status (FuUefiUpdateInfo *self) +{ + g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), 0); + return self->status; +} + +static void +fu_uefi_update_info_finalize (GObject *object) +{ + FuUefiUpdateInfo *self = FU_UEFI_UPDATE_INFO (object); + g_free (self->guid); + g_free (self->capsule_fn); + G_OBJECT_CLASS (fu_uefi_update_info_parent_class)->finalize (object); +} + +static void +fu_uefi_update_info_class_init (FuUefiUpdateInfoClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fu_uefi_update_info_finalize; +} + +static void +fu_uefi_update_info_init (FuUefiUpdateInfo *self) +{ +} + +FuUefiUpdateInfo * +fu_uefi_update_info_new (void) +{ + FuUefiUpdateInfo *self; + self = g_object_new (FU_TYPE_UEFI_UPDATE_INFO, NULL); + return FU_UEFI_UPDATE_INFO (self); +} diff -Nru fwupd-1.4.5/plugins/uefi-capsule/fu-uefi-update-info.h fwupd-1.5.8/plugins/uefi-capsule/fu-uefi-update-info.h --- fwupd-1.4.5/plugins/uefi-capsule/fu-uefi-update-info.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/fu-uefi-update-info.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#define FU_TYPE_UEFI_UPDATE_INFO (fu_uefi_update_info_get_type ()) +G_DECLARE_FINAL_TYPE (FuUefiUpdateInfo, fu_uefi_update_info, FU, UEFI_UPDATE_INFO, GObject) + +typedef enum { + FU_UEFI_UPDATE_INFO_STATUS_ATTEMPT_UPDATE = 0x00000001, + FU_UEFI_UPDATE_INFO_STATUS_ATTEMPTED = 0x00000002, +} FuUefiUpdateInfoStatus; + +const gchar *fu_uefi_update_info_status_to_string (FuUefiUpdateInfoStatus status); + +FuUefiUpdateInfo *fu_uefi_update_info_new (void); +gboolean fu_uefi_update_info_parse (FuUefiUpdateInfo *self, + const guint8 *buf, + gsize sz, + GError **error); +guint32 fu_uefi_update_info_get_version (FuUefiUpdateInfo *self); +const gchar *fu_uefi_update_info_get_guid (FuUefiUpdateInfo *self); +const gchar *fu_uefi_update_info_get_capsule_fn (FuUefiUpdateInfo *self); +guint32 fu_uefi_update_info_get_capsule_flags (FuUefiUpdateInfo *self); +guint64 fu_uefi_update_info_get_hw_inst (FuUefiUpdateInfo *self); +FuUefiUpdateInfoStatus fu_uefi_update_info_get_status (FuUefiUpdateInfo *self); diff -Nru fwupd-1.4.5/plugins/uefi-capsule/make-images.py fwupd-1.5.8/plugins/uefi-capsule/make-images.py --- fwupd-1.4.5/plugins/uefi-capsule/make-images.py 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/make-images.py 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,191 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +# +# Copyright (C) 2017 Peter Jones +# Copyright (C) 2020 Richard Hughes +# +# SPDX-License-Identifier: LGPL-2.1+ +# +# pylint: disable=wrong-import-position,too-many-locals,unused-argument,too-many-statements +# pylint: disable=invalid-name,too-many-instance-attributes,missing-module-docstring +# pylint: disable=missing-function-docstring,missing-class-docstring,too-few-public-methods + +import os +import sys +import argparse +import tarfile +import math +import io +from typing import Dict, Optional, Any + +import cairo +import gi + +gi.require_version("Pango", "1.0") +gi.require_version("PangoCairo", "1.0") +from gi.repository import Pango, PangoCairo +from PIL import Image + + +def languages(podir: str): + for x in open(os.path.join(podir, "LINGUAS"), "r").readlines(): + yield x.strip() + yield "en" + + +class PotFile: + def __init__(self, fn=None): + self.msgs: Dict[str, str] = {} + if fn: + self.parse(fn) + + def parse(self, fn: str) -> None: + with open(fn, "r") as f: + lang_en: Optional[str] = None + for line in f.read().split("\n"): + if not line: + continue + if line[0] == "#": + continue + try: + key, value = line.split(" ", maxsplit=1) + except ValueError as _: + continue + if key == "msgid": + lang_en = value[1:-1] + continue + if key == "msgstr" and lang_en: + self.msgs[lang_en] = value[1:-1] + lang_en = None + continue + + +def main(args) -> int: + + # open output archive + with tarfile.open(args.out, "w:xz") as tar: + + for lang in languages(args.podir): + # these are the 1.6:1 of some common(ish) screen widths + if lang == "en": + label_translated: str = args.label + else: + potfile = PotFile(os.path.join(args.podir, "{}.po".format(lang))) + try: + label_translated = potfile.msgs[args.label] + except KeyError as _: + continue + if label_translated == args.label: + continue + for width, height in ( + (640, 480), + (800, 600), + (1024, 768), + (1280, 720), + (1280, 800), + (1366, 768), + (1536, 864), + (1600, 900), + (1920, 1080), + (1920, 1200), + (2160, 1350), + (2560, 1440), + (3840, 2160), + (5120, 2880), + (5688, 3200), + (7680, 4320), + ): + + # generate PangoLanguage + font_desc = "Sans %.2fpx" % (height / 32,) + fd = Pango.FontDescription(font_desc) + font_option = cairo.FontOptions() + font_option.set_antialias(cairo.ANTIALIAS_SUBPIXEL) + l = Pango.Language.from_string(lang) + + # create surface + img = cairo.ImageSurface(cairo.FORMAT_RGB24, 1, 1) + cctx = cairo.Context(img) + layout = PangoCairo.create_layout(cctx) + pctx = layout.get_context() + pctx.set_font_description(fd) + pctx.set_language(l) + fs = pctx.load_fontset(fd, l) + PangoCairo.context_set_font_options(pctx, font_option) + + attrs = Pango.AttrList() + length = len(bytes(label_translated, "utf8")) + items = Pango.itemize(pctx, label_translated, 0, length, attrs, None) + gs = Pango.GlyphString() + Pango.shape(label_translated, length, items[0].analysis, gs) + del img, cctx, pctx, layout + + def find_size(fs, f, data): + """ find our size, I hope... """ + (ink, log) = gs.extents(f) + if ink.height == 0 or ink.width == 0: + return False + data.update({"log": log, "ink": ink}) + return True + + data: Dict[str, Any] = {} + fs.foreach(find_size, data) + if len(data) == 0: + print("Missing sans fonts") + return 2 + log = data["log"] + ink = data["ink"] + + surface_height = math.ceil(max(ink.height, log.height) / Pango.SCALE) + surface_width = math.ceil(max(ink.width, log.width) / Pango.SCALE) + + x = -math.ceil(log.x / Pango.SCALE) + y = -math.ceil(log.y / Pango.SCALE) + + img = cairo.ImageSurface( + cairo.FORMAT_RGB24, surface_width, surface_height + ) + cctx = cairo.Context(img) + layout = PangoCairo.create_layout(cctx) + pctx = layout.get_context() + PangoCairo.context_set_font_options(pctx, font_option) + + cctx.set_source_rgb(1, 1, 1) + cctx.move_to(x, y) + + def do_write(fs, f, data): + """ write out glyphs """ + ink = gs.extents(f)[0] + if ink.height == 0 or ink.width == 0: + return False + PangoCairo.show_glyph_string(cctx, f, gs) + return True + + fs.foreach(do_write, None) + img.flush() + + # write PNG + with io.BytesIO() as io_png: + img.write_to_png(io_png) + io_png.seek(0) + + # convert to BMP and add to archive + with io.BytesIO() as io_bmp: + pimg = Image.open(io_png) + pimg.save(io_bmp, format="BMP") + filename = "fwupd-{}-{}-{}.bmp".format(lang, width, height) + tarinfo = tarfile.TarInfo(filename) + tarinfo.size = io_bmp.tell() + io_bmp.seek(0) + tar.addfile(tarinfo, fileobj=io_bmp) + + # success + return 0 + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Make UX images") + parser.add_argument("--label", help="Update text", required=True) + parser.add_argument("--podir", help="Po location", required=True) + parser.add_argument("--out", help="Output archive", required=True) + sys.exit(main(parser.parse_args())) diff -Nru fwupd-1.4.5/plugins/uefi-capsule/meson.build fwupd-1.5.8/plugins/uefi-capsule/meson.build --- fwupd-1.4.5/plugins/uefi-capsule/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,164 @@ +if get_option('plugin_uefi_capsule') +subdir('efi') + +cargs = ['-DG_LOG_DOMAIN="FuPluginUefiCapsule"'] + +efi_os_dir = get_option('efi_os_dir') +if efi_os_dir != '' + cargs += '-DEFI_OS_DIR="' + efi_os_dir + '"' +endif + +install_data(['uefi-capsule.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d')) + +shared_module('fu_plugin_uefi_capsule', + fu_hash, + sources : [ + 'fu-plugin-uefi-capsule.c', + 'fu-uefi-bgrt.c', + 'fu-ucs2.c', + 'fu-uefi-bootmgr.c', + 'fu-uefi-common.c', + 'fu-uefi-device.c', + 'fu-uefi-devpath.c', + 'fu-uefi-pcrs.c', + 'fu-uefi-update-info.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + efiboot, + tpm2tss, + ], +) + +fwupdate = executable( + 'fwupdate', + resources_src, + fu_hash, + sources : [ + 'fu-uefi-tool.c', + 'fu-uefi-bgrt.c', + 'fu-ucs2.c', + 'fu-uefi-bootmgr.c', + 'fu-uefi-common.c', + 'fu-uefi-device.c', + 'fu-uefi-devpath.c', + 'fu-uefi-pcrs.c', + 'fu-uefi-update-info.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + dependencies : [ + plugin_deps, + efiboot, + tpm2tss, + ], + link_with : [ + fwupd, + fwupdplugin, + ], + install : true, + install_dir : bindir, + c_args : cargs, +) + +if get_option('man') + custom_target('fwupdate-man', + input : fwupdate, + output : 'fwupdate.1', + command : [ + help2man, '@INPUT@', + '--no-info', + '--output', '@OUTPUT@', + '--name', 'Debugging utility for UEFI firmware updates', + '--manual', 'User Commands', + '--version-string', fwupd_version, + ], + install : true, + install_dir : join_paths(mandir, 'man1'), + ) +endif + +install_data(['uefi_capsule.conf'], + install_dir: join_paths(sysconfdir, 'fwupd') +) + +# add all the .po files as inputs to watch +ux_linguas = run_command( + 'cat', files(join_paths(meson.source_root(), 'po', 'LINGUAS')), +).stdout().strip().split('\n') +ux_capsule_pofiles = [] +foreach ux_lingua : ux_linguas + ux_capsule_pofiles += join_paths(meson.source_root(), 'po', '@0@.po'.format(ux_lingua)) +endforeach + +# add the archive of pregenerated images +custom_target('ux-capsule-tar', + input : [ + join_paths(meson.source_root(), 'po', 'LINGUAS'), + join_paths(meson.current_source_dir(), 'make-images.py'), + ux_capsule_pofiles, + ], + output : 'uefi-capsule-ux.tar.xz', + command : [ + python3.path(), + join_paths(meson.current_source_dir(), 'make-images.py'), + '--podir', join_paths(meson.source_root(), 'po'), + '--label', 'Installing firmware update…', + '--out', '@OUTPUT@', + ], + install: true, + install_dir: join_paths(datadir, 'fwupd'), +) + +if get_option('tests') + testdatadir = join_paths(meson.current_source_dir(), 'tests') + cargs += '-DTESTDATADIR="' + testdatadir + '"' + e = executable( + 'uefi-self-test', + fu_hash, + sources : [ + 'fu-self-test.c', + 'fu-uefi-bgrt.c', + 'fu-uefi-bootmgr.c', + 'fu-uefi-common.c', + 'fu-uefi-device.c', + 'fu-uefi-devpath.c', + 'fu-uefi-pcrs.c', + 'fu-uefi-update-info.c', + 'fu-ucs2.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + dependencies : [ + plugin_deps, + efiboot, + tpm2tss, + ], + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs + ) + test('uefi-self-test', e) +endif +endif diff -Nru fwupd-1.4.5/plugins/uefi-capsule/README.md fwupd-1.5.8/plugins/uefi-capsule/README.md --- fwupd-1.4.5/plugins/uefi-capsule/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,105 @@ +UEFI Capsule Support +==================== + +Introduction +------------ + +The Unified Extensible Firmware Interface (UEFI) is a specification that +defines the software interface between an OS and platform firmware. +With the UpdateCapsule boot service it can be used to update system firmware. + +If you don't want or need this functionality you can use the +`-Dplugin_uefi_capsule=false` option. + +Lenovo Specific Behavior +------------------------ + +On Lenovo hardware only the boot label is set to `Linux-Firmware-Updater` rather +than "Linux Firmware Updater" (with spaces) due to long-fixed EFI boot manager +bugs. Many users will have these old BIOS versions installed and so we use the +`use-legacy-bootmgr-desc` quirk to use the safe name. + +On some Lenovo hardware only one capsule is installable due to possible problems +with the UpdateCapsule coalesce operation. As soon as one UEFI device has been +scheduled for update the other UEFI devices found in the ESRT will be marked +as `updatable-hidden` rather than `updatable`. Rebooting will restore them so +they can be updated on next OS boot. + +UEFI SBAT Support +----------------- + +If compiling with `-Dsupported_build=true` the packager must also specify the +SBAT metadata required for the secure boot revocation support. See the +specification for more information: https://github.com/rhboot/shim/blob/sbat/SBAT.md + +Typically, this will be set as part of the package build script, e.g. + + -Defi_sbat_distro_id="fedora" \ + -Defi_sbat_distro_summary="The Fedora Project" \ + -Defi_sbat_distro_pkgname="%{name}" \ + -Defi_sbat_distro_version="%{version}" \ + -Defi_sbat_distro_url="https://src.fedoraproject.org/rpms/%{name}" \ + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +EFI capsule file format. + +See https://www.uefi.org/sites/default/files/resources/UEFI%20Spec%202_6.pdf +for details. + +This plugin supports the following protocol ID: + + * org.uefi.capsule + +Update Behavior +--------------- + +The firmware is deployed when the OS is running, but it is only written when the +system has been restarted and the `fwupd*.efi` binary has been run. To achieve +this fwupd sets up the EFI `BootNext` variable, creating the new boot entry if +required. + +GUID Generation +--------------- + +These devices use the UEFI GUID as provided in the ESRT. Additionally, for the +system device the `main-system-firmware` GUID is also added. + +For compatibility with Windows 10, the plugin also adds GUIDs of the form +`UEFI\RES_{$(esrt)}`. + +Vendor ID Security +------------------ + +The vendor ID is set from the BIOS vendor, for example `DMI:LENOVO` for all +devices that are not marked as supporting Firmware Management Protocol. For FMP +device no vendor ID is set. + +UEFI Unlock Support +------------------- + +On some Dell systems it is possible to turn on and off UEFI capsule +support from within the BIOS. This functionality can also be adjusted +from within the OS by fwupd. This requires compiling with libsmbios support. + +When fwupd has been compiled with this support you will be able to enable UEFI +support on the device by using the `unlock` command. + +Custom EFI System Partition +--------------------------- + +Since version 1.1.0 fwupd will autodetect the ESP when it is mounted on +`/boot/efi`, `/boot`, or `/efi`. A custom EFI system partition location can be +used by modifying *OverrideESPMountPoint* in `/etc/fwupd/uefi_capsule.conf`. + +Setting an invalid directory will disable the fwupd plugin. + +External interface access +------------------------- +This plugin requires: +* read/write access to the EFI system partition. +* read access to `/sys/firmware/efi/esrt/` +* read access to `/sys/firmware/efi/fw_platform_size` +* read/write access to `/sys/firmware/efi/efivars` Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/uefi-capsule/tests/acpi/bgrt/image and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/uefi-capsule/tests/acpi/bgrt/image differ diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/acpi/bgrt/status fwupd-1.5.8/plugins/uefi-capsule/tests/acpi/bgrt/status --- fwupd-1.4.5/plugins/uefi-capsule/tests/acpi/bgrt/status 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/acpi/bgrt/status 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/acpi/bgrt/type fwupd-1.5.8/plugins/uefi-capsule/tests/acpi/bgrt/type --- fwupd-1.4.5/plugins/uefi-capsule/tests/acpi/bgrt/type 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/acpi/bgrt/type 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +0 diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/acpi/bgrt/version fwupd-1.5.8/plugins/uefi-capsule/tests/acpi/bgrt/version --- fwupd-1.4.5/plugins/uefi-capsule/tests/acpi/bgrt/version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/acpi/bgrt/version 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/acpi/bgrt/xoffset fwupd-1.5.8/plugins/uefi-capsule/tests/acpi/bgrt/xoffset --- fwupd-1.4.5/plugins/uefi-capsule/tests/acpi/bgrt/xoffset 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/acpi/bgrt/xoffset 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +123 diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/acpi/bgrt/yoffset fwupd-1.5.8/plugins/uefi-capsule/tests/acpi/bgrt/yoffset --- fwupd-1.4.5/plugins/uefi-capsule/tests/acpi/bgrt/yoffset 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/acpi/bgrt/yoffset 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +456 Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/uefi-capsule/tests/efi/efivars/fwupd-ddc0ee61-e7f0-4e7d-acc5-c070a398838e-0-0abba7dc-e516-4167-bbf5-4d9d1c739416 and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/uefi-capsule/tests/efi/efivars/fwupd-ddc0ee61-e7f0-4e7d-acc5-c070a398838e-0-0abba7dc-e516-4167-bbf5-4d9d1c739416 differ diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry0/capsule_flags fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry0/capsule_flags --- fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry0/capsule_flags 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry0/capsule_flags 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +0xfe diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry0/fw_class fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry0/fw_class --- fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry0/fw_class 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry0/fw_class 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +ddc0ee61-e7f0-4e7d-acc5-c070a398838e diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry0/fw_type fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry0/fw_type --- fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry0/fw_type 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry0/fw_type 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry0/fw_version fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry0/fw_version --- fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry0/fw_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry0/fw_version 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +65586 diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry0/last_attempt_status fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry0/last_attempt_status --- fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry0/last_attempt_status 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry0/last_attempt_status 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry0/last_attempt_version fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry0/last_attempt_version --- fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry0/last_attempt_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry0/last_attempt_version 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +18472960 diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry0/lowest_supported_fw_version fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry0/lowest_supported_fw_version --- fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry0/lowest_supported_fw_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry0/lowest_supported_fw_version 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +65582 diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry1/capsule_flags fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry1/capsule_flags --- fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry1/capsule_flags 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry1/capsule_flags 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +0x8010 diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry1/fw_class fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry1/fw_class --- fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry1/fw_class 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry1/fw_class 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +671d19d0-d43c-4852-98d9-1ce16f9967e4 diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry1/fw_type fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry1/fw_type --- fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry1/fw_type 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry1/fw_type 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +2 diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry1/fw_version fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry1/fw_version --- fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry1/fw_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry1/fw_version 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +3090287969 diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry1/last_attempt_status fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry1/last_attempt_status --- fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry1/last_attempt_status 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry1/last_attempt_status 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +0 diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry1/last_attempt_version fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry1/last_attempt_version --- fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry1/last_attempt_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry1/last_attempt_version 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +0 diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry1/lowest_supported_fw_version fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry1/lowest_supported_fw_version --- fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry1/lowest_supported_fw_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry1/lowest_supported_fw_version 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry2/capsule_flags fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry2/capsule_flags --- fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry2/capsule_flags 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry2/capsule_flags 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +0x8010 diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry2/fw_class fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry2/fw_class --- fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry2/fw_class 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry2/fw_class 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +00000000-0000-0000-0000-000000000000 diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry2/fw_type fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry2/fw_type --- fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry2/fw_type 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry2/fw_type 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +2 diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry2/fw_version fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry2/fw_version --- fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry2/fw_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry2/fw_version 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +3090287969 diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry2/last_attempt_status fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry2/last_attempt_status --- fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry2/last_attempt_status 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry2/last_attempt_status 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +0 diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry2/last_attempt_version fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry2/last_attempt_version --- fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry2/last_attempt_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry2/last_attempt_version 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +0 diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry2/lowest_supported_fw_version fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry2/lowest_supported_fw_version --- fwupd-1.4.5/plugins/uefi-capsule/tests/efi/esrt/entries/entry2/lowest_supported_fw_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/efi/esrt/entries/entry2/lowest_supported_fw_version 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/efi/fw_platform_size fwupd-1.5.8/plugins/uefi-capsule/tests/efi/fw_platform_size --- fwupd-1.4.5/plugins/uefi-capsule/tests/efi/fw_platform_size 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/efi/fw_platform_size 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +64 diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/efi-framebuffer/efi-framebuffer.0/height fwupd-1.5.8/plugins/uefi-capsule/tests/efi-framebuffer/efi-framebuffer.0/height --- fwupd-1.4.5/plugins/uefi-capsule/tests/efi-framebuffer/efi-framebuffer.0/height 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/efi-framebuffer/efi-framebuffer.0/height 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +789 diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/efi-framebuffer/efi-framebuffer.0/width fwupd-1.5.8/plugins/uefi-capsule/tests/efi-framebuffer/efi-framebuffer.0/width --- fwupd-1.4.5/plugins/uefi-capsule/tests/efi-framebuffer/efi-framebuffer.0/width 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/efi-framebuffer/efi-framebuffer.0/width 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +456 diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/.gitignore fwupd-1.5.8/plugins/uefi-capsule/tests/.gitignore --- fwupd-1.4.5/plugins/uefi-capsule/tests/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/.gitignore 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,2 @@ +EFI +efi/efivars/fwupd-c34cb672-a81e-5d32-9d89-cbcabe8ec37b-0-0abba7dc-e516-4167-bbf5-4d9d1c739416 Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/uefi-capsule/tests/test.bmp and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/uefi-capsule/tests/test.bmp differ diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/tpm0/active fwupd-1.5.8/plugins/uefi-capsule/tests/tpm0/active --- fwupd-1.4.5/plugins/uefi-capsule/tests/tpm0/active 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/tpm0/active 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/tpm0/caps fwupd-1.5.8/plugins/uefi-capsule/tests/tpm0/caps --- fwupd-1.4.5/plugins/uefi-capsule/tests/tpm0/caps 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/tpm0/caps 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,3 @@ +Manufacturer: 0x49465800 +TCG version: 1.2 +Firmware version: 6.40 diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/tpm0/enabled fwupd-1.5.8/plugins/uefi-capsule/tests/tpm0/enabled --- fwupd-1.4.5/plugins/uefi-capsule/tests/tpm0/enabled 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/tpm0/enabled 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/tpm0/owned fwupd-1.5.8/plugins/uefi-capsule/tests/tpm0/owned --- fwupd-1.4.5/plugins/uefi-capsule/tests/tpm0/owned 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/tpm0/owned 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.4.5/plugins/uefi-capsule/tests/tpm0/pcrs fwupd-1.5.8/plugins/uefi-capsule/tests/tpm0/pcrs --- fwupd-1.4.5/plugins/uefi-capsule/tests/tpm0/pcrs 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/tests/tpm0/pcrs 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,24 @@ +PCR-00: 3C 97 99 20 C9 00 99 60 09 27 D5 DA B3 81 EB 95 1E 7F C8 68 +PCR-01: CE 9F A4 B2 01 09 D8 81 14 EA 1A 6D 13 94 CD 45 5F 52 69 23 +PCR-02: 47 09 7A 9A AD C3 26 A4 93 91 26 63 A1 6F DF 53 D7 88 96 8E +PCR-03: B2 A8 3B 0E BF 2F 83 74 29 9A 5B 2B DF C3 1E A9 55 AD 72 36 +PCR-04: A4 A5 87 4C 59 94 8D 9B 93 66 0A F4 19 D8 6F F8 94 36 20 CC +PCR-05: 00 0B 58 00 89 72 EF 6C 2A AC 79 33 C4 AE 67 6B A6 EF CF 6A +PCR-06: B2 A8 3B 0E BF 2F 83 74 29 9A 5B 2B DF C3 1E A9 55 AD 72 36 +PCR-07: 0A 2A 68 15 85 0D AC B2 D1 F4 E0 C1 F4 56 D5 E2 81 08 6D EA +PCR-08: DB A7 29 4E 49 BA D7 9E 53 99 0A 6E 3A CB 52 97 B9 08 3A 66 +PCR-09: 19 F9 6F 10 83 F5 5B 50 98 26 C3 14 73 43 35 21 1F E6 39 E9 +PCR-10: 37 3D 89 9E 10 0D DD 2D 21 B5 F4 96 8D 4F DC A7 6D 1A C7 BD +PCR-11: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-12: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-13: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-14: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-15: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-16: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-17: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-18: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-19: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-20: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-21: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-22: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-23: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 diff -Nru fwupd-1.4.5/plugins/uefi-capsule/uefi_capsule.conf fwupd-1.5.8/plugins/uefi-capsule/uefi_capsule.conf --- fwupd-1.4.5/plugins/uefi-capsule/uefi_capsule.conf 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/uefi_capsule.conf 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,16 @@ +[uefi_capsule] + +# the shim loader is required to chainload the fwupd EFI binary unless +# the fwupd.efi file has been self-signed manually +#DisableShimForSecureBoot=true + +# the EFI system partition path used +# if this is is not /boot/efi, /boot, or /efi +#OverrideESPMountPoint= + +# amount of free space required on the ESP, for example using 0x2000000 for 32Mb +#RequireESPFreeSpace= + +# with the UEFI removable path enabled, the default esp path is set to /EFI/boot +# the shim EFI binary and presumably this is $ESP/EFI/boot/bootx64.efi +#FallbacktoRemovablePath=false diff -Nru fwupd-1.4.5/plugins/uefi-capsule/uefi-capsule.quirk fwupd-1.5.8/plugins/uefi-capsule/uefi-capsule.quirk --- fwupd-1.4.5/plugins/uefi-capsule/uefi-capsule.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-capsule/uefi-capsule.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,39 @@ +# Star Labs Lite (Mk III) +[d9d7b13b-e4db-4f91-8bf6-8952a9caa82a] +Flags = no-ux-capsule + +# Star Labs LabTop (Mk III) +[8265d473-a6c2-42b4-897b-bc220faa2d32] +Flags = use-shim-unique + +# Star Labs Lite (Mk II) +[797f8bae-0ea2-4c0f-8a30-7d10ccfacbc0] +Flags = use-shim-unique,no-ux-capsule + +# Silicom Minnowboard Turbot D0/D1 PLATFORM +[386c2f52-44ec-55d3-b802-47631bfb8451] +Flags = uefi-force-enable + +# Lenovo +[6de5d951-d755-576b-bd09-c5cf66b27234] +Flags = boot-order-lock,use-legacy-bootmgr-desc + +# Lenovo ThinkPad X1 Yoga 4th +[1138930e-8df1-5ae0-b946-7b0d9c9b4a79] +Flags = no-coalesce + +# Lenovo ThinkPad X1 Carbon 5th +[595a0c1a-9819-52f6-8ea7-e0924c073f64] +Flags = no-coalesce + +# Lenovo ThinkPad X1 Carbon 7th +[30ddbc9b-8200-5581-8dfd-6bb26e2e42d7] +Flags = no-coalesce + +# Lenovo ThinkPad T460s +[90706264-e399-575b-a9fb-077ead03b9b4] +Flags = no-coalesce + +# Dynabook (né Toshiba) X30, X40 +[28108d08-5027-42c2-a5b8-92d6ede9b97b] +VersionFormat = bcd diff -Nru fwupd-1.4.5/plugins/uefi-dbx/dbxtool.h2m fwupd-1.5.8/plugins/uefi-dbx/dbxtool.h2m --- fwupd-1.4.5/plugins/uefi-dbx/dbxtool.h2m 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-dbx/dbxtool.h2m 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,7 @@ +[DESCRIPTION] +.PP +This manual page documents briefly the \fBdbxtool\fR command. +.PP +\fBdbxtool\fR allows a user to operate on the UEFI dbx revokation list. +This tool can be used to list the current dbx contents or update it to a newer +version. diff -Nru fwupd-1.4.5/plugins/uefi-dbx/fu-dbxtool.c fwupd-1.5.8/plugins/uefi-dbx/fu-dbxtool.c --- fwupd-1.4.5/plugins/uefi-dbx/fu-dbxtool.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-dbx/fu-dbxtool.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,290 @@ +/* + * Copyright (C) 2015 Peter Jones + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "fu-common.h" +#include "fu-efivar.h" +#include "fu-uefi-dbx-common.h" +#include "fu-efi-signature.h" + +/* custom return code */ +#define EXIT_NOTHING_TO_DO 2 + +static void +fu_util_ignore_cb (const gchar *log_domain, GLogLevelFlags log_level, + const gchar *message, gpointer user_data) +{ +} + +static FuFirmware * +fu_dbxtool_get_siglist_system (GError **error) +{ + g_autoptr(GBytes) blob = NULL; + g_autoptr(FuFirmware) dbx = fu_efi_signature_list_new (); + blob = fu_efivar_get_data_bytes (FU_EFIVAR_GUID_SECURITY_DATABASE, "dbx", NULL, error); + if (blob == NULL) + return NULL; + if (!fu_firmware_parse (dbx, blob, FWUPD_INSTALL_FLAG_NO_SEARCH, error)) + return NULL; + return g_steal_pointer (&dbx); +} + +static FuFirmware * +fu_dbxtool_get_siglist_local (const gchar *filename, GError **error) +{ + g_autoptr(GBytes) blob = NULL; + g_autoptr(FuFirmware) siglist = fu_efi_signature_list_new (); + blob = fu_common_get_contents_bytes (filename, error); + if (blob == NULL) + return NULL; + if (!fu_firmware_parse (siglist, blob, FWUPD_INSTALL_FLAG_NONE, error)) + return NULL; + return g_steal_pointer (&siglist); +} + +static gboolean +fu_dbxtool_siglist_inclusive (FuFirmware *outer, FuFirmware *inner) +{ + g_autoptr(GPtrArray) sigs = fu_firmware_get_images (inner); + for (guint i = 0; i < sigs->len; i++) { + FuEfiSignature *sig = g_ptr_array_index (sigs, i); + g_autofree gchar *checksum = NULL; + g_autoptr(FuFirmwareImage) img = NULL; + checksum = fu_firmware_image_get_checksum (FU_FIRMWARE_IMAGE (sig), + G_CHECKSUM_SHA256, NULL); + if (checksum == NULL) + continue; + img = fu_firmware_get_image_by_checksum (outer, checksum, NULL); + if (img == NULL) + return FALSE; + } + return TRUE; +} + +static const gchar * +fu_dbxtool_guid_to_string (const gchar *guid) +{ + if (g_strcmp0 (guid, FU_EFI_SIGNATURE_GUID_ZERO) == 0) + return "zero"; + if (g_strcmp0 (guid, FU_EFI_SIGNATURE_GUID_MICROSOFT) == 0) + return "microsoft"; + if (g_strcmp0 (guid, FU_EFI_SIGNATURE_GUID_OVMF) == 0 || + g_strcmp0 (guid, FU_EFI_SIGNATURE_GUID_OVMF_LEGACY) == 0) + return "ovmf"; + return guid; +} + +int +main (int argc, char *argv[]) +{ + gboolean action_apply = FALSE; + gboolean action_list = FALSE; + gboolean action_version = FALSE; + gboolean force = FALSE; + gboolean verbose = FALSE; + g_autofree gchar *dbxfile = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GOptionContext) context = NULL; + g_autofree gchar *tmp = NULL; + const GOptionEntry options[] = { + { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, + /* TRANSLATORS: command line option */ + _("Show extra debugging information"), NULL }, + { "version", '\0', 0, G_OPTION_ARG_NONE, &action_version, + /* TRANSLATORS: command line option */ + _("Show the calculated version of the dbx"), NULL }, + { "list", 'l', 0, G_OPTION_ARG_NONE, &action_list, + /* TRANSLATORS: command line option */ + _("List entries in dbx"), NULL }, + { "apply", 'a', 0, G_OPTION_ARG_NONE, &action_apply, + /* TRANSLATORS: command line option */ + _("Apply update files"), NULL }, + { "dbx", 'd', 0, G_OPTION_ARG_STRING, &dbxfile, + /* TRANSLATORS: command line option */ + _("Specify the dbx database file"), + /* TRANSLATORS: command argument: uppercase, spaces->dashes */ + _("FILENAME") }, + { "force", 'f', 0, G_OPTION_ARG_NONE, &force, + /* TRANSLATORS: command line option */ + _("Apply update even when not advised"), NULL }, + { NULL} + }; + + setlocale (LC_ALL, ""); + + bindtextdomain (GETTEXT_PACKAGE, FWUPD_LOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + /* get a action_list of the commands */ + context = g_option_context_new (NULL); + g_option_context_set_description (context, + /* TRANSLATORS: description of dbxtool */ + _("This tool allows an administrator to apply UEFI dbx updates.")); + + /* TRANSLATORS: program name */ + g_set_application_name (_("UEFI dbx Utility")); + g_option_context_add_main_entries (context, options, NULL); + if (!g_option_context_parse (context, &argc, &argv, &error)) { + /* TRANSLATORS: the user didn't read the man page */ + g_print ("%s: %s\n", _("Failed to parse arguments"), + error->message); + return EXIT_FAILURE; + } + + /* set verbose? */ + if (verbose) { + g_setenv ("G_MESSAGES_DEBUG", "all", FALSE); + } else { + g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, + fu_util_ignore_cb, NULL); + } + + /* list contents, either of the existing system, or an update */ + if (action_list || action_version) { + guint cnt = 1; + g_autoptr(FuFirmware) dbx = NULL; + g_autoptr(GPtrArray) sigs = NULL; + if (dbxfile != NULL) { + dbx = fu_dbxtool_get_siglist_local (dbxfile, &error); + if (dbx == NULL) { + /* TRANSLATORS: could not read existing system data */ + g_printerr ("%s: %s\n", _("Failed to load local dbx"), error->message); + return EXIT_FAILURE; + } + } else { + dbx = fu_dbxtool_get_siglist_system (&error); + if (dbx == NULL) { + /* TRANSLATORS: could not read existing system data */ + g_printerr ("%s: %s\n", _("Failed to load system dbx"), error->message); + return EXIT_FAILURE; + } + } + if (action_version) { + /* TRANSLATORS: the detected version number of the dbx */ + g_print ("%s: %s\n", _("Version"), fu_firmware_get_version (dbx)); + return EXIT_SUCCESS; + } + sigs = fu_firmware_get_images (FU_FIRMWARE (dbx)); + for (guint i = 0; i < sigs->len; i++) { + FuEfiSignature *sig = g_ptr_array_index (sigs, i); + g_autofree gchar *checksum = NULL; + checksum = fu_firmware_image_get_checksum (FU_FIRMWARE_IMAGE (sig), + G_CHECKSUM_SHA256, + NULL); + g_print ("%4u: {%s} {%s} %s\n", + cnt++, + fu_dbxtool_guid_to_string (fu_efi_signature_get_owner (sig)), + fu_efi_signature_kind_to_string (fu_efi_signature_get_kind (sig)), + checksum); + } + return EXIT_SUCCESS; + } + +#ifdef HAVE_GETUID + /* ensure root user */ + if (getuid () != 0 || geteuid () != 0) { + /* TRANSLATORS: we're poking around as a power user */ + g_printerr ("%s\n", _("This program may only work correctly as root")); + } +#endif + + /* apply update */ + if (action_apply) { + g_autoptr(FuFirmware) dbx_system = NULL; + g_autoptr(FuFirmware) dbx_update = fu_efi_signature_list_new (); + g_autoptr(GBytes) blob = NULL; + + if (dbxfile == NULL) { + /* TRANSLATORS: user did not include a filename parameter */ + g_printerr ("%s\n", _("Filename required")); + return EXIT_FAILURE; + } + + /* TRANSLATORS: reading existing dbx from the system */ + g_print ("%s\n", _("Parsing system dbx…")); + dbx_system = fu_dbxtool_get_siglist_system (&error); + if (dbx_system == NULL) { + /* TRANSLATORS: could not read existing system data */ + g_printerr ("%s: %s\n", _("Failed to load system dbx"), error->message); + return EXIT_FAILURE; + } + + /* TRANSLATORS: reading new dbx from the update */ + g_print ("%s\n", _("Parsing dbx update…")); + blob = fu_common_get_contents_bytes (dbxfile, &error); + if (blob == NULL) { + /* TRANSLATORS: could not read file */ + g_printerr ("%s: %s\n", _("Failed to load local dbx"), error->message); + return EXIT_FAILURE; + } + if (!fu_firmware_parse (dbx_update, blob, FWUPD_INSTALL_FLAG_NONE, &error)) { + /* TRANSLATORS: could not parse file */ + g_printerr ("%s: %s\n", _("Failed to parse local dbx"), error->message); + return EXIT_FAILURE; + } + + /* check this is a newer dbx update */ + if (!force && fu_dbxtool_siglist_inclusive (dbx_system, dbx_update)) { + /* TRANSLATORS: same or newer update already applied */ + g_printerr ("%s\n", _("Cannot apply as dbx update has already been applied.")); + return EXIT_FAILURE; + } + + /* check if on live media */ + if (fu_common_is_live_media () && !force) { + /* TRANSLATORS: the user is using a LiveCD or LiveUSB install disk */ + g_printerr ("%s\n", _("Cannot apply updates on live media")); + return EXIT_FAILURE; + } + + /* validate this is safe to apply */ + if (!force) { + /* TRANSLATORS: ESP refers to the EFI System Partition */ + g_print ("%s\n", _("Validating ESP contents…")); + if (!fu_uefi_dbx_signature_list_validate (FU_EFI_SIGNATURE_LIST (dbx_update), &error)) { + /* TRANSLATORS: something with a blocked hash exists + * in the users ESP -- which would be bad! */ + g_printerr ("%s: %s\n", _("Failed to validate ESP contents"), error->message); + return EXIT_FAILURE; + } + } + + /* TRANSLATORS: actually sending the update to the hardware */ + g_print ("%s\n", _("Applying update…")); + if (!fu_efivar_set_data_bytes (FU_EFIVAR_GUID_SECURITY_DATABASE, + "dbx", blob, + FU_EFIVAR_ATTR_APPEND_WRITE | + FU_EFIVAR_ATTR_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | + FU_EFIVAR_ATTR_RUNTIME_ACCESS | + FU_EFIVAR_ATTR_BOOTSERVICE_ACCESS | + FU_EFIVAR_ATTR_NON_VOLATILE, + &error)) { + /* TRANSLATORS: dbx file failed to be applied as an update */ + g_printerr ("%s: %s\n", _("Failed to apply update"), error->message); + return EXIT_FAILURE; + } + + /* TRANSLATORS: success */ + g_print ("%s\n", _("Done!")); + return EXIT_SUCCESS; + } + + /* nothing specified */ + tmp = g_option_context_get_help (context, TRUE, NULL); + /* TRANSLATORS: user did not tell the tool what to do */ + g_printerr ("%s\n\n%s", _("No action specified!"), tmp); + return EXIT_FAILURE; +} diff -Nru fwupd-1.4.5/plugins/uefi-dbx/fu-efi-image.c fwupd-1.5.8/plugins/uefi-dbx/fu-efi-image.c --- fwupd-1.4.5/plugins/uefi-dbx/fu-efi-image.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-dbx/fu-efi-image.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,332 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-common.h" +#include "fu-efi-image.h" + +struct _FuEfiImage { + GObject parent_instance; + gchar *checksum; +}; + +typedef struct { + gsize offset; + gsize size; + gchar *name; +} FuEfiImageRegion; + +typedef struct __attribute__((packed)) { + guint32 addr; + guint32 size; +} FuEfiImageDataDirEntry; + +G_DEFINE_TYPE (FuEfiImage, fu_efi_image, G_TYPE_OBJECT) + +#define _DOS_OFFSET_SIGNATURE 0x00 +#define _DOS_OFFSET_TO_PE_HEADER 0x3c + +#define _PEI_OFFSET_SIGNATURE 0x00 +#define _PEI_OFFSET_MACHINE 0x04 +#define _PEI_OFFSET_NUMBER_OF_SECTIONS 0x06 +#define _PEI_OFFSET_OPTIONAL_HEADER_SIZE 0x14 +#define _PEI_HEADER_SIZE 0x18 + +#define _PE_OFFSET_SIZE_OF_HEADERS 0x54 +#define _PE_OFFSET_CHECKSUM 0x58 +#define _PE_OFFSET_DEBUG_TABLE_OFFSET 0x98 + +#define _PEP_OFFSET_SIZE_OF_HEADERS 0x54 +#define _PEP_OFFSET_CHECKSUM 0x58 +#define _PEP_OFFSET_DEBUG_TABLE_OFFSET 0xa8 + +#define _SECTION_HEADER_OFFSET_NAME 0x0 +#define _SECTION_HEADER_OFFSET_SIZE 0x10 +#define _SECTION_HEADER_OFFSET_PTR 0x14 +#define _SECTION_HEADER_SIZE 0x28 + +#define IMAGE_FILE_MACHINE_AMD64 0x8664 +#define IMAGE_FILE_MACHINE_I386 0x014c +#define IMAGE_FILE_MACHINE_THUMB 0x01c2 +#define IMAGE_FILE_MACHINE_AARCH64 0xaa64 + +static gint +fu_efi_image_region_sort_cb (gconstpointer a, gconstpointer b) +{ + const FuEfiImageRegion *r1 = *((const FuEfiImageRegion **) a); + const FuEfiImageRegion *r2 = *((const FuEfiImageRegion **) b); + if (r1->offset < r2->offset) + return -1; + if (r1->offset > r2->offset) + return 1; + return 0; +} + +static FuEfiImageRegion * +fu_efi_image_add_region (GPtrArray *checksum_regions, + const gchar *name, + gsize offset_start, + gsize offset_end) +{ + FuEfiImageRegion *r = g_new0 (FuEfiImageRegion, 1); + r->name = g_strdup (name); + r->offset = offset_start; + r->size = offset_end - offset_start; + g_ptr_array_add (checksum_regions, r); + return r; +} + +static void +fu_efi_image_region_free (FuEfiImageRegion *r) +{ + g_free (r->name); + g_free (r); +} + +FuEfiImage * +fu_efi_image_new (GBytes *data, GError **error) +{ + FuEfiImageRegion *r; + const guint8 *buf; + gsize bufsz; + gsize image_bytes = 0; + gsize checksum_offset; + gsize data_dir_debug_offset; + gsize offset_tmp; + guint16 dos_sig = 0; + guint16 machine = 0; + guint16 opthdrsz; + guint16 sections; + guint32 baseaddr = 0; + guint32 cert_table_size; + guint32 header_size; + guint32 nt_sig = 0; + g_autoptr(FuEfiImage) self = g_object_new (FU_TYPE_EFI_IMAGE, NULL); + g_autoptr(GChecksum) checksum = g_checksum_new (G_CHECKSUM_SHA256); + g_autoptr(GPtrArray) checksum_regions = NULL; + + /* verify this is a DOS file */ + buf = g_bytes_get_data (data, &bufsz); + if (!fu_common_read_uint16_safe (buf, bufsz, + _DOS_OFFSET_SIGNATURE, + &dos_sig, G_LITTLE_ENDIAN, error)) + return NULL; + if (dos_sig != 0x5a4d) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "Invalid DOS header magic %04x", dos_sig); + return NULL; + } + + /* verify the PE signature */ + if (!fu_common_read_uint32_safe (buf, bufsz, + _DOS_OFFSET_TO_PE_HEADER, + &baseaddr, G_LITTLE_ENDIAN, error)) + return NULL; + if (!fu_common_read_uint32_safe (buf, bufsz, + baseaddr + _PEI_OFFSET_SIGNATURE, + &nt_sig, G_LITTLE_ENDIAN, error)) + return NULL; + if (nt_sig != 0x4550) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "Invalid PE header signature %08x", nt_sig); + return NULL; + } + + /* which machine type are we reading */ + if (!fu_common_read_uint16_safe (buf, bufsz, + baseaddr + _PEI_OFFSET_MACHINE, + &machine, G_LITTLE_ENDIAN, error)) + return NULL; + if (machine == IMAGE_FILE_MACHINE_AMD64 || + machine == IMAGE_FILE_MACHINE_AARCH64) { + + /* a.out header directly follows PE header */ + if (!fu_common_read_uint16_safe (buf, bufsz, + baseaddr + _PEI_HEADER_SIZE, + &machine, G_LITTLE_ENDIAN, error)) + return NULL; + if (machine != 0x020b) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "Invalid a.out machine type %04x", machine); + return NULL; + } + if (!fu_common_read_uint32_safe (buf, bufsz, + baseaddr + _PEP_OFFSET_SIZE_OF_HEADERS, + &header_size, G_LITTLE_ENDIAN, error)) + return NULL; + + checksum_offset = baseaddr + _PEP_OFFSET_CHECKSUM; + + /* now, this is odd. sbsigntools seems to think that we're + * skipping the CertificateTable -- but we actually seems to be + * ignoring Debug instead */ + data_dir_debug_offset = baseaddr + _PEP_OFFSET_DEBUG_TABLE_OFFSET; + + } else if (machine == IMAGE_FILE_MACHINE_I386 || + machine == IMAGE_FILE_MACHINE_THUMB) { + + /* a.out header directly follows PE header */ + if (!fu_common_read_uint16_safe (buf, bufsz, + baseaddr + _PEI_HEADER_SIZE, + &machine, G_LITTLE_ENDIAN, error)) + return NULL; + if (machine != 0x010b) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "Invalid a.out machine type %04x", machine); + return NULL; + } + if (!fu_common_read_uint32_safe (buf, bufsz, + baseaddr + _PE_OFFSET_SIZE_OF_HEADERS, + &header_size, G_LITTLE_ENDIAN, error)) + return NULL; + + checksum_offset = baseaddr + _PE_OFFSET_CHECKSUM; + data_dir_debug_offset = baseaddr + _PE_OFFSET_DEBUG_TABLE_OFFSET; + + } else { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "Invalid PE header machine %04x", machine); + return NULL; + } + + /* get sections */ + if (!fu_common_read_uint32_safe (buf, bufsz, + data_dir_debug_offset + sizeof(guint32), + &cert_table_size, G_LITTLE_ENDIAN, error)) + return NULL; + if (!fu_common_read_uint16_safe (buf, bufsz, + baseaddr + _PEI_OFFSET_NUMBER_OF_SECTIONS, + §ions, G_LITTLE_ENDIAN, error)) + return NULL; + g_debug ("number_of_sections: %u", sections); + + /* get header size */ + if (!fu_common_read_uint16_safe (buf, bufsz, + baseaddr + _PEI_OFFSET_OPTIONAL_HEADER_SIZE, + &opthdrsz, G_LITTLE_ENDIAN, error)) + return NULL; + g_debug ("optional_header_size: 0x%x", opthdrsz); + + /* first region: beginning to checksum_offset field */ + checksum_regions = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_efi_image_region_free); + r = fu_efi_image_add_region (checksum_regions, "begin->cksum", 0x0, checksum_offset); + image_bytes += r->size + sizeof(guint32); + + /* second region: end of checksum_offset to certificate table entry */ + r = fu_efi_image_add_region (checksum_regions, "cksum->datadir[DEBUG]", + checksum_offset + sizeof(guint32), + data_dir_debug_offset); + image_bytes += r->size + sizeof(FuEfiImageDataDirEntry); + + /* third region: end of checksum_offset to end of headers */ + r = fu_efi_image_add_region (checksum_regions, "datadir[DEBUG]->headers", + data_dir_debug_offset + sizeof(FuEfiImageDataDirEntry), + header_size); + image_bytes += r->size; + + /* add COFF sections */ + offset_tmp = baseaddr + _PEI_HEADER_SIZE + opthdrsz; + for (guint i = 0; i < sections; i++) { + guint32 file_offset = 0; + guint32 file_size = 0; + gchar name[9] = { '\0' }; + + if (!fu_common_read_uint32_safe (buf, bufsz, + offset_tmp + _SECTION_HEADER_OFFSET_PTR, + &file_offset, G_LITTLE_ENDIAN, error)) + return NULL; + if (!fu_common_read_uint32_safe (buf, bufsz, + offset_tmp + _SECTION_HEADER_OFFSET_SIZE, + &file_size, G_LITTLE_ENDIAN, error)) + return NULL; + if (file_size == 0) + continue; + if (!fu_memcpy_safe ((guint8 *) name, sizeof(name), 0x0, /* dst */ + buf, bufsz, + offset_tmp + _SECTION_HEADER_OFFSET_NAME, /* src */ + sizeof(name) - 1, error)) + return NULL; + r = fu_efi_image_add_region (checksum_regions, name, file_offset, file_offset + file_size); + image_bytes += r->size; + + if (file_offset + r->size > bufsz) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "file-aligned section %s extends beyond end of file", + r->name); + return NULL; + } + offset_tmp += _SECTION_HEADER_SIZE; + } + + /* make sure in order */ + g_ptr_array_sort (checksum_regions, fu_efi_image_region_sort_cb); + + /* for the data at the end of the image */ + if (image_bytes + cert_table_size < bufsz) { + fu_efi_image_add_region (checksum_regions, "endjunk", + image_bytes, bufsz - cert_table_size); + } else if (image_bytes + cert_table_size > bufsz) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "checksum_offset areas outside image size"); + return NULL; + } + + /* calculate the checksum we would find in the dbx */ + for (guint i = 0; i < checksum_regions->len; i++) { + r = g_ptr_array_index (checksum_regions, i); + g_debug ("region %s: 0x%04x -> 0x%04x [0x%04x]", + r->name, + (guint) r->offset, + (guint) (r->offset + r->size - 1), + (guint) r->size); + g_checksum_update (checksum, + (const guchar *) buf + r->offset, + (gssize) r->size); + } + self->checksum = g_strdup (g_checksum_get_string (checksum)); + return g_steal_pointer (&self); +} + +const gchar * +fu_efi_image_get_checksum (FuEfiImage *self) +{ + return self->checksum; +} + +static void +fu_efi_image_finalize (GObject *obj) +{ + FuEfiImage *self = FU_EFI_IMAGE (obj); + g_free (self->checksum); + G_OBJECT_CLASS (fu_efi_image_parent_class)->finalize (obj); +} + +static void +fu_efi_image_class_init (FuEfiImageClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fu_efi_image_finalize; +} + +static void +fu_efi_image_init (FuEfiImage *self) +{ +} diff -Nru fwupd-1.4.5/plugins/uefi-dbx/fu-efi-image.h fwupd-1.5.8/plugins/uefi-dbx/fu-efi-image.h --- fwupd-1.4.5/plugins/uefi-dbx/fu-efi-image.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-dbx/fu-efi-image.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#define FU_TYPE_EFI_IMAGE (fu_efi_image_get_type ()) +G_DECLARE_FINAL_TYPE (FuEfiImage, fu_efi_image, FU, EFI_IMAGE, GObject) + +FuEfiImage *fu_efi_image_new (GBytes *data, + GError **error); +const gchar *fu_efi_image_get_checksum (FuEfiImage *self); diff -Nru fwupd-1.4.5/plugins/uefi-dbx/fu-plugin-uefi-dbx.c fwupd-1.5.8/plugins/uefi-dbx/fu-plugin-uefi-dbx.c --- fwupd-1.4.5/plugins/uefi-dbx/fu-plugin-uefi-dbx.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-dbx/fu-plugin-uefi-dbx.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" +#include "fu-efi-signature-list.h" +#include "fu-uefi-dbx-device.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_METADATA_SOURCE, "uefi_capsule"); + fu_plugin_add_firmware_gtype (plugin, NULL, FU_TYPE_EFI_SIGNATURE_LIST); +} + +gboolean +fu_plugin_coldplug (FuPlugin *plugin, GError **error) +{ + g_autoptr(FuUefiDbxDevice) device = fu_uefi_dbx_device_new (); + if (!fu_device_probe (FU_DEVICE (device), error)) + return FALSE; + if (!fu_device_setup (FU_DEVICE (device), error)) + return FALSE; + fu_plugin_device_add (plugin, FU_DEVICE (device)); + return TRUE; +} diff -Nru fwupd-1.4.5/plugins/uefi-dbx/fu-self-test.c fwupd-1.5.8/plugins/uefi-dbx/fu-self-test.c --- fwupd-1.4.5/plugins/uefi-dbx/fu-self-test.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-dbx/fu-self-test.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" +#include "fu-uefi-dbx-common.h" +#include "fu-efi-image.h" + +static void +fu_efi_image_func (void) +{ + const gchar *ci = g_getenv ("CI_NETWORK"); + const gchar *csum = NULL; + g_autofree gchar *fn = NULL; + g_autoptr(FuEfiImage) img = NULL; + g_autoptr(GBytes) bytes = NULL; + g_autoptr(GError) error = NULL; + + fn = g_test_build_filename (G_TEST_DIST, "tests", "fwupdx64.efi", NULL); + if (!g_file_test (fn, G_FILE_TEST_EXISTS) && ci == NULL) { + g_test_skip ("Missing fwupdx64.efi"); + return; + } + g_assert_nonnull (fn); + bytes = fu_common_get_contents_bytes (fn, &error); + g_assert_no_error (error); + g_assert_nonnull (bytes); + + img = fu_efi_image_new (bytes, &error); + g_assert_no_error (error); + g_assert_nonnull (img); + csum = fu_efi_image_get_checksum (img); + g_assert_cmpstr (csum, ==, "e99707d4378140c01eb3f867240d5cc9e237b126d3db0c3b4bbcd3da1720ddff"); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + /* only critical and error are fatal */ + g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); + g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); + + /* tests go here */ + g_test_add_func ("/uefi-dbx/image", fu_efi_image_func); + return g_test_run (); +} diff -Nru fwupd-1.4.5/plugins/uefi-dbx/fu-uefi-dbx-common.c fwupd-1.5.8/plugins/uefi-dbx/fu-uefi-dbx-common.c --- fwupd-1.4.5/plugins/uefi-dbx/fu-uefi-dbx-common.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-dbx/fu-uefi-dbx-common.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fwupd-error.h" + +#include "fu-common.h" +#include "fu-efi-image.h" +#include "fu-volume.h" + +#include "fu-uefi-dbx-common.h" + +gchar * +fu_uefi_dbx_get_authenticode_hash (const gchar *fn, GError **error) +{ + g_autoptr(FuEfiImage) img = NULL; + g_autoptr(GBytes) bytes = NULL; + g_autoptr(GMappedFile) mmap = NULL; + + g_debug ("getting Authenticode hash of %s", fn); + mmap = g_mapped_file_new (fn, FALSE, error); + if (mmap == NULL) + return NULL; + bytes = g_mapped_file_get_bytes (mmap); + + img = fu_efi_image_new (bytes, error); + if (img == NULL) + return NULL; + g_debug ("SHA256 was %s", fu_efi_image_get_checksum (img)); + return g_strdup (fu_efi_image_get_checksum (img)); +} + +static gboolean +fu_uefi_dbx_signature_list_validate_volume (FuEfiSignatureList *siglist, FuVolume *esp, GError **error) +{ + g_autofree gchar *esp_path = NULL; + g_autoptr(GPtrArray) files = NULL; + + /* get list of files contained in the ESP */ + esp_path = fu_volume_get_mount_point (esp); + if (esp_path == NULL) + return TRUE; + files = fu_common_get_files_recursive (esp_path, error); + if (files == NULL) + return FALSE; + + /* verify each file does not exist in the ESP */ + for (guint i = 0; i < files->len; i++) { + const gchar *fn = g_ptr_array_index (files, i); + g_autofree gchar *checksum = NULL; + g_autoptr(FuFirmwareImage) img = NULL; + g_autoptr(GError) error_local = NULL; + + /* get checksum of file */ + checksum = fu_uefi_dbx_get_authenticode_hash (fn, &error_local); + if (checksum == NULL) { + g_debug ("failed to get checksum for %s: %s", fn, error_local->message); + continue; + } + + /* Authenticode signature is present in dbx! */ + g_debug ("fn=%s, checksum=%s", fn, checksum); + img = fu_firmware_get_image_by_checksum (FU_FIRMWARE (siglist), checksum, NULL); + if (img != NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NEEDS_USER_ACTION, + "%s Authenticode checksum [%s] is present in dbx", + fn, checksum); + return FALSE; + } + } + + /* success */ + return TRUE; +} + +gboolean +fu_uefi_dbx_signature_list_validate (FuEfiSignatureList *siglist, GError **error) +{ + g_autoptr(GPtrArray) volumes = NULL; + volumes = fu_common_get_volumes_by_kind (FU_VOLUME_KIND_ESP, error); + if (volumes == NULL) + return FALSE; + for (guint i = 0; i < volumes->len; i++) { + FuVolume *esp = g_ptr_array_index (volumes, i); + g_autoptr(FuDeviceLocker) locker = NULL; + locker = fu_volume_locker (esp, error); + if (locker == NULL) + return FALSE; + if (!fu_uefi_dbx_signature_list_validate_volume (siglist, esp, error)) + return FALSE; + } + return TRUE; +} diff -Nru fwupd-1.4.5/plugins/uefi-dbx/fu-uefi-dbx-common.h fwupd-1.5.8/plugins/uefi-dbx/fu-uefi-dbx-common.h --- fwupd-1.4.5/plugins/uefi-dbx/fu-uefi-dbx-common.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-dbx/fu-uefi-dbx-common.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#include "fu-efi-signature-list.h" + +gchar *fu_uefi_dbx_get_authenticode_hash (const gchar *fn, + GError **error); +gboolean fu_uefi_dbx_signature_list_validate (FuEfiSignatureList *siglist, + GError **error); diff -Nru fwupd-1.4.5/plugins/uefi-dbx/fu-uefi-dbx-device.c fwupd-1.5.8/plugins/uefi-dbx/fu-uefi-dbx-device.c --- fwupd-1.4.5/plugins/uefi-dbx/fu-uefi-dbx-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-dbx/fu-uefi-dbx-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-efivar.h" + +#include "fu-efi-signature.h" +#include "fu-uefi-dbx-common.h" +#include "fu-uefi-dbx-device.h" + +struct _FuUefiDbxDevice { + FuDevice parent_instance; +}; + +G_DEFINE_TYPE (FuUefiDbxDevice, fu_uefi_dbx_device, FU_TYPE_DEVICE) + +static gboolean +fu_uefi_dbx_device_write_firmware (FuDevice *device, + FuFirmware *firmware, + FwupdInstallFlags install_flags, + GError **error) +{ + const guint8 *buf; + gsize bufsz = 0; + g_autoptr(GBytes) fw = NULL; + + /* get default image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + + /* write entire chunk to efivarfs */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + buf = g_bytes_get_data (fw, &bufsz); + if (!fu_efivar_set_data (FU_EFIVAR_GUID_SECURITY_DATABASE, + "dbx", buf, bufsz, + FU_EFIVAR_ATTR_APPEND_WRITE | + FU_EFIVAR_ATTR_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | + FU_EFIVAR_ATTR_RUNTIME_ACCESS | + FU_EFIVAR_ATTR_BOOTSERVICE_ACCESS | + FU_EFIVAR_ATTR_NON_VOLATILE, + error)) { + return FALSE; + } + + /* success! */ + return TRUE; +} + +static gboolean +fu_uefi_dbx_device_set_version_number (FuDevice *device, GError **error) +{ + g_autoptr(GBytes) dbx_blob = NULL; + g_autoptr(FuFirmware) dbx = fu_efi_signature_list_new (); + + /* use the number of checksums in the dbx as a version number, ignoring + * some owners that do not make sense */ + dbx_blob = fu_efivar_get_data_bytes (FU_EFIVAR_GUID_SECURITY_DATABASE, "dbx", NULL, error); + if (dbx_blob == NULL) + return FALSE; + if (!fu_firmware_parse (dbx, dbx_blob, FWUPD_INSTALL_FLAG_NO_SEARCH, error)) + return FALSE; + fu_device_set_version (device, fu_firmware_get_version (dbx)); + fu_device_set_version_lowest (device, fu_firmware_get_version (dbx)); + return TRUE; +} + +static FuFirmware * +fu_uefi_dbx_prepare_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuFirmware) siglist = fu_efi_signature_list_new (); + + /* parse dbx */ + if (!fu_firmware_parse (siglist, fw, flags, error)) + return NULL; + + /* validate this is safe to apply */ + if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + fu_device_set_status (device, FWUPD_STATUS_DEVICE_VERIFY); + if (!fu_uefi_dbx_signature_list_validate (FU_EFI_SIGNATURE_LIST (siglist), error)) { + g_prefix_error (error, + "Blocked executable in the ESP, " + "ensure grub and shim are up to date: "); + return NULL; + } + } + + /* default blob */ + return fu_firmware_new_from_bytes (fw); +} + +static gboolean +fu_uefi_dbx_device_probe (FuDevice *device, GError **error) +{ + g_autofree gchar *arch_up = NULL; + g_autoptr(FuFirmware) kek = fu_efi_signature_list_new (); + g_autoptr(GBytes) kek_blob = NULL; + g_autoptr(GPtrArray) sigs = NULL; + + /* use each of the certificates in the KEK to generate the GUIDs */ + kek_blob = fu_efivar_get_data_bytes (FU_EFIVAR_GUID_EFI_GLOBAL, "KEK", NULL, error); + if (kek_blob == NULL) + return FALSE; + if (!fu_firmware_parse (kek, kek_blob, FWUPD_INSTALL_FLAG_NO_SEARCH, error)) + return FALSE; + arch_up = g_utf8_strup (EFI_MACHINE_TYPE_NAME, -1); + sigs = fu_firmware_get_images (kek); + for (guint j = 0; j < sigs->len; j++) { + FuEfiSignature *sig = g_ptr_array_index (sigs, j); + g_autofree gchar *checksum = NULL; + g_autofree gchar *checksum_up = NULL; + g_autofree gchar *devid1 = NULL; + g_autofree gchar *devid2 = NULL; + + checksum = fu_firmware_image_get_checksum (FU_FIRMWARE_IMAGE (sig), + G_CHECKSUM_SHA256, + error); + if (checksum == NULL) + return FALSE; + checksum_up = g_utf8_strup (checksum, -1); + devid1 = g_strdup_printf ("UEFI\\CRT_%s", checksum_up); + fu_device_add_instance_id (device, devid1); + devid2 = g_strdup_printf ("UEFI\\CRT_%s&ARCH_%s", + checksum_up, arch_up); + fu_device_add_instance_id (device, devid2); + } + return fu_uefi_dbx_device_set_version_number (device, error); +} + +static void +fu_uefi_dbx_device_init (FuUefiDbxDevice *self) +{ + fu_device_set_physical_id (FU_DEVICE (self), "dbx"); + fu_device_set_name (FU_DEVICE (self), "UEFI dbx"); + fu_device_set_summary (FU_DEVICE (self), "UEFI Revocation Database"); + fu_device_add_vendor_id (FU_DEVICE (self), "UEFI:Linux Foundation"); + fu_device_add_protocol (FU_DEVICE (self), "org.uefi.dbx"); + fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_NUMBER); + fu_device_set_install_duration (FU_DEVICE (self), 1); + fu_device_add_icon (FU_DEVICE (self), "computer"); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NEEDS_REBOOT); + fu_device_add_parent_guid (FU_DEVICE (self), "main-system-firmware"); + if (!fu_common_is_live_media ()) + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); +} + +static void +fu_uefi_dbx_device_class_init (FuUefiDbxDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + klass_device->probe = fu_uefi_dbx_device_probe; + klass_device->write_firmware = fu_uefi_dbx_device_write_firmware; + klass_device->prepare_firmware = fu_uefi_dbx_prepare_firmware; +} + +FuUefiDbxDevice * +fu_uefi_dbx_device_new (void) +{ + FuUefiDbxDevice *self; + self = g_object_new (FU_TYPE_UEFI_DBX_DEVICE, NULL); + return self; +} diff -Nru fwupd-1.4.5/plugins/uefi-dbx/fu-uefi-dbx-device.h fwupd-1.5.8/plugins/uefi-dbx/fu-uefi-dbx-device.h --- fwupd-1.4.5/plugins/uefi-dbx/fu-uefi-dbx-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-dbx/fu-uefi-dbx-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +#define FU_TYPE_UEFI_DBX_DEVICE (fu_uefi_dbx_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuUefiDbxDevice, fu_uefi_dbx_device, FU, UEFI_DBX_DEVICE, FuDevice) + +FuUefiDbxDevice *fu_uefi_dbx_device_new (void); Binary files /tmp/tmpL43cVd/35odgmMgHT/fwupd-1.4.5/plugins/uefi-dbx/fuzzing/example.bin and /tmp/tmpL43cVd/PDLFbnBkMt/fwupd-1.5.8/plugins/uefi-dbx/fuzzing/example.bin differ diff -Nru fwupd-1.4.5/plugins/uefi-dbx/meson.build fwupd-1.5.8/plugins/uefi-dbx/meson.build --- fwupd-1.4.5/plugins/uefi-dbx/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-dbx/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,103 @@ +if get_option('plugin_uefi_capsule') +cargs = ['-DG_LOG_DOMAIN="FuPluginUefiDbx"'] + +shared_module('fu_plugin_uefi_dbx', + fu_hash, + sources : [ + 'fu-plugin-uefi-dbx.c', + 'fu-uefi-dbx-common.c', + 'fu-uefi-dbx-device.c', + 'fu-efi-image.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) + +if get_option('tests') + testdatadirs = environment() + testdatadirs.set('G_TEST_SRCDIR', meson.current_source_dir()) + testdatadirs.set('G_TEST_BUILDDIR', meson.current_build_dir()) + e = executable( + 'uefi-dbx-self-test', + fu_hash, + sources : [ + 'fu-self-test.c', + 'fu-uefi-dbx-common.c', + 'fu-efi-image.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + dependencies : [ + plugin_deps, + ], + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + install : true, + install_dir : installed_test_bindir, + ) + test('uefi-dbx-self-test', e, env : testdatadirs) # added to installed-tests +endif + +dbxtool = executable( + 'dbxtool', + sources : [ + 'fu-dbxtool.c', + 'fu-uefi-dbx-common.c', + 'fu-efi-image.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + dependencies : [ + plugin_deps, + ], + link_with : [ + fwupd, + fwupdplugin, + ], + install : true, + install_dir : bindir, + c_args : cargs, +) + +if get_option('man') + help2man = find_program('help2man') + extra = join_paths(meson.current_source_dir(), 'dbxtool.h2m') + custom_target('dbxtool-man', + input : dbxtool, + output : 'dbxtool.1', + command : [ + help2man, '@INPUT@', + '--no-info', + '--output', '@OUTPUT@', + '--name', 'dbxtool', + '--manual', 'User Commands', + '--version-string', fwupd_version, + '--include', extra, + ], + install : true, + install_dir : join_paths(mandir, 'man1'), + ) +endif +endif diff -Nru fwupd-1.4.5/plugins/uefi-dbx/README.md fwupd-1.5.8/plugins/uefi-dbx/README.md --- fwupd-1.4.5/plugins/uefi-dbx/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-dbx/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,53 @@ +UEFI dbx Support +================ + +Introduction +------------ + +Updating the UEFI revocation database prevents starting EFI binaries with known +security issues, and is typically no longer done from a firmware update due to +the risk of the machine being "bricked" if the bootloader is not updated first. + +This plugin also checks if the UEFI dbx contains all the most recent revoked +checksums. The result will be stored in an security attribute for HSI. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +EFI_SIGNATURE_LIST format. + +See https://www.uefi.org/sites/default/files/resources/UEFI%20Spec%202_6.pdf +for details. + +This plugin supports the following protocol ID: + + * org.uefi.dbx + +GUID Generation +--------------- + +These devices use the GUID constructed of the uppercase SHA256 of the X509 +certificates found in the system KEK and optionally the EFI architecture. e.g. + + * `UEFI\CRT_{sha256}` + * `UEFI\CRT_{sha256}&ARCH_{arch}` + +...where `arch` is typically one of `IA32`, `X64`, `ARM` or `AA64` + +Update Behavior +--------------- + +The firmware is deployed when the machine is in normal runtime mode, but it is +only activated when the system is restarted. + +Vendor ID Security +------------------ + +The vendor ID is hardcoded to `UEFI:Microsoft` for all devices. + + +External interface access +------------------------- +This plugin requires: +* read/write access to `/sys/firmware/efi/efivars` diff -Nru fwupd-1.4.5/plugins/uefi-pk/fu-plugin-uefi-pk.c fwupd-1.5.8/plugins/uefi-pk/fu-plugin-uefi-pk.c --- fwupd-1.4.5/plugins/uefi-pk/fu-plugin-uefi-pk.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-pk/fu-plugin-uefi-pk.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include + +#include "fu-efi-signature.h" +#include "fu-efi-signature-list.h" +#include "fu-efivar.h" +#include "fu-plugin-vfuncs.h" + +struct FuPluginData { + gboolean has_pk_test_key; +}; + +#define FU_UEFI_PK_CHECKSUM_AMI_TEST_KEY "a773113bafaf5129aa83fd0912e95da4fa555f91" + +static void +_gnutls_datum_deinit (gnutls_datum_t *d) +{ + gnutls_free (d->data); + gnutls_free (d); +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +G_DEFINE_AUTOPTR_CLEANUP_FUNC(gnutls_datum_t, _gnutls_datum_deinit) +G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gnutls_x509_crt_t, gnutls_x509_crt_deinit, NULL) +#pragma clang diagnostic pop + +static gboolean +fu_plugin_uefi_pk_parse_buf (FuPlugin *plugin, + const gchar *buf, + gsize bufsz, + GError **error) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + const gchar *needles[] = { + "DO NOT TRUST", + "DO NOT SHIP", + NULL, + }; + for (guint i = 0; needles[i] != NULL; i++) { + if (g_strstr_len (buf, bufsz, needles[i]) != NULL) { + g_debug ("got %s, marking unsafe", buf); + priv->has_pk_test_key = TRUE; + break; + } + } + return TRUE; +} + +static gboolean +fu_plugin_uefi_pk_parse_signature (FuPlugin *plugin, + FuEfiSignature *sig, + GError **error) +{ + gchar buf[1024] = { '\0' }; + gnutls_datum_t d = { 0 }; + gnutls_x509_dn_t dn = { 0x0 }; + gsize bufsz = sizeof(buf); + int rc; + g_auto(gnutls_x509_crt_t) crt = NULL; + g_autoptr(gnutls_datum_t) subject = NULL; + g_autoptr(GBytes) blob = NULL; + + /* create certificate */ + rc = gnutls_x509_crt_init (&crt); + if (rc < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "crt_init: %s [%i]", + gnutls_strerror (rc), rc); + return FALSE; + } + + /* parse certificate */ + blob = fu_firmware_image_get_bytes (FU_FIRMWARE_IMAGE (sig)); + d.size = g_bytes_get_size (blob); + d.data = (unsigned char *) g_bytes_get_data (blob, NULL); + rc = gnutls_x509_crt_import (crt, &d, GNUTLS_X509_FMT_DER); + if (rc < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "crt_import: %s [%i]", + gnutls_strerror (rc), rc); + return FALSE; + } + + /* look in issuer */ + if (gnutls_x509_crt_get_issuer_dn (crt, buf, &bufsz) == GNUTLS_E_SUCCESS) { + if (g_getenv ("FWUPD_UEFI_PK_VERBOSE") != NULL) + g_debug ("PK issuer: %s", buf); + if (!fu_plugin_uefi_pk_parse_buf (plugin, + buf, bufsz, + error)) + return FALSE; + } + + /* look in subject */ + subject = (gnutls_datum_t *) gnutls_malloc (sizeof (gnutls_datum_t)); + if (gnutls_x509_crt_get_subject (crt, &dn) == GNUTLS_E_SUCCESS) { + gnutls_x509_dn_get_str (dn, subject); + if (g_getenv ("FWUPD_UEFI_PK_VERBOSE") != NULL) + g_debug ("PK subject: %s", subject->data); + if (!fu_plugin_uefi_pk_parse_buf (plugin, + (const gchar *) subject->data, + subject->size, + error)) + return FALSE; + } + + /* success, certificate was parsed correctly */ + return TRUE; +} + +gboolean +fu_plugin_coldplug (FuPlugin *plugin, GError **error) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FuFirmwareImage) img = NULL; + g_autoptr(FuFirmware) pk = fu_efi_signature_list_new (); + g_autoptr(GBytes) pk_blob = NULL; + g_autoptr(GPtrArray) sigs = NULL; + + pk_blob = fu_efivar_get_data_bytes (FU_EFIVAR_GUID_EFI_GLOBAL, "PK", NULL, error); + if (pk_blob == NULL) + return FALSE; + if (!fu_firmware_parse (pk, pk_blob, FU_FIRMWARE_FLAG_NONE, error)) { + g_prefix_error (error, "failed to parse PK: "); + return FALSE; + } + + /* by checksum */ + img = fu_firmware_get_image_by_checksum (pk, FU_UEFI_PK_CHECKSUM_AMI_TEST_KEY, NULL); + if (img != NULL) { + g_debug ("detected AMI test certificate"); + priv->has_pk_test_key = TRUE; + } + + /* by text */ + sigs = fu_firmware_get_images (pk); + for (guint i = 0; i < sigs->len; i++) { + FuEfiSignature *sig = g_ptr_array_index (sigs, i); + if (!fu_plugin_uefi_pk_parse_signature (plugin, sig, error)) + return FALSE; + } + + /* success */ + return TRUE; +} + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* create attr */ + attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_UEFI_PK); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin)); + fu_security_attrs_append (attrs, attr); + + /* test key is not secure */ + if (priv->has_pk_test_key) { + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_VALID); +} diff -Nru fwupd-1.4.5/plugins/uefi-pk/meson.build fwupd-1.5.8/plugins/uefi-pk/meson.build --- fwupd-1.4.5/plugins/uefi-pk/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-pk/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,26 @@ +if get_option('plugin_uefi_pk') +cargs = ['-DG_LOG_DOMAIN="FuPluginUefiPk"'] + +shared_module('fu_plugin_uefi_pk', + fu_hash, + sources : [ + 'fu-plugin-uefi-pk.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + gnutls, + ], +) +endif diff -Nru fwupd-1.4.5/plugins/uefi-pk/README.md fwupd-1.5.8/plugins/uefi-pk/README.md --- fwupd-1.4.5/plugins/uefi-pk/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-pk/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,18 @@ +UEFI PK Support +=============== + +Introduction +------------ + +The platform key (PK) specifies the machine owner, typically the OEM +that created the laptop or desktop. + +Several device manufacturers decide to ship the default "AMI Test PK" +platform key instead of a Device Manufacturer specific one. This will +cause an HSI-1 failure. + +External interface access +------------------------- + +This plugin requires: +* read access to `/sys/firmware/efi/efivars` diff -Nru fwupd-1.4.5/plugins/uefi-recovery/fu-plugin-uefi-recovery.c fwupd-1.5.8/plugins/uefi-recovery/fu-plugin-uefi-recovery.c --- fwupd-1.4.5/plugins/uefi-recovery/fu-plugin-uefi-recovery.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-recovery/fu-plugin-uefi-recovery.c 2021-03-31 20:08:32.000000000 +0000 @@ -8,27 +8,14 @@ #include "fu-device-metadata.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" void fu_plugin_init (FuPlugin *plugin) { /* make sure that UEFI plugin is ready to receive devices */ - fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_AFTER, "uefi"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_AFTER, "uefi_capsule"); fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); -} - -gboolean -fu_plugin_startup (FuPlugin *plugin, GError **error) -{ - if (!fu_plugin_has_custom_flag (plugin, "requires-uefi-recovery")) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "not required"); - return FALSE; - } - return TRUE; + fu_plugin_add_flag (plugin, FWUPD_PLUGIN_FLAG_REQUIRE_HWID); } gboolean @@ -56,7 +43,7 @@ dmi_vendor = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_BIOS_VENDOR); if (dmi_vendor != NULL) { g_autofree gchar *vendor_id = g_strdup_printf ("DMI:%s", dmi_vendor); - fu_device_set_vendor_id (device, vendor_id); + fu_device_add_vendor_id (device, vendor_id); } fu_plugin_device_register (plugin, device); diff -Nru fwupd-1.4.5/plugins/uefi-recovery/meson.build fwupd-1.5.8/plugins/uefi-recovery/meson.build --- fwupd-1.4.5/plugins/uefi-recovery/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-recovery/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,4 @@ +if get_option('plugin_uefi_capsule') cargs = ['-DG_LOG_DOMAIN="FuPluginUefiRecovery"'] install_data(['uefi-recovery.quirk'], @@ -27,3 +28,4 @@ plugin_deps, ], ) +endif diff -Nru fwupd-1.4.5/plugins/uefi-recovery/README.md fwupd-1.5.8/plugins/uefi-recovery/README.md --- fwupd-1.4.5/plugins/uefi-recovery/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-recovery/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -20,3 +20,7 @@ ------------------ The vendor ID is set from the BIOS vendor, for example `DMI:LENOVO` + +External interface access +------------------------- +This plugin requires no extra access. diff -Nru fwupd-1.4.5/plugins/uefi-recovery/uefi-recovery.quirk fwupd-1.5.8/plugins/uefi-recovery/uefi-recovery.quirk --- fwupd-1.4.5/plugins/uefi-recovery/uefi-recovery.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/uefi-recovery/uefi-recovery.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,3 @@ # Silicom Minnowboard Turbot MNW2MAX1.X64.0100.R01.1811141729 -[HwId=ea358e00-39f1-55b6-97be-a39225a585e1] -Flags = requires-uefi-recovery +[ea358e00-39f1-55b6-97be-a39225a585e1] +Plugin = uefi_recovery diff -Nru fwupd-1.4.5/plugins/upower/fu-plugin-upower.c fwupd-1.5.8/plugins/upower/fu-plugin-upower.c --- fwupd-1.4.5/plugins/upower/fu-plugin-upower.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/upower/fu-plugin-upower.c 2021-03-31 20:08:32.000000000 +0000 @@ -7,7 +7,6 @@ #include "config.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #define MINIMUM_BATTERY_PERCENTAGE_FALLBACK 10 @@ -149,7 +148,7 @@ /* determine if operating on AC or battery */ if (fu_plugin_upower_check_on_battery (plugin) && - (flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + (flags & FWUPD_INSTALL_FLAG_IGNORE_POWER) == 0) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_AC_POWER_REQUIRED, @@ -160,7 +159,7 @@ /* determine if battery high enough */ if (!fu_plugin_upower_check_percentage_level (plugin) && - (flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + (flags & FWUPD_INSTALL_FLAG_IGNORE_POWER) == 0) { FuPluginData *data = fu_plugin_get_data (plugin); g_set_error (error, FWUPD_ERROR, diff -Nru fwupd-1.4.5/plugins/upower/meson.build fwupd-1.5.8/plugins/upower/meson.build --- fwupd-1.4.5/plugins/upower/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/upower/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,4 @@ +if host_machine.system() == 'linux' cargs = ['-DG_LOG_DOMAIN="FuPluginUpower"'] shared_module('fu_plugin_upower', @@ -25,3 +26,4 @@ install_data(['upower.conf'], install_dir: join_paths(sysconfdir, 'fwupd') ) +endif diff -Nru fwupd-1.4.5/plugins/upower/README.md fwupd-1.5.8/plugins/upower/README.md --- fwupd-1.4.5/plugins/upower/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/upower/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -10,3 +10,7 @@ ------------------ This protocol does not create a device and thus requires no vendor ID set. + +External interface access +------------------------- +This plugin requires access to the dbus interface `org.freedesktop.UPower`. diff -Nru fwupd-1.4.5/plugins/vli/fu-plugin-vli.c fwupd-1.5.8/plugins/vli/fu-plugin-vli.c --- fwupd-1.4.5/plugins/vli/fu-plugin-vli.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/vli/fu-plugin-vli.c 2021-03-31 20:08:32.000000000 +0000 @@ -7,7 +7,6 @@ #include "config.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #include "fu-vli-pd-device.h" #include "fu-vli-pd-firmware.h" @@ -18,8 +17,14 @@ fu_plugin_init (FuPlugin *plugin) { fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); - fu_plugin_add_firmware_gtype (plugin, "vli-usbhub", FU_TYPE_VLI_USBHUB_FIRMWARE); - fu_plugin_add_firmware_gtype (plugin, "vli-pd", FU_TYPE_VLI_PD_FIRMWARE); + fu_plugin_add_firmware_gtype (plugin, NULL, FU_TYPE_VLI_USBHUB_FIRMWARE); + fu_plugin_add_firmware_gtype (plugin, NULL, FU_TYPE_VLI_PD_FIRMWARE); + fu_plugin_add_possible_quirk_key (plugin, "VliDeviceKind"); + fu_plugin_add_possible_quirk_key (plugin, "VliSpiAutoDetect"); + fu_plugin_add_possible_quirk_key (plugin, "VliSpiCmdChipErase"); + fu_plugin_add_possible_quirk_key (plugin, "VliSpiCmdReadId"); + fu_plugin_add_possible_quirk_key (plugin, "VliSpiCmdReadIdSz"); + fu_plugin_add_possible_quirk_key (plugin, "VliSpiCmdSectorErase"); /* register the custom types */ g_type_ensure (FU_TYPE_VLI_USBHUB_DEVICE); diff -Nru fwupd-1.4.5/plugins/vli/fu-vli-common.c fwupd-1.5.8/plugins/vli/fu-vli-common.c --- fwupd-1.4.5/plugins/vli/fu-vli-common.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/vli/fu-vli-common.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2019 VIA Corporation + * Copyright (C) 2017 VIA Corporation * Copyright (C) 2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ @@ -9,38 +9,6 @@ #include "fu-vli-common.h" -guint8 -fu_vli_common_crc8 (const guint8 *buf, gsize bufsz) -{ - guint32 crc = 0; - for (gsize j = bufsz; j > 0; j--) { - crc ^= (*(buf++) << 8); - for (guint32 i = 8; i; i--) { - if (crc & 0x8000) - crc ^= (0x1070 << 3); - crc <<= 1; - } - } - return (guint8) (crc >> 8); -} - -guint16 -fu_vli_common_crc16 (const guint8 *buf, gsize bufsz) -{ - guint16 crc = 0xffff; - for (gsize len = bufsz; len > 0; len--) { - crc = (guint16) (crc ^ (*buf++)); - for (guint8 i = 0; i < 8; i++) { - if (crc & 0x1) { - crc = (crc >> 1) ^ 0xa001; - } else { - crc >>= 1; - } - } - } - return ~crc; -} - const gchar * fu_vli_common_device_kind_to_string (FuVliDeviceKind device_kind) { @@ -94,6 +62,8 @@ return "MSP430"; if (device_kind == FU_VLI_DEVICE_KIND_PS186) return "PS186"; + if (device_kind == FU_VLI_DEVICE_KIND_RTD21XX) + return "RTD21XX"; return NULL; } @@ -150,6 +120,8 @@ return FU_VLI_DEVICE_KIND_MSP430; if (g_strcmp0 (device_kind, "PS186") == 0) return FU_VLI_DEVICE_KIND_PS186; + if (g_strcmp0 (device_kind, "RTD21XX") == 0) + return FU_VLI_DEVICE_KIND_RTD21XX; return FU_VLI_DEVICE_KIND_UNKNOWN; } diff -Nru fwupd-1.4.5/plugins/vli/fu-vli-common.h fwupd-1.5.8/plugins/vli/fu-vli-common.h --- fwupd-1.4.5/plugins/vli/fu-vli-common.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/vli/fu-vli-common.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2019 VIA Corporation + * Copyright (C) 2017 VIA Corporation * Copyright (C) 2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ @@ -36,14 +36,10 @@ FU_VLI_DEVICE_KIND_VL820Q8 = 0xb820, FU_VLI_DEVICE_KIND_MSP430 = 0xf430, /* guessed */ FU_VLI_DEVICE_KIND_PS186 = 0xf186, /* guessed */ + FU_VLI_DEVICE_KIND_RTD21XX = 0xff00, /* guessed */ } FuVliDeviceKind; const gchar *fu_vli_common_device_kind_to_string (FuVliDeviceKind device_kind); FuVliDeviceKind fu_vli_common_device_kind_from_string (const gchar *device_kind); guint32 fu_vli_common_device_kind_get_size (FuVliDeviceKind device_kind); guint32 fu_vli_common_device_kind_get_offset (FuVliDeviceKind device_kind); - -guint8 fu_vli_common_crc8 (const guint8 *buf, - gsize bufsz); -guint16 fu_vli_common_crc16 (const guint8 *buf, - gsize bufsz); diff -Nru fwupd-1.4.5/plugins/vli/fu-vli-device.c fwupd-1.5.8/plugins/vli/fu-vli-device.c --- fwupd-1.4.5/plugins/vli/fu-vli-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/vli/fu-vli-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2019 VIA Corporation + * Copyright (C) 2017 VIA Corporation * Copyright (C) 2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ @@ -218,11 +218,11 @@ return FALSE; } if (!fu_vli_device_spi_sector_erase (self, addr, error)) { - g_prefix_error (error, "->spi_sector_erase failed"); + g_prefix_error (error, "->spi_sector_erase failed: "); return FALSE; } if (!fu_vli_device_spi_wait_finish (self, error)) { - g_prefix_error (error, "->spi_wait_finish failed"); + g_prefix_error (error, "->spi_wait_finish failed: "); return FALSE; } @@ -259,15 +259,17 @@ g_autoptr(GPtrArray) chunks = NULL; /* get data from hardware */ - chunks = fu_chunk_array_new (buf, bufsz, address, 0x0, FU_VLI_DEVICE_TXSIZE); + chunks = fu_chunk_array_mutable_new (buf, bufsz, address, 0x0, FU_VLI_DEVICE_TXSIZE); for (guint i = 0; i < chunks->len; i++) { FuChunk *chk = g_ptr_array_index (chunks, i); if (!fu_vli_device_spi_read_block (self, - chk->address, - (guint8 *) chk->data, - chk->data_sz, + fu_chunk_get_address (chk), + fu_chunk_get_data_out (chk), + fu_chunk_get_data_sz (chk), error)) { - g_prefix_error (error, "SPI data read failed @0x%x: ", chk->address); + g_prefix_error (error, + "SPI data read failed @0x%x: ", + fu_chunk_get_address (chk)); return NULL; } fu_device_set_progress_full (FU_DEVICE (self), @@ -333,11 +335,11 @@ for (guint i = 1; i < chunks->len; i++) { chk = g_ptr_array_index (chunks, i); if (!fu_vli_device_spi_write_block (self, - chk->address + address, - chk->data, - chk->data_sz, + fu_chunk_get_address (chk) + address, + fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk), error)) { - g_prefix_error (error, "failed to write block 0x%x: ", chk->idx); + g_prefix_error (error, "failed to write block 0x%x: ", fu_chunk_get_idx (chk)); return FALSE; } fu_device_set_progress_full (FU_DEVICE (self), @@ -347,9 +349,9 @@ } chk = g_ptr_array_index (chunks, 0); if (!fu_vli_device_spi_write_block (self, - chk->address + address, - chk->data, - chk->data_sz, + fu_chunk_get_address (chk) + address, + fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk), error)) { g_prefix_error (error, "failed to write CRC block: "); return FALSE; @@ -370,7 +372,7 @@ return FALSE; if (!fu_vli_device_spi_chip_erase (self, error)) return FALSE; - g_usleep (4 * G_USEC_PER_SEC); + fu_device_sleep_with_progress (FU_DEVICE (self), 4); /* seconds */ /* verify chip was erased */ for (guint addr = 0; addr < 0x10000; addr += 0x1000) { @@ -400,13 +402,15 @@ g_autoptr(GPtrArray) chunks = fu_chunk_array_new (NULL, sz, addr, 0x0, 0x1000); g_debug ("erasing 0x%x bytes @0x%x", (guint) sz, addr); for (guint i = 0; i < chunks->len; i++) { - FuChunk *chunk = g_ptr_array_index (chunks, i); + FuChunk *chk = g_ptr_array_index (chunks, i); if (g_getenv ("FWUPD_VLI_USBHUB_VERBOSE") != NULL) - g_debug ("erasing @0x%x", chunk->address); - if (!fu_vli_device_spi_erase_sector (FU_VLI_DEVICE (self), chunk->address, error)) { + g_debug ("erasing @0x%x", fu_chunk_get_address (chk)); + if (!fu_vli_device_spi_erase_sector (FU_VLI_DEVICE (self), + fu_chunk_get_address (chk), + error)) { g_prefix_error (error, "failed to erase FW sector @0x%x: ", - chunk->address); + fu_chunk_get_address (chk)); return FALSE; } fu_device_set_progress_full (FU_DEVICE (self), @@ -511,12 +515,24 @@ } if (g_getenv ("FWUPD_VLI_USBHUB_VERBOSE") != NULL) fu_common_dump_raw (G_LOG_DOMAIN, "SpiCmdReadId", buf, sizeof(buf)); - if (priv->spi_cmd_read_id_sz == 4) - priv->flash_id = fu_common_read_uint32 (buf, G_BIG_ENDIAN); - else if (priv->spi_cmd_read_id_sz == 2) - priv->flash_id = fu_common_read_uint16 (buf, G_BIG_ENDIAN); - else if (priv->spi_cmd_read_id_sz == 1) - priv->flash_id = buf[0]; + if (priv->spi_cmd_read_id_sz == 4) { + if (!fu_common_read_uint32_safe (buf, sizeof(buf), 0x0, + &priv->flash_id, + G_BIG_ENDIAN, error)) + return FALSE; + } else if (priv->spi_cmd_read_id_sz == 2) { + guint16 tmp = 0; + if (!fu_common_read_uint16_safe (buf, sizeof(buf), 0x0, + &tmp, G_BIG_ENDIAN, error)) + return FALSE; + priv->flash_id = tmp; + } else if (priv->spi_cmd_read_id_sz == 1) { + guint8 tmp = 0; + if (!fu_common_read_uint8_safe (buf, sizeof(buf), 0x0, + &tmp, error)) + return FALSE; + priv->flash_id = tmp; + } return TRUE; } @@ -539,7 +555,6 @@ g_autofree gchar *devid1 = NULL; g_autofree gchar *devid2 = NULL; g_autofree gchar *flash_id = fu_vli_device_get_flash_id_str (self); - g_debug ("using flash part %s", flash_id); /* load the SPI parameters from quirks */ spi_id = g_strdup_printf ("VLI_USBHUB\\SPI_%s", flash_id); @@ -590,34 +605,34 @@ { FuVliDevice *self = FU_VLI_DEVICE (device); FuVliDevicePrivate *priv = GET_PRIVATE (self); - if (g_strcmp0 (key, "SpiCmdReadId") == 0) { + if (g_strcmp0 (key, "VliSpiCmdReadId") == 0) { priv->spi_cmds[FU_VLI_DEVICE_SPI_REQ_READ_ID] = fu_common_strtoull (value); return TRUE; } - if (g_strcmp0 (key, "SpiCmdReadIdSz") == 0) { + if (g_strcmp0 (key, "VliSpiCmdReadIdSz") == 0) { priv->spi_cmd_read_id_sz = fu_common_strtoull (value); return TRUE; } - if (g_strcmp0 (key, "SpiCmdChipErase") == 0) { + if (g_strcmp0 (key, "VliSpiCmdChipErase") == 0) { priv->spi_cmds[FU_VLI_DEVICE_SPI_REQ_CHIP_ERASE] = fu_common_strtoull (value); return TRUE; } - if (g_strcmp0 (key, "SpiCmdSectorErase") == 0) { + if (g_strcmp0 (key, "VliSpiCmdSectorErase") == 0) { priv->spi_cmds[FU_VLI_DEVICE_SPI_REQ_SECTOR_ERASE] = fu_common_strtoull (value); return TRUE; } - if (g_strcmp0 (key, "SpiAutoDetect") == 0) { + if (g_strcmp0 (key, "VliSpiAutoDetect") == 0) { priv->spi_auto_detect = fu_common_strtoull (value) > 0; return TRUE; } - if (g_strcmp0 (key, "DeviceKind") == 0) { + if (g_strcmp0 (key, "VliDeviceKind") == 0) { FuVliDeviceKind device_kind; device_kind = fu_vli_common_device_kind_from_string (value); if (device_kind == FU_VLI_DEVICE_KIND_UNKNOWN) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - "DeviceKind %s is not supported", + "VliDeviceKind %s is not supported", value); return FALSE; } @@ -632,6 +647,15 @@ } static void +fu_vli_device_report_metadata_pre (FuDevice *device, GHashTable *metadata) +{ + FuVliDevice *self = FU_VLI_DEVICE (device); + g_hash_table_insert (metadata, + g_strdup ("GType"), + g_strdup (G_OBJECT_TYPE_NAME (self))); +} + +static void fu_vli_device_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { FuVliDevice *self = FU_VLI_DEVICE (object); @@ -675,7 +699,6 @@ priv->spi_cmd_read_id_sz = 2; priv->spi_auto_detect = TRUE; fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_ADD_COUNTERPART_GUIDS); - fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NO_GUID_MATCHING); } static void @@ -697,4 +720,5 @@ klass_device->to_string = fu_vli_device_to_string; klass_device->set_quirk_kv = fu_vli_device_set_quirk_kv; klass_device->setup = fu_vli_device_setup; + klass_device->report_metadata_pre = fu_vli_device_report_metadata_pre; } diff -Nru fwupd-1.4.5/plugins/vli/fu-vli-pd-common.c fwupd-1.5.8/plugins/vli/fu-vli-pd-common.c --- fwupd-1.4.5/plugins/vli/fu-vli-pd-common.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/vli/fu-vli-pd-common.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2019 VIA Corporation + * Copyright (C) 2017 VIA Corporation * Copyright (C) 2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ diff -Nru fwupd-1.4.5/plugins/vli/fu-vli-pd-common.h fwupd-1.5.8/plugins/vli/fu-vli-pd-common.h --- fwupd-1.4.5/plugins/vli/fu-vli-pd-common.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/vli/fu-vli-pd-common.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2019 VIA Corporation + * Copyright (C) 2017 VIA Corporation * Copyright (C) 2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ diff -Nru fwupd-1.4.5/plugins/vli/fu-vli-pd-device.c fwupd-1.5.8/plugins/vli/fu-vli-pd-device.c --- fwupd-1.4.5/plugins/vli/fu-vli-pd-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/vli/fu-vli-pd-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2019 VIA Corporation + * Copyright (C) 2015 VIA Corporation * Copyright (C) 2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ @@ -7,6 +7,7 @@ #include "config.h" +#include "fu-common.h" #include "fu-firmware.h" #include "fu-vli-pd-device.h" @@ -271,7 +272,9 @@ g_prefix_error (error, "failed to get version: "); return FALSE; } - version_raw = fu_common_read_uint32 (verbuf, G_BIG_ENDIAN); + if (!fu_common_read_uint32_safe (verbuf, sizeof(verbuf), 0x0, + &version_raw, G_BIG_ENDIAN, error)) + return FALSE; fu_device_set_version_raw (FU_DEVICE (self), version_raw); version_str = fu_common_version_from_uint32 (version_raw, FWUPD_VERSION_FORMAT_QUAD); fu_device_set_version (FU_DEVICE (self), version_str); @@ -344,7 +347,6 @@ } /* check is compatible with firmware */ - fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); if (!fu_firmware_parse (firmware, fw, flags, error)) return NULL; device_kind = fu_vli_pd_firmware_get_kind (FU_VLI_PD_FIRMWARE (firmware)); @@ -363,18 +365,23 @@ return g_steal_pointer (&firmware); } -static FuFirmware * -fu_vli_pd_device_read_firmware (FuDevice *device, GError **error) +static GBytes * +fu_vli_pd_device_dump_firmware (FuDevice *device, GError **error) { FuVliPdDevice *self = FU_VLI_PD_DEVICE (device); - g_autoptr(GBytes) fw = NULL; - fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_VERIFY); - fw = fu_vli_device_spi_read (FU_VLI_DEVICE (self), 0x0, - fu_device_get_firmware_size_max (device), - error); - if (fw == NULL) + g_autoptr(FuDeviceLocker) locker = NULL; + + /* require detach -> attach */ + locker = fu_device_locker_new_full (device, + (FuDeviceLockerFunc) fu_device_detach, + (FuDeviceLockerFunc) fu_device_attach, + error); + if (locker == NULL) return NULL; - return fu_firmware_new_from_bytes (fw); + fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_READ); + return fu_vli_device_spi_read (FU_VLI_DEVICE (self), 0x0, + fu_device_get_firmware_size_max (device), + error); } static gboolean @@ -420,7 +427,7 @@ g_prefix_error (error, "failed to read file CRC: "); return FALSE; } - crc_actual = fu_vli_common_crc16 (sbuf, sbufsz - 2); + crc_actual = fu_common_crc16 (sbuf, sbufsz - 2); fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_WRITE); /* update fw2 first if fw1 correct */ @@ -671,7 +678,7 @@ fu_vli_pd_device_init (FuVliPdDevice *self) { fu_device_add_icon (FU_DEVICE (self), "audio-card"); - fu_device_set_protocol (FU_DEVICE (self), "com.vli.pd"); + fu_device_add_protocol (FU_DEVICE (self), "com.vli.pd"); fu_device_set_summary (FU_DEVICE (self), "USB PD"); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE); @@ -689,7 +696,7 @@ { FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); FuVliDeviceClass *klass_vli_device = FU_VLI_DEVICE_CLASS (klass); - klass_device->read_firmware = fu_vli_pd_device_read_firmware; + klass_device->dump_firmware = fu_vli_pd_device_dump_firmware; klass_device->write_firmware = fu_vli_pd_device_write_firmware; klass_device->prepare_firmware = fu_vli_pd_device_prepare_firmware; klass_device->attach = fu_vli_pd_device_attach; diff -Nru fwupd-1.4.5/plugins/vli/fu-vli-pd-firmware.c fwupd-1.5.8/plugins/vli/fu-vli-pd-firmware.c --- fwupd-1.4.5/plugins/vli/fu-vli-pd-firmware.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/vli/fu-vli-pd-firmware.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2019 VIA Corporation + * Copyright (C) 2017 VIA Corporation * Copyright (C) 2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ @@ -7,6 +7,8 @@ #include "config.h" +#include "fu-common.h" + #include "fu-vli-pd-common.h" #include "fu-vli-pd-firmware.h" @@ -46,6 +48,8 @@ return TRUE; if (GUINT16_FROM_LE (self->hdr.vid) == 0x17EF) return TRUE; + if (GUINT16_FROM_LE (self->hdr.vid) == 0x2D01) + return TRUE; return FALSE; } @@ -115,6 +119,7 @@ } fwver_str = fu_common_version_from_uint32 (fwver, FWUPD_VERSION_FORMAT_QUAD); fu_firmware_set_version (firmware, fwver_str); + fu_firmware_set_version_raw (firmware, fwver); /* check size */ if (bufsz != fu_vli_common_device_kind_get_size (self->device_kind)) { @@ -128,7 +133,7 @@ } /* check CRC */ - if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + if ((flags & FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM) == 0) { guint16 crc_actual; guint16 crc_file = 0x0; if (!fu_common_read_uint16_safe (buf, bufsz, bufsz - 2, &crc_file, @@ -136,7 +141,7 @@ g_prefix_error (error, "failed to read file CRC: "); return FALSE; } - crc_actual = fu_vli_common_crc16 (buf, bufsz - 2); + crc_actual = fu_common_crc16 (buf, bufsz - 2); if (crc_actual != crc_file) { g_set_error (error, FWUPD_ERROR, @@ -155,6 +160,7 @@ static void fu_vli_pd_firmware_init (FuVliPdFirmware *self) { + fu_firmware_add_flag (FU_FIRMWARE (self), FU_FIRMWARE_FLAG_HAS_CHECKSUM); } static void diff -Nru fwupd-1.4.5/plugins/vli/fu-vli-pd-firmware.h fwupd-1.5.8/plugins/vli/fu-vli-pd-firmware.h --- fwupd-1.4.5/plugins/vli/fu-vli-pd-firmware.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/vli/fu-vli-pd-firmware.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2019 VIA Corporation + * Copyright (C) 2017 VIA Corporation * Copyright (C) 2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ diff -Nru fwupd-1.4.5/plugins/vli/fu-vli-pd-parade-device.c fwupd-1.5.8/plugins/vli/fu-vli-pd-parade-device.c --- fwupd-1.4.5/plugins/vli/fu-vli-pd-parade-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/vli/fu-vli-pd-parade-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2019 VIA Corporation + * Copyright (C) 2015 VIA Corporation * Copyright (C) 2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ @@ -410,13 +410,6 @@ return TRUE; } -static GBytes * -_g_bytes_new_sized (gsize sz) -{ - guint8 *buf = g_malloc0 (sz); - return g_bytes_new_take (buf, sz); -} - static gboolean fu_vli_pd_parade_device_block_read (FuVliPdParadeDevice *self, guint8 block_idx, @@ -444,13 +437,14 @@ { FuVliPdParadeDevice *self = FU_VLI_PD_PARADE_DEVICE (device); FuVliPdDevice *parent = FU_VLI_PD_DEVICE (fu_device_get_parent (device)); + FuChunk *chk0; guint8 buf[0x20]; guint block_idx_tmp; g_autoptr(FuDeviceLocker) locker = NULL; + g_autoptr(GByteArray) buf_verify = NULL; g_autoptr(GBytes) fw = NULL; g_autoptr(GBytes) fw_verify = NULL; g_autoptr(GPtrArray) blocks = NULL; - g_autoptr(GPtrArray) blocks_verify = NULL; /* simple image */ fw = fu_firmware_get_image_default_bytes (firmware, error); @@ -476,8 +470,8 @@ return FALSE; blocks = fu_chunk_array_new_from_bytes (fw, 0x0, 0x0, 0x10000); for (guint i = 1; i < blocks->len; i++) { - FuChunk *block = g_ptr_array_index (blocks, i); - if (!fu_vli_pd_parade_device_block_erase (self, block->idx, error)) + FuChunk *chk = g_ptr_array_index (blocks, i); + if (!fu_vli_pd_parade_device_block_erase (self, fu_chunk_get_idx (chk), error)) return FALSE; fu_device_set_progress_full (FU_DEVICE (self), i, blocks->len); } @@ -494,28 +488,37 @@ /* write blocks */ fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_WRITE); for (guint i = 1; i < blocks->len; i++) { - FuChunk *block = g_ptr_array_index (blocks, i); - if (!fu_vli_pd_parade_device_block_write (self, block->idx, block->data, error)) + FuChunk *chk = g_ptr_array_index (blocks, i); + if (!fu_vli_pd_parade_device_block_write (self, fu_chunk_get_idx (chk), fu_chunk_get_data (chk), error)) return FALSE; fu_device_set_progress_full (FU_DEVICE (self), i, blocks->len); } if (!fu_vli_pd_parade_device_write_disable (self, error)) return FALSE; - /* verify SPI ROM */ + /* add the new boot config into the verify buffer */ + buf_verify = g_byte_array_sized_new (g_bytes_get_size (fw)); + chk0 = g_ptr_array_index (blocks, 0); + g_byte_array_append (buf_verify, + fu_chunk_get_data (chk0), + fu_chunk_get_data_sz (chk0)); + + /* verify SPI ROM, ignoring the boot config */ fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_VERIFY); - fw_verify = _g_bytes_new_sized (g_bytes_get_size (fw)); - blocks_verify = fu_chunk_array_new_from_bytes (fw_verify, 0x0, 0x0, 0x10000); - for (guint i = 1; i < blocks_verify->len; i++) { - FuChunk *block = g_ptr_array_index (blocks_verify, i); + for (guint i = 1; i < blocks->len; i++) { + FuChunk *chk = g_ptr_array_index (blocks, i); + gsize bufsz = fu_chunk_get_data_sz (chk); + g_autofree guint8 *vbuf = g_malloc0 (bufsz); if (!fu_vli_pd_parade_device_block_read (self, - block->idx, - (guint8 *) block->data, - block->data_sz, + fu_chunk_get_idx (chk), + vbuf, + bufsz, error)) return FALSE; + g_byte_array_append (buf_verify, vbuf, bufsz); fu_device_set_progress_full (FU_DEVICE (self), i, blocks->len); } + fw_verify = g_byte_array_free_to_bytes (g_steal_pointer (&buf_verify)); if (!fu_common_bytes_compare (fw, fw_verify, error)) return FALSE; @@ -579,13 +582,13 @@ return TRUE; } -static FuFirmware * -fu_vli_pd_parade_device_read_firmware (FuDevice *device, GError **error) +static GBytes * +fu_vli_pd_parade_device_dump_firmware (FuDevice *device, GError **error) { FuVliPdDevice *parent = FU_VLI_PD_DEVICE (fu_device_get_parent (device)); FuVliPdParadeDevice *self = FU_VLI_PD_PARADE_DEVICE (device); g_autoptr(FuDeviceLocker) locker = NULL; - g_autoptr(GBytes) fw = NULL; + g_autoptr(GByteArray) fw = NULL; g_autoptr(GPtrArray) blocks = NULL; /* open device */ @@ -599,38 +602,18 @@ /* read */ fu_device_set_status (FU_DEVICE (device), FWUPD_STATUS_DEVICE_VERIFY); - fw = _g_bytes_new_sized (fu_device_get_firmware_size_max (device)); - blocks = fu_chunk_array_new_from_bytes (fw, 0x0, 0x0, 0x10000); + fu_byte_array_set_size (fw, fu_device_get_firmware_size_max (device)); + blocks = fu_chunk_array_mutable_new (fw->data, fw->len, 0x0, 0x0, 0x10000); for (guint i = 0; i < blocks->len; i++) { - FuChunk *block = g_ptr_array_index (blocks, i); + FuChunk *chk = g_ptr_array_index (blocks, i); if (!fu_vli_pd_parade_device_block_read (self, - block->idx, - (guint8 *) block->data, - block->data_sz, + fu_chunk_get_idx (chk), + fu_chunk_get_data_out (chk), + fu_chunk_get_data_sz (chk), error)) return NULL; } - return fu_firmware_new_from_bytes (fw); -} - - -static FuFirmware * -fu_vli_pd_parade_device_prepare_firmware (FuDevice *device, - GBytes *fw, - FwupdInstallFlags flags, - GError **error) -{ - /* check size */ - if (g_bytes_get_size (fw) < fu_device_get_firmware_size_min (device)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "firmware too small, got 0x%x, expected >= 0x%x", - (guint) g_bytes_get_size (fw), - (guint) fu_device_get_firmware_size_min (device)); - return NULL; - } - return fu_firmware_new_from_bytes (fw); + return g_byte_array_free_to_bytes (g_steal_pointer (&fw)); } static gboolean @@ -664,7 +647,7 @@ fu_device_add_icon (FU_DEVICE (self), "video-display"); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_TRIPLET); - fu_device_set_protocol (FU_DEVICE (self), "com.vli.i2c"); + fu_device_add_protocol (FU_DEVICE (self), "com.vli.i2c"); fu_device_set_install_duration (FU_DEVICE (self), 15); /* seconds */ fu_device_set_logical_id (FU_DEVICE (self), "PS186"); fu_device_set_summary (FU_DEVICE (self), "DisplayPort 1.4a to HDMI 2.0b Protocol Converter"); @@ -677,8 +660,7 @@ FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); klass_device->to_string = fu_vli_pd_parade_device_to_string; klass_device->probe = fu_vli_pd_parade_device_probe; - klass_device->read_firmware = fu_vli_pd_parade_device_read_firmware; - klass_device->prepare_firmware = fu_vli_pd_parade_device_prepare_firmware; + klass_device->dump_firmware = fu_vli_pd_parade_device_dump_firmware; klass_device->write_firmware = fu_vli_pd_parade_device_write_firmware; } diff -Nru fwupd-1.4.5/plugins/vli/fu-vli-usbhub-common.c fwupd-1.5.8/plugins/vli/fu-vli-usbhub-common.c --- fwupd-1.4.5/plugins/vli/fu-vli-usbhub-common.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/vli/fu-vli-usbhub-common.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2019 VIA Corporation + * Copyright (C) 2017 VIA Corporation * Copyright (C) 2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ @@ -12,7 +12,7 @@ guint8 fu_vli_usbhub_header_crc8 (FuVliUsbhubHeader *hdr) { - return fu_vli_common_crc8 ((const guint8 *) hdr, sizeof(*hdr) - 1); + return ~fu_common_crc8 ((const guint8 *) hdr, sizeof(*hdr) - 1); } void diff -Nru fwupd-1.4.5/plugins/vli/fu-vli-usbhub-common.h fwupd-1.5.8/plugins/vli/fu-vli-usbhub-common.h --- fwupd-1.4.5/plugins/vli/fu-vli-usbhub-common.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/vli/fu-vli-usbhub-common.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2019 VIA Corporation + * Copyright (C) 2017 VIA Corporation * Copyright (C) 2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ diff -Nru fwupd-1.4.5/plugins/vli/fu-vli-usbhub-device.c fwupd-1.5.8/plugins/vli/fu-vli-usbhub-device.c --- fwupd-1.4.5/plugins/vli/fu-vli-usbhub-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/vli/fu-vli-usbhub-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2019 VIA Corporation + * Copyright (C) 2017 VIA Corporation * Copyright (C) 2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ @@ -16,6 +16,7 @@ #include "fu-vli-usbhub-device.h" #include "fu-vli-usbhub-firmware.h" #include "fu-vli-usbhub-msp430-device.h" +#include "fu-vli-usbhub-rtd21xx-device.h" #include "fu-vli-usbhub-pd-device.h" struct _FuVliUsbhubDevice @@ -418,14 +419,16 @@ g_prefix_error (error, "Read_820Q7Q8 failed: "); return FALSE; } - g_debug ("chipver = 0x%02x", chipver); - g_debug ("chipver2 = 0x%02x", chipver2); - g_debug ("b811P812 = 0x%02x", b811P812); - g_debug ("chipid1 = 0x%02x", chipid1); - g_debug ("chipid2 = 0x%02x", chipid2); - g_debug ("chipid12 = 0x%02x", chipid12); - g_debug ("chipid22 = 0x%02x", chipid22); - g_debug ("b820Q7Q8 = 0x%02x", b820Q7Q8); + if (g_getenv ("FWUPD_VLI_USBHUB_VERBOSE") != NULL) { + g_debug ("chipver = 0x%02x", chipver); + g_debug ("chipver2 = 0x%02x", chipver2); + g_debug ("b811P812 = 0x%02x", b811P812); + g_debug ("chipid1 = 0x%02x", chipid1); + g_debug ("chipid2 = 0x%02x", chipid2); + g_debug ("chipid12 = 0x%02x", chipid12); + g_debug ("chipid22 = 0x%02x", chipid22); + g_debug ("b820Q7Q8 = 0x%02x", b820Q7Q8); + } if (chipid2 == 0x35 && chipid1 == 0x07) { fu_vli_device_set_kind (FU_VLI_DEVICE (self), FU_VLI_DEVICE_KIND_VL210); @@ -495,43 +498,47 @@ static gboolean fu_vli_usbhub_device_pd_setup (FuVliUsbhubDevice *self, GError **error) { - FuVliPdHdr hdr = { 0x0 }; g_autoptr(FuDevice) dev = NULL; g_autoptr(GError) error_local = NULL; - /* legacy location */ - if (!fu_vli_device_spi_read_block (FU_VLI_DEVICE (self), - VLI_USBHUB_FLASHMAP_ADDR_PD_LEGACY + - VLI_USBHUB_PD_FLASHMAP_ADDR_LEGACY, - (guint8 *) &hdr, sizeof(hdr), error)) { - g_prefix_error (error, "failed to read legacy PD header"); + /* add child */ + dev = fu_vli_usbhub_pd_device_new (self); + if (!fu_device_probe (dev, error)) return FALSE; - } - - /* new location */ - if (GUINT16_FROM_LE (hdr.vid) != 0x2109) { - g_debug ("PD VID was 0x%04x trying new location", - GUINT16_FROM_LE (hdr.vid)); - if (!fu_vli_device_spi_read_block (FU_VLI_DEVICE (self), - VLI_USBHUB_FLASHMAP_ADDR_PD + - VLI_USBHUB_PD_FLASHMAP_ADDR, - (guint8 *) &hdr, sizeof(hdr), error)) { - g_prefix_error (error, "failed to read PD header"); - return FALSE; + if (!fu_device_setup (dev, &error_local)) { + if (g_error_matches (error_local, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND)) { + g_debug ("%s", error_local->message); + } else { + g_warning ("cannot create PD device: %s", + error_local->message); } - } - - /* just empty space */ - if (hdr.fwver == G_MAXUINT32) { - g_debug ("no PD device header found"); return TRUE; } + fu_device_add_child (FU_DEVICE (self), dev); + return TRUE; +} + +static gboolean +fu_vli_usbhub_device_msp430_setup (FuVliUsbhubDevice *self, GError **error) +{ + g_autoptr(FuDevice) dev = NULL; + g_autoptr(GError) error_local = NULL; /* add child */ - dev = fu_vli_usbhub_pd_device_new (&hdr); - fu_device_set_quirks (dev, fu_device_get_quirks (FU_DEVICE (self))); - if (!fu_device_probe (dev, &error_local)) { - g_warning ("cannot create PD device: %s", error_local->message); + dev = fu_vli_usbhub_msp430_device_new (self); + if (!fu_device_probe (dev, error)) + return FALSE; + if (!fu_device_setup (dev, &error_local)) { + if (g_error_matches (error_local, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND)) { + g_debug ("%s", error_local->message); + } else { + g_warning ("cannot create MSP430 I²C device: %s", + error_local->message); + } return TRUE; } fu_device_add_child (FU_DEVICE (self), dev); @@ -539,13 +546,13 @@ } static gboolean -fu_vli_usbhub_device_msp430_setup (FuVliUsbhubDevice *self, GError **error) +fu_vli_usbhub_device_rtd21xx_setup (FuVliUsbhubDevice *self, GError **error) { g_autoptr(FuDevice) dev = NULL; g_autoptr(GError) error_local = NULL; /* add child */ - dev = fu_vli_usbhub_msp430_device_new (self); + dev = fu_vli_usbhub_rtd21xx_device_new (self); if (!fu_device_probe (dev, error)) return FALSE; if (!fu_device_setup (dev, &error_local)) { @@ -554,7 +561,7 @@ FWUPD_ERROR_NOT_FOUND)) { g_debug ("%s", error_local->message); } else { - g_warning ("cannot create I²C device: %s", + g_warning ("cannot create RTD21XX I²C device: %s", error_local->message); } return TRUE; @@ -593,7 +600,7 @@ if (!fu_vli_device_spi_read_block (FU_VLI_DEVICE (self), VLI_USBHUB_FLASHMAP_ADDR_HD1, (guint8 *) &self->hd1_hdr, sizeof(self->hd1_hdr), error)) { - g_prefix_error (error, "failed to read HD1 header"); + g_prefix_error (error, "failed to read HD1 header: "); return FALSE; } @@ -621,7 +628,7 @@ G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "hardware is not supported, dev_id=0x%x", - GUINT16_FROM_BE(self->hd1_hdr.dev_id)); + (guint) GUINT16_FROM_BE(self->hd1_hdr.dev_id)); return FALSE; } @@ -630,7 +637,7 @@ if (!fu_vli_device_spi_read_block (FU_VLI_DEVICE (self), VLI_USBHUB_FLASHMAP_ADDR_HD2, (guint8 *) &self->hd2_hdr, sizeof(self->hd2_hdr), error)) { - g_prefix_error (error, "failed to read HD2 header"); + g_prefix_error (error, "failed to read HD2 header: "); return FALSE; } } @@ -647,6 +654,10 @@ if (!fu_vli_usbhub_device_msp430_setup (self, error)) return FALSE; } + if (fu_device_has_custom_flag (FU_DEVICE (self), "has-rtd21xx")) { + if (!fu_vli_usbhub_device_rtd21xx_setup (self, error)) + return FALSE; + } /* success */ return TRUE; @@ -663,28 +674,7 @@ guint16 device_id; g_autoptr(FuFirmware) firmware = fu_vli_usbhub_firmware_new (); - /* check size */ - if (g_bytes_get_size (fw) < fu_device_get_firmware_size_min (device)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "firmware too small, got 0x%x, expected >= 0x%x", - (guint) g_bytes_get_size (fw), - (guint) fu_device_get_firmware_size_min (device)); - return NULL; - } - if (g_bytes_get_size (fw) > fu_device_get_firmware_size_max (device)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "firmware too large, got 0x%x, expected <= 0x%x", - (guint) g_bytes_get_size (fw), - (guint) fu_device_get_firmware_size_max (device)); - return NULL; - } - /* check is compatible with firmware */ - fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); if (!fu_firmware_parse (firmware, fw, flags, error)) return NULL; device_kind = fu_vli_usbhub_firmware_get_device_kind (FU_VLI_USBHUB_FIRMWARE (firmware)); @@ -703,7 +693,8 @@ FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "firmware incompatible, got 0x%04x, expected 0x%04x", - device_id, GUINT16_FROM_BE(self->hd1_hdr.dev_id)); + device_id, + (guint) GUINT16_FROM_BE(self->hd1_hdr.dev_id)); return NULL; } @@ -754,7 +745,7 @@ fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_ERASE); for (guint32 addr = 0; addr < bufsz; addr += 0x1000) { if (!fu_vli_device_spi_erase_sector (FU_VLI_DEVICE (self), addr, error)) { - g_prefix_error (error, "failed to erase sector @0x%x", addr); + g_prefix_error (error, "failed to erase sector @0x%x: ", addr); return FALSE; } fu_device_set_progress_full (FU_DEVICE (self), (gsize) addr, bufsz); @@ -858,7 +849,7 @@ (guint8 *) &self->hd1_hdr, sizeof(hdr), error)) { g_prefix_error (error, - "failed to read root header from 0x%x", + "failed to read root header from 0x%x: ", (guint) VLI_USBHUB_FLASHMAP_ADDR_HD1_BACKUP); return FALSE; } @@ -939,18 +930,14 @@ return TRUE; } -static FuFirmware * -fu_vli_usbhub_device_read_firmware (FuDevice *device, GError **error) +static GBytes * +fu_vli_usbhub_device_dump_firmware (FuDevice *device, GError **error) { FuVliUsbhubDevice *self = FU_VLI_USBHUB_DEVICE (device); - g_autoptr(GBytes) fw = NULL; - fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_VERIFY); - fw = fu_vli_device_spi_read (FU_VLI_DEVICE (self), 0x0, - fu_device_get_firmware_size_max (device), - error); - if (fw == NULL) - return NULL; - return fu_firmware_new_from_bytes (fw); + fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_READ); + return fu_vli_device_spi_read (FU_VLI_DEVICE (self), 0x0, + fu_device_get_firmware_size_max (device), + error); } static gboolean @@ -988,7 +975,7 @@ fu_vli_usbhub_device_init (FuVliUsbhubDevice *self) { fu_device_add_icon (FU_DEVICE (self), "audio-card"); - fu_device_set_protocol (FU_DEVICE (self), "com.vli.usbhub"); + fu_device_add_protocol (FU_DEVICE (self), "com.vli.usbhub"); fu_device_set_remove_delay (FU_DEVICE (self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); } @@ -998,7 +985,7 @@ FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); FuVliDeviceClass *klass_vli_device = FU_VLI_DEVICE_CLASS (klass); klass_device->probe = fu_vli_usbhub_device_probe; - klass_device->read_firmware = fu_vli_usbhub_device_read_firmware; + klass_device->dump_firmware = fu_vli_usbhub_device_dump_firmware; klass_device->write_firmware = fu_vli_usbhub_device_write_firmware; klass_device->prepare_firmware = fu_vli_usbhub_device_prepare_firmware; klass_device->attach = fu_vli_usbhub_device_attach; diff -Nru fwupd-1.4.5/plugins/vli/fu-vli-usbhub-firmware.c fwupd-1.5.8/plugins/vli/fu-vli-usbhub-firmware.c --- fwupd-1.4.5/plugins/vli/fu-vli-usbhub-firmware.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/vli/fu-vli-usbhub-firmware.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2019 VIA Corporation + * Copyright (C) 2017 VIA Corporation * Copyright (C) 2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ @@ -115,6 +115,7 @@ g_autofree gchar *version_str = NULL; version_str = fu_common_version_from_uint16 (version, FWUPD_VERSION_FORMAT_BCD); fu_firmware_set_version (firmware, version_str); + fu_firmware_set_version_raw (firmware, version); } /* get device type from firmware image */ diff -Nru fwupd-1.4.5/plugins/vli/fu-vli-usbhub-firmware.h fwupd-1.5.8/plugins/vli/fu-vli-usbhub-firmware.h --- fwupd-1.4.5/plugins/vli/fu-vli-usbhub-firmware.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/vli/fu-vli-usbhub-firmware.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2019 VIA Corporation + * Copyright (C) 2017 VIA Corporation * Copyright (C) 2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ diff -Nru fwupd-1.4.5/plugins/vli/fu-vli-usbhub-i2c-common.c fwupd-1.5.8/plugins/vli/fu-vli-usbhub-i2c-common.c --- fwupd-1.4.5/plugins/vli/fu-vli-usbhub-i2c-common.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/vli/fu-vli-usbhub-i2c-common.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2019 VIA Corporation + * Copyright (C) 2017 VIA Corporation * Copyright (C) 2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ diff -Nru fwupd-1.4.5/plugins/vli/fu-vli-usbhub-i2c-common.h fwupd-1.5.8/plugins/vli/fu-vli-usbhub-i2c-common.h --- fwupd-1.4.5/plugins/vli/fu-vli-usbhub-i2c-common.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/vli/fu-vli-usbhub-i2c-common.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2019 VIA Corporation + * Copyright (C) 2017 VIA Corporation * Copyright (C) 2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ diff -Nru fwupd-1.4.5/plugins/vli/fu-vli-usbhub-msp430-device.c fwupd-1.5.8/plugins/vli/fu-vli-usbhub-msp430-device.c --- fwupd-1.4.5/plugins/vli/fu-vli-usbhub-msp430-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/vli/fu-vli-usbhub-msp430-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,6 +1,6 @@ /* - * Copyright (C) 2017-2019 VIA Corporation - * Copyright (C) 2019-2020 Richard Hughes + * Copyright (C) 2017 VIA Corporation + * Copyright (C) 2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -149,12 +149,11 @@ /* avoid power instability by waiting T1 */ fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); - fu_device_set_progress (device, 0); - g_usleep (G_USEC_PER_SEC); + fu_device_sleep_with_progress (device, 1); /* seconds */ /* check the device came back */ if (!fu_vli_usbhub_device_i2c_read_status (parent, &status, error)) { - g_prefix_error (error, "device did not come back after detach"); + g_prefix_error (error, "device did not come back after detach: "); return FALSE; } return fu_vli_usbhub_i2c_check_status (status, error); @@ -167,7 +166,6 @@ GError **error) { g_autoptr(FuFirmware) firmware = fu_ihex_firmware_new (); - fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); if (!fu_firmware_tokenize (firmware, fw, flags, error)) return NULL; return g_steal_pointer (&firmware); @@ -232,7 +230,6 @@ FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (device)); GPtrArray *records = fu_ihex_firmware_get_records (FU_IHEX_FIRMWARE (firmware)); g_autoptr(FuDeviceLocker) locker = NULL; - g_autoptr(FuDevice) root = NULL; /* open device */ locker = fu_device_locker_new (parent, error); @@ -246,28 +243,8 @@ FuVliUsbhubDeviceRequest req = { 0x0 }; const gchar *line = rcd->buf->str; - /* check there's enough data for the smallest possible record */ - if (rcd->buf->len < 11) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "line %u is incomplete, length %u", - rcd->ln, (guint) rcd->buf->len); - return FALSE; - } - - /* check starting token */ - if (line[0] != ':') { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "invalid starting token on line %u: %s", - rcd->ln, line); - return FALSE; - } - /* length, 16-bit address, type */ - req.len = fu_firmware_strparse_uint8 (line + 1); + req.len = rcd->byte_cnt; if (req.len >= sizeof(req.buf) - 7) { g_set_error (error, FWUPD_ERROR, @@ -276,25 +253,34 @@ (guint) sizeof(req.buf)); return FALSE; } - if (9 + (guint) req.len * 2 > (guint) rcd->buf->len) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "line %u malformed", rcd->ln); - return FALSE; - } /* write each record directly to the hardware */ req.buf[0] = I2C_ADDR_WRITE; req.buf[1] = I2C_CMD_WRITE; req.buf[2] = 0x3a; /* ':' */ req.buf[3] = req.len; - req.buf[4] = fu_firmware_strparse_uint8 (line + 3); - req.buf[5] = fu_firmware_strparse_uint8 (line + 5); - req.buf[6] = fu_firmware_strparse_uint8 (line + 7); - for (guint8 i = 0; i < req.len; i++) - req.buf[7 + i] = fu_firmware_strparse_uint8 (line + 9 + (i * 2)); - req.buf[7 + req.len] = fu_firmware_strparse_uint8 (line + 9+ (req.len * 2)); + if (!fu_firmware_strparse_uint8_safe (line, rcd->buf->len, + 3, &req.buf[4], error)) + return FALSE; + if (!fu_firmware_strparse_uint8_safe (line, rcd->buf->len, + 5, &req.buf[5], error)) + return FALSE; + if (!fu_firmware_strparse_uint8_safe (line, rcd->buf->len, + 7, &req.buf[6], error)) + return FALSE; + for (guint8 i = 0; i < req.len; i++) { + if (!fu_firmware_strparse_uint8_safe (line, + rcd->buf->len, 9 + (i * 2), + &req.buf[7 + i], + error)) + return FALSE; + } + if (!fu_firmware_strparse_uint8_safe (line, + rcd->buf->len, + 9 + (req.len * 2), + &req.buf[7 + req.len], + error)) + return FALSE; req.bufsz = req.len + 8; /* retry this if it fails */ @@ -308,10 +294,7 @@ /* the device automatically reboots */ fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); fu_device_set_progress (device, 0); - - /* as soon as the parent comes back we can query the child */ - root = fu_device_get_root (device); - fu_device_add_flag (root, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); /* success */ return TRUE; @@ -340,9 +323,8 @@ fu_vli_usbhub_msp430_device_init (FuVliUsbhubMsp430Device *self) { fu_device_add_icon (FU_DEVICE (self), "audio-card"); - fu_device_set_protocol (FU_DEVICE (self), "com.vli.i2c"); + fu_device_add_protocol (FU_DEVICE (self), "com.vli.i2c"); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); - fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NO_GUID_MATCHING); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_PAIR); fu_device_set_logical_id (FU_DEVICE (self), "I2C"); fu_device_set_summary (FU_DEVICE (self), "I²C Dock Management Device"); diff -Nru fwupd-1.4.5/plugins/vli/fu-vli-usbhub-msp430-device.h fwupd-1.5.8/plugins/vli/fu-vli-usbhub-msp430-device.h --- fwupd-1.4.5/plugins/vli/fu-vli-usbhub-msp430-device.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/vli/fu-vli-usbhub-msp430-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019-2020 Richard Hughes + * Copyright (C) 2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/vli/fu-vli-usbhub-pd-device.c fwupd-1.5.8/plugins/vli/fu-vli-usbhub-pd-device.c --- fwupd-1.4.5/plugins/vli/fu-vli-usbhub-pd-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/vli/fu-vli-usbhub-pd-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2019 VIA Corporation + * Copyright (C) 2017 VIA Corporation * Copyright (C) 2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ @@ -19,7 +19,6 @@ struct _FuVliUsbhubPdDevice { FuDevice parent_instance; - FuVliPdHdr hdr; FuVliDeviceKind device_kind; }; @@ -38,10 +37,11 @@ } static gboolean -fu_vli_usbhub_pd_device_probe (FuDevice *device, GError **error) +fu_vli_usbhub_pd_device_setup (FuDevice *device, GError **error) { + FuVliPdHdr hdr = { 0x0 }; FuVliUsbhubPdDevice *self = FU_VLI_USBHUB_PD_DEVICE (device); - + FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (device)); guint32 fwver; g_autofree gchar *fwver_str = NULL; g_autofree gchar *instance_id0 = NULL; @@ -49,8 +49,39 @@ g_autofree gchar *instance_id2 = NULL; g_autofree gchar *instance_id3 = NULL; + /* legacy location */ + if (!fu_vli_device_spi_read_block (FU_VLI_DEVICE (parent), + VLI_USBHUB_FLASHMAP_ADDR_PD_LEGACY + + VLI_USBHUB_PD_FLASHMAP_ADDR_LEGACY, + (guint8 *) &hdr, sizeof(hdr), error)) { + g_prefix_error (error, "failed to read legacy PD header: "); + return FALSE; + } + + /* new location */ + if (GUINT16_FROM_LE (hdr.vid) != 0x2109) { + g_debug ("PD VID was 0x%04x trying new location", + GUINT16_FROM_LE (hdr.vid)); + if (!fu_vli_device_spi_read_block (FU_VLI_DEVICE (parent), + VLI_USBHUB_FLASHMAP_ADDR_PD + + VLI_USBHUB_PD_FLASHMAP_ADDR, + (guint8 *) &hdr, sizeof(hdr), error)) { + g_prefix_error (error, "failed to read PD header: "); + return FALSE; + } + } + + /* just empty space */ + if (hdr.fwver == G_MAXUINT32) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "no PD device header found"); + return FALSE; + } + /* get version */ - fwver = GUINT32_FROM_BE (self->hdr.fwver); + fwver = GUINT32_FROM_BE (hdr.fwver); self->device_kind = fu_vli_pd_common_guess_device_kind (fwver); if (self->device_kind == FU_VLI_DEVICE_KIND_UNKNOWN) { g_set_error (error, @@ -66,23 +97,23 @@ fwver_str = fu_common_version_from_uint32 (fwver, FWUPD_VERSION_FORMAT_QUAD); fu_device_set_version (device, fwver_str); instance_id0 = g_strdup_printf ("USB\\VID_%04X&PID_%04X&APP_%02X", - GUINT16_FROM_LE (self->hdr.vid), - GUINT16_FROM_LE (self->hdr.pid), + GUINT16_FROM_LE (hdr.vid), + GUINT16_FROM_LE (hdr.pid), fwver & 0xff); fu_device_add_instance_id (device, instance_id0); instance_id1 = g_strdup_printf ("USB\\VID_%04X&PID_%04X&DEV_%s", - GUINT16_FROM_LE (self->hdr.vid), - GUINT16_FROM_LE (self->hdr.pid), + GUINT16_FROM_LE (hdr.vid), + GUINT16_FROM_LE (hdr.pid), fu_vli_common_device_kind_to_string (self->device_kind)); fu_device_add_instance_id (device, instance_id1); /* add standard GUIDs in order of priority */ instance_id2 = g_strdup_printf ("USB\\VID_%04X&PID_%04X", - GUINT16_FROM_LE (self->hdr.vid), - GUINT16_FROM_LE (self->hdr.pid)); + GUINT16_FROM_LE (hdr.vid), + GUINT16_FROM_LE (hdr.pid)); fu_device_add_instance_id (device, instance_id2); instance_id3 = g_strdup_printf ("USB\\VID_%04X", - GUINT16_FROM_LE (self->hdr.vid)); + GUINT16_FROM_LE (hdr.vid)); fu_device_add_instance_id_full (device, instance_id3, FU_DEVICE_INSTANCE_FLAG_ONLY_QUIRKS); @@ -94,6 +125,19 @@ return TRUE; } +static gboolean +fu_vli_usbhub_pd_device_reload (FuDevice *device, GError **error) +{ + FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (device)); + g_autoptr(FuDeviceLocker) locker = NULL; + + /* open parent device */ + locker = fu_device_locker_new (parent, error); + if (locker == NULL) + return FALSE; + return fu_vli_usbhub_pd_device_setup (device, error); +} + static FuFirmware * fu_vli_usbhub_pd_device_prepare_firmware (FuDevice *device, GBytes *fw, @@ -104,28 +148,7 @@ FuVliDeviceKind device_kind; g_autoptr(FuFirmware) firmware = fu_vli_pd_firmware_new (); - /* check size */ - if (g_bytes_get_size (fw) < fu_device_get_firmware_size_min (device)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "firmware too small, got 0x%x, expected >= 0x%x", - (guint) g_bytes_get_size (fw), - (guint) fu_device_get_firmware_size_min (device)); - return NULL; - } - if (g_bytes_get_size (fw) > fu_device_get_firmware_size_max (device)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "firmware too large, got 0x%x, expected <= 0x%x", - (guint) g_bytes_get_size (fw), - (guint) fu_device_get_firmware_size_max (device)); - return NULL; - } - /* check is compatible with firmware */ - fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); if (!fu_firmware_parse (firmware, fw, flags, error)) return NULL; device_kind = fu_vli_pd_firmware_get_kind (FU_VLI_PD_FIRMWARE (firmware)); @@ -144,13 +167,12 @@ return g_steal_pointer (&firmware); } -static FuFirmware * -fu_vli_usbhub_pd_device_read_firmware (FuDevice *device, GError **error) +static GBytes * +fu_vli_usbhub_pd_device_dump_firmware (FuDevice *device, GError **error) { FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (device)); FuVliUsbhubPdDevice *self = FU_VLI_USBHUB_PD_DEVICE (device); g_autoptr(FuDeviceLocker) locker = NULL; - g_autoptr(GBytes) fw = NULL; /* open device */ locker = fu_device_locker_new (parent, error); @@ -158,14 +180,11 @@ return NULL; /* read */ - fu_device_set_status (FU_DEVICE (device), FWUPD_STATUS_DEVICE_VERIFY); - fw = fu_vli_device_spi_read (FU_VLI_DEVICE (parent), - fu_vli_common_device_kind_get_offset (self->device_kind), - fu_device_get_firmware_size_max (device), - error); - if (fw == NULL) - return NULL; - return fu_firmware_new_from_bytes (fw); + fu_device_set_status (FU_DEVICE (device), FWUPD_STATUS_DEVICE_READ); + return fu_vli_device_spi_read (FU_VLI_DEVICE (parent), + fu_vli_common_device_kind_get_offset (self->device_kind), + fu_device_get_firmware_size_max (device), + error); } static gboolean @@ -225,7 +244,7 @@ fu_vli_usbhub_pd_device_init (FuVliUsbhubPdDevice *self) { fu_device_add_icon (FU_DEVICE (self), "audio-card"); - fu_device_set_protocol (FU_DEVICE (self), "com.vli.usbhub"); + fu_device_add_protocol (FU_DEVICE (self), "com.vli.usbhub"); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_QUAD); @@ -239,17 +258,19 @@ { FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); klass_device->to_string = fu_vli_usbhub_pd_device_to_string; - klass_device->probe = fu_vli_usbhub_pd_device_probe; + klass_device->setup = fu_vli_usbhub_pd_device_setup; + klass_device->reload = fu_vli_usbhub_pd_device_reload; klass_device->attach = fu_vli_usbhub_pd_device_attach; - klass_device->read_firmware = fu_vli_usbhub_pd_device_read_firmware; + klass_device->dump_firmware = fu_vli_usbhub_pd_device_dump_firmware; klass_device->write_firmware = fu_vli_usbhub_pd_device_write_firmware; klass_device->prepare_firmware = fu_vli_usbhub_pd_device_prepare_firmware; } FuDevice * -fu_vli_usbhub_pd_device_new (FuVliPdHdr *hdr) +fu_vli_usbhub_pd_device_new (FuVliUsbhubDevice *parent) { - FuVliUsbhubPdDevice *self = g_object_new (FU_TYPE_VLI_USBHUB_PD_DEVICE, NULL); - memcpy (&self->hdr, hdr, sizeof(self->hdr)); + FuVliUsbhubPdDevice *self = g_object_new (FU_TYPE_VLI_USBHUB_PD_DEVICE, + "parent", parent, + NULL); return FU_DEVICE (self); } diff -Nru fwupd-1.4.5/plugins/vli/fu-vli-usbhub-pd-device.h fwupd-1.5.8/plugins/vli/fu-vli-usbhub-pd-device.h --- fwupd-1.4.5/plugins/vli/fu-vli-usbhub-pd-device.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/vli/fu-vli-usbhub-pd-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -8,8 +8,6 @@ #include "fu-plugin.h" -#include "fu-vli-pd-common.h" - #define FU_TYPE_VLI_USBHUB_PD_DEVICE (fu_vli_usbhub_pd_device_get_type ()) G_DECLARE_FINAL_TYPE (FuVliUsbhubPdDevice, fu_vli_usbhub_pd_device, FU, VLI_USBHUB_PD_DEVICE, FuDevice) @@ -18,4 +16,4 @@ FuDeviceClass parent_class; }; -FuDevice *fu_vli_usbhub_pd_device_new (FuVliPdHdr *hdr); +FuDevice *fu_vli_usbhub_pd_device_new (FuVliUsbhubDevice *parent); diff -Nru fwupd-1.4.5/plugins/vli/fu-vli-usbhub-rtd21xx-device.c fwupd-1.5.8/plugins/vli/fu-vli-usbhub-rtd21xx-device.c --- fwupd-1.4.5/plugins/vli/fu-vli-usbhub-rtd21xx-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/vli/fu-vli-usbhub-rtd21xx-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,525 @@ +/* + * Copyright (C) 2017 VIA Corporation + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-chunk.h" + +#include "fu-vli-usbhub-device.h" +#include "fu-vli-usbhub-rtd21xx-device.h" + +struct _FuVliUsbhubRtd21xxDevice +{ + FuDevice parent_instance; +}; + +G_DEFINE_TYPE (FuVliUsbhubRtd21xxDevice, fu_vli_usbhub_rtd21xx_device, FU_TYPE_DEVICE) + +#define I2C_WRITE_REQUEST 0xB2 +#define I2C_READ_REQUEST 0xA5 + +#define I2C_DELAY_AFTER_SEND 5000 /* us */ + +#define UC_FOREGROUND_SLAVE_ADDR 0x3A +#define UC_FOREGROUND_STATUS 0x31 +#define UC_FOREGROUND_OPCODE 0x33 +#define UC_FOREGROUND_ISP_DATA_OPCODE 0x34 + +#define ISP_DATA_BLOCKSIZE 30 +#define ISP_PACKET_SIZE 32 + +typedef enum { + ISP_STATUS_BUSY = 0xBB, /* host must wait for device */ + ISP_STATUS_IDLE_SUCCESS = 0x11, /* previous command was OK */ + ISP_STATUS_IDLE_FAILURE = 0x12, /* previous command failed */ +} IspStatus; + +typedef enum { + ISP_CMD_ENTER_FW_UPDATE = 0x01, + ISP_CMD_GET_PROJECT_ID_ADDR = 0x02, + ISP_CMD_SYNC_IDENTIFY_CODE = 0x03, + ISP_CMD_GET_FW_INFO = 0x04, + ISP_CMD_FW_UPDATE_START = 0x05, + ISP_CMD_FW_UPDATE_ISP_DONE = 0x06, + ISP_CMD_FW_UPDATE_EXIT = 0x07, + ISP_CMD_FW_UPDATE_RESET = 0x08, +} IspCmd; + +static gboolean +fu_vli_usbhub_device_i2c_write (FuVliUsbhubDevice *self, + guint8 slave_addr, guint8 sub_addr, + guint8 *data, gsize datasz, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + gsize bufsz = datasz + 2; + g_autofree guint8 *buf = g_malloc0 (bufsz); + + buf[0] = slave_addr; + buf[1] = sub_addr; + if (!fu_memcpy_safe (buf, bufsz, 0x2, /* dst */ + data, datasz, 0x0, /* src */ + datasz, error)) + return FALSE; + if (g_getenv ("FWUPD_VLI_USBHUB_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "I2cWriteData", buf, datasz + 2); + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + I2C_WRITE_REQUEST, 0x0000, 0x0000, + buf, datasz + 2, NULL, + FU_VLI_DEVICE_TIMEOUT, + NULL, error)) { + g_prefix_error (error, + "failed to write I2C @0x%02x:%02x: ", + slave_addr, sub_addr); + return FALSE; + } + g_usleep (I2C_DELAY_AFTER_SEND); + return TRUE; +} + +static gboolean +fu_vli_usbhub_device_i2c_read (FuVliUsbhubDevice *self, + guint8 slave_addr, guint8 sub_addr, + guint8 *data, gsize datasz, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + I2C_READ_REQUEST, 0x0000, + ((guint16) sub_addr << 8) + slave_addr, + data, datasz, NULL, + FU_VLI_DEVICE_TIMEOUT, + NULL, error)) { + g_prefix_error (error, "failed to read I2C: "); + return FALSE; + } + if (g_getenv ("FWUPD_VLI_USBHUB_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "I2cReadData", data, datasz); + return TRUE; + +} + +static gboolean +fu_vli_usbhub_device_rtd21xx_read_status_raw (FuVliUsbhubRtd21xxDevice *self, + guint8 *status, + GError **error) +{ + FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (FU_DEVICE (self))); + guint8 buf[] = { 0x00 }; + if (!fu_vli_usbhub_device_i2c_read (parent, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_STATUS, + buf, sizeof(buf), + error)) + return FALSE; + if (status != NULL) + *status = buf[0]; + return TRUE; +} + +static gboolean +fu_vli_usbhub_device_rtd21xx_read_status_cb (FuDevice *device, + gpointer user_data, + GError **error) +{ + FuVliUsbhubRtd21xxDevice *self = FU_VLI_USBHUB_RTD21XX_DEVICE (device); + guint8 status = 0xfd; + if (!fu_vli_usbhub_device_rtd21xx_read_status_raw (self, &status, error)) + return FALSE; + if (status == ISP_STATUS_BUSY) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "status was 0x%02x", status); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_vli_usbhub_device_rtd21xx_read_status (FuVliUsbhubRtd21xxDevice *self, + guint8 *status, + GError **error) +{ + return fu_device_retry (FU_DEVICE (self), + fu_vli_usbhub_device_rtd21xx_read_status_cb, + 4200, status, error); +} + +static gboolean +fu_vli_usbhub_rtd21xx_ensure_version_unlocked (FuVliUsbhubRtd21xxDevice *self, + GError **error) +{ + FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (FU_DEVICE (self))); + guint8 buf_rep[7] = { 0x00 }; + guint8 buf_req[] = { ISP_CMD_GET_FW_INFO }; + g_autofree gchar *version = NULL; + + if (!fu_vli_usbhub_device_i2c_write (parent, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_OPCODE, + buf_req, sizeof(buf_req), + error)) { + g_prefix_error (error, "failed to get version number: "); + return FALSE; + } + + /* wait for device ready */ + g_usleep (300000); + if (!fu_vli_usbhub_device_i2c_read (parent, + UC_FOREGROUND_SLAVE_ADDR, + 0x00, + buf_rep, sizeof(buf_rep), + error)) { + g_prefix_error (error, "failed to get version number: "); + return FALSE; + } + + /* set version */ + version = g_strdup_printf ("%u.%u", buf_rep[1], buf_rep[2]); + fu_device_set_version (FU_DEVICE (self), version); + return TRUE; +} + +static gboolean +fu_vli_usbhub_rtd21xx_device_setup (FuDevice *device, GError **error) +{ + FuVliUsbhubRtd21xxDevice *self = FU_VLI_USBHUB_RTD21XX_DEVICE (device); + g_autoptr(FuDeviceLocker) locker = NULL; + + /* get version */ + locker = fu_device_locker_new_full (device, + (FuDeviceLockerFunc) fu_device_detach, + (FuDeviceLockerFunc) fu_device_attach, + error); + if (locker == NULL) + return FALSE; + if (!fu_vli_usbhub_rtd21xx_ensure_version_unlocked (self, error)) + return FALSE; + + /* success */ + return TRUE; +} + +static gboolean +fu_vli_usbhub_device_rtd21xx_detach_raw (FuVliUsbhubRtd21xxDevice *self, GError **error) +{ + FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (FU_DEVICE (self))); + guint8 buf[] = { 0x03 }; + if (!fu_vli_usbhub_device_i2c_write (parent, 0x6A, 0x31, buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to detach: "); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_vli_usbhub_device_rtd21xx_detach_cb (FuDevice *device, + gpointer user_data, + GError **error) +{ + FuVliUsbhubRtd21xxDevice *self = FU_VLI_USBHUB_RTD21XX_DEVICE (device); + guint8 status = 0xfe; + if (!fu_vli_usbhub_device_rtd21xx_detach_raw (self, error)) + return FALSE; + if (!fu_vli_usbhub_device_rtd21xx_read_status_raw (self, &status, error)) + return FALSE; + if (status != ISP_STATUS_IDLE_SUCCESS) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "detach status was 0x%02x", status); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_vli_usbhub_rtd21xx_device_detach (FuDevice *device, GError **error) +{ + FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (device)); + g_autoptr(FuDeviceLocker) locker = NULL; + + /* open device */ + locker = fu_device_locker_new (parent, error); + if (locker == NULL) + return FALSE; + if (!fu_device_retry (device, + fu_vli_usbhub_device_rtd21xx_detach_cb, + 100, NULL, error)) + return FALSE; + + /* success */ + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + return TRUE; +} + +static gboolean +fu_vli_usbhub_rtd21xx_device_attach (FuDevice *device, GError **error) +{ + FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (device)); + guint8 buf[] = { ISP_CMD_FW_UPDATE_RESET }; + g_autoptr(FuDeviceLocker) locker = NULL; + + /* open device */ + locker = fu_device_locker_new (parent, error); + if (locker == NULL) + return FALSE; + if (!fu_vli_usbhub_device_i2c_write (parent, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_OPCODE, + buf, sizeof(buf), + error)) { + g_prefix_error (error, "failed to attach: "); + return FALSE; + } + + /* success */ + fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + return TRUE; +} + +static gboolean +fu_vli_usbhub_rtd21xx_device_write_firmware (FuDevice *device, + FuFirmware *firmware, + FwupdInstallFlags flags, + GError **error) +{ + FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (device)); + FuVliUsbhubRtd21xxDevice *self = FU_VLI_USBHUB_RTD21XX_DEVICE (device); + const guint8 *fwbuf; + gsize fwbufsz = 0; + guint32 project_addr; + guint8 project_id_count; + guint8 read_buf[10] = { 0 }; + guint8 write_buf[ISP_PACKET_SIZE] = {0}; + g_autoptr(FuDeviceLocker) locker = NULL; + g_autoptr(GBytes) fw = NULL; + g_autoptr(GPtrArray) chunks = NULL; + + /* open device */ + locker = fu_device_locker_new (parent, error); + if (locker == NULL) + return FALSE; + + /* simple image */ + fw = fu_firmware_get_image_default_bytes (firmware, error); + if (fw == NULL) + return FALSE; + fwbuf = g_bytes_get_data (fw, &fwbufsz); + + /* enable ISP high priority */ + write_buf[0] = ISP_CMD_ENTER_FW_UPDATE; + write_buf[1] = 0x01; + fu_device_set_status (device, FWUPD_STATUS_DEVICE_BUSY); + if (!fu_vli_usbhub_device_i2c_write (parent, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_OPCODE, + write_buf, + 2, + error)) { + g_prefix_error (error, "failed to enable ISP: "); + return FALSE; + } + if (!fu_vli_usbhub_device_rtd21xx_read_status (self, NULL, error)) + return FALSE; + + /* get project ID address */ + write_buf[0] = ISP_CMD_GET_PROJECT_ID_ADDR; + fu_device_set_status (device, FWUPD_STATUS_DEVICE_READ); + if (!fu_vli_usbhub_device_i2c_write (parent, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_OPCODE, + write_buf, 1, + error)) { + g_prefix_error (error, "failed to get project ID address: "); + return FALSE; + } + + /* read back 6 bytes data */ + g_usleep (I2C_DELAY_AFTER_SEND * 40); + if (!fu_vli_usbhub_device_i2c_read (parent, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_STATUS, + read_buf, 6, + error)) { + g_prefix_error (error, "failed to read project ID: "); + return FALSE; + } + if (read_buf[0] != ISP_STATUS_IDLE_SUCCESS) { + g_prefix_error (error, "failed project ID with error 0x%02x: ", read_buf[0]); + return FALSE; + } + + /* verify project ID */ + if (!fu_common_read_uint32_safe (read_buf, sizeof(read_buf), 0x1, + &project_addr, G_BIG_ENDIAN, error)) + return FALSE; + project_id_count = read_buf[5]; + write_buf[0] = ISP_CMD_SYNC_IDENTIFY_CODE; + if (!fu_memcpy_safe (write_buf, sizeof(write_buf), 0x1, /* dst */ + fwbuf, fwbufsz, project_addr, /* src */ + project_id_count, error)) { + g_prefix_error (error, "failed to write project ID from 0x%04x: ", project_addr); + return FALSE; + } + fu_device_set_status (device, FWUPD_STATUS_DEVICE_BUSY); + if (!fu_vli_usbhub_device_i2c_write (parent, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_OPCODE, + write_buf, + project_id_count + 1, + error)) { + g_prefix_error (error, "failed to send fw update start cmd: "); + return FALSE; + } + if (!fu_vli_usbhub_device_rtd21xx_read_status (self, NULL, error)) + return FALSE; + + /* background FW update start command */ + write_buf[0] = ISP_CMD_FW_UPDATE_START; + fu_common_write_uint16 (write_buf + 1, ISP_DATA_BLOCKSIZE, G_BIG_ENDIAN); + if (!fu_vli_usbhub_device_i2c_write (parent, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_OPCODE, + write_buf, 3, + error)) { + g_prefix_error (error, "failed to send fw update start cmd: "); + return FALSE; + } + + /* send data */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + chunks = fu_chunk_array_new_from_bytes (fw, + 0x00, /* start addr */ + 0x00, /* page_sz */ + ISP_DATA_BLOCKSIZE); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + if (!fu_vli_usbhub_device_rtd21xx_read_status (self, NULL, error)) + return FALSE; + if (!fu_vli_usbhub_device_i2c_write (parent, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_ISP_DATA_OPCODE, + fu_chunk_get_data_out (chk), + fu_chunk_get_data_sz (chk), + error)) { + g_prefix_error (error, "failed to write @0x%04x: ", fu_chunk_get_address (chk)); + return FALSE; + } + + /* update progress */ + fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len); + } + + /* update finish command */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_BUSY); + if (!fu_vli_usbhub_device_rtd21xx_read_status (self, NULL, error)) + return FALSE; + write_buf[0] = ISP_CMD_FW_UPDATE_ISP_DONE; + if (!fu_vli_usbhub_device_i2c_write (parent, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_OPCODE, + write_buf, 1, + error)) { + g_prefix_error (error, "failed update finish cmd: "); + return FALSE; + } + + /* exit background-fw mode */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + fu_device_set_progress (device, 0); + if (!fu_vli_usbhub_device_rtd21xx_read_status (self, NULL, error)) + return FALSE; + write_buf[0] = ISP_CMD_FW_UPDATE_EXIT; + if (!fu_vli_usbhub_device_i2c_write (parent, + UC_FOREGROUND_SLAVE_ADDR, + UC_FOREGROUND_OPCODE, + write_buf, 1, + error)) { + g_prefix_error (error, "FwUpdate exit: "); + return FALSE; + } + + /* the device needs some time to restart with the new firmware before + * it can be queried again */ + fu_device_sleep_with_progress (device, 20); + + /* success */ + return TRUE; +} + +static gboolean +fu_vli_usbhub_rtd21xx_device_reload (FuDevice *device, GError **error) +{ + FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (device)); + g_autoptr(FuDeviceLocker) locker = NULL; + + /* open parent device */ + locker = fu_device_locker_new (parent, error); + if (locker == NULL) + return FALSE; + return fu_vli_usbhub_rtd21xx_device_setup (device, error); +} + +static gboolean +fu_vli_usbhub_rtd21xx_device_probe (FuDevice *device, GError **error) +{ + FuVliDeviceKind device_kind = FU_VLI_DEVICE_KIND_RTD21XX; + FuVliUsbhubDevice *parent = FU_VLI_USBHUB_DEVICE (fu_device_get_parent (device)); + g_autofree gchar *instance_id = NULL; + + fu_device_set_name (device, fu_vli_common_device_kind_to_string (device_kind)); + + /* add instance ID */ + instance_id = g_strdup_printf ("USB\\VID_%04X&PID_%04X&I2C_%s", + fu_usb_device_get_vid (FU_USB_DEVICE (parent)), + fu_usb_device_get_pid (FU_USB_DEVICE (parent)), + fu_vli_common_device_kind_to_string (device_kind)); + fu_device_add_instance_id (device, instance_id); + return TRUE; +} + +static void +fu_vli_usbhub_rtd21xx_device_init (FuVliUsbhubRtd21xxDevice *self) +{ + fu_device_add_icon (FU_DEVICE (self), "video-display"); + fu_device_add_protocol (FU_DEVICE (self), "com.vli.i2c"); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_DUAL_IMAGE); + fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_PAIR); + fu_device_set_install_duration (FU_DEVICE (self), 100); /* seconds */ + fu_device_set_logical_id (FU_DEVICE (self), "I2C"); + fu_device_retry_set_delay (FU_DEVICE (self), 30); /* ms */ +} + +static void +fu_vli_usbhub_rtd21xx_device_class_init (FuVliUsbhubRtd21xxDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + klass_device->probe = fu_vli_usbhub_rtd21xx_device_probe; + klass_device->setup = fu_vli_usbhub_rtd21xx_device_setup; + klass_device->reload = fu_vli_usbhub_rtd21xx_device_reload; + klass_device->attach = fu_vli_usbhub_rtd21xx_device_attach; + klass_device->detach = fu_vli_usbhub_rtd21xx_device_detach; + klass_device->write_firmware = fu_vli_usbhub_rtd21xx_device_write_firmware; +} + +FuDevice * +fu_vli_usbhub_rtd21xx_device_new (FuVliUsbhubDevice *parent) +{ + FuVliUsbhubRtd21xxDevice *self = g_object_new (FU_TYPE_VLI_USBHUB_RTD21XX_DEVICE, + "parent", parent, + NULL); + return FU_DEVICE (self); +} diff -Nru fwupd-1.4.5/plugins/vli/fu-vli-usbhub-rtd21xx-device.h fwupd-1.5.8/plugins/vli/fu-vli-usbhub-rtd21xx-device.h --- fwupd-1.4.5/plugins/vli/fu-vli-usbhub-rtd21xx-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/vli/fu-vli-usbhub-rtd21xx-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +#define FU_TYPE_VLI_USBHUB_RTD21XX_DEVICE (fu_vli_usbhub_rtd21xx_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuVliUsbhubRtd21xxDevice, fu_vli_usbhub_rtd21xx_device, FU, VLI_USBHUB_RTD21XX_DEVICE, FuDevice) + +struct _FuVliUsbhubRtd21xxDeviceClass +{ + FuDeviceClass parent_class; +}; + +FuDevice *fu_vli_usbhub_rtd21xx_device_new (FuVliUsbhubDevice *parent); diff -Nru fwupd-1.4.5/plugins/vli/meson.build fwupd-1.5.8/plugins/vli/meson.build --- fwupd-1.4.5/plugins/vli/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/vli/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,9 +1,11 @@ +if get_option('gusb') cargs = ['-DG_LOG_DOMAIN="FuPluginVliUsbhub"'] install_data([ 'vli-pd.quirk', 'vli-usbhub.quirk', 'vli-usbhub-lenovo.quirk', + 'vli-usbhub-hyper.quirk', ], install_dir: join_paths(datadir, 'fwupd', 'quirks.d') ) @@ -24,6 +26,7 @@ 'fu-vli-usbhub-i2c-common.c', 'fu-vli-usbhub-msp430-device.c', 'fu-vli-usbhub-pd-device.c', + 'fu-vli-usbhub-rtd21xx-device.c', ], include_directories : [ root_incdir, @@ -43,8 +46,6 @@ ) if get_option('tests') - testdatadir = join_paths(meson.current_source_dir(), 'data') - cargs += '-DTESTDATADIR="' + testdatadir + '"' e = executable( 'vli-self-test', fu_hash, @@ -64,7 +65,10 @@ fwupd, fwupdplugin, ], - c_args : cargs + c_args : cargs, + install : true, + install_dir : installed_test_bindir, ) - test('vli-self-test', e) + test('vli-self-test', e) # added to installed-tests +endif endif diff -Nru fwupd-1.4.5/plugins/vli/README.md fwupd-1.5.8/plugins/vli/README.md --- fwupd-1.4.5/plugins/vli/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/vli/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -59,24 +59,28 @@ | Quirk | Description | Minimum fwupd version | |----------------------------|----------------------------------|-----------------------| -| `DeviceKind` | Device kind, e.g. `VL102` | 1.3.7 | -| `SpiAutoDetect` | SPI autodetect (default 0x1) | 1.3.7 | -| `SpiCmdChipErase` | Flash command to erase chip | 1.3.3 | -| `SpiCmdChipErase` | Flash command to erase sector | 1.3.3 | -| `SpiCmdReadId` | Flash command to read the ID | 1.3.3 | -| `SpiCmdReadIdSz` | Size of the ReadId response | 1.3.3 | +| `VliDeviceKind` | Device kind, e.g. `VL102` | 1.3.7 | +| `VliSpiAutoDetect` | SPI autodetect (default 0x1) | 1.3.7 | +| `VliSpiCmdChipErase` | Flash command to erase chip | 1.3.3 | +| `VliSpiCmdChipErase` | Flash command to erase sector | 1.3.3 | +| `VliSpiCmdReadId` | Flash command to read the ID | 1.3.3 | +| `VliSpiCmdReadIdSz` | Size of the ReadId response | 1.3.3 | -The `SpiCmdReadId` and `SpiCmdReadIdSz` quirks have to be assigned to the device +The `VliSpiCmdReadId` and `VliSpiCmdReadIdSz` quirks have to be assigned to the device instance attribute, rather then the flash part as the ID is required to query the other flash chip parameters. For example: - [DeviceInstanceId=USB\VID_2109&PID_0210] + [USB\VID_2109&PID_0210] Plugin = vli GType = FuVliUsbhubDevice - SpiCmdReadId = 0xf8 - SpiCmdReadIdSz = 4 + VliSpiCmdReadId = 0xf8 + VliSpiCmdReadIdSz = 4 # W3IRDFLASHxxx - [Guid=VLI_USBHUB\\SPI_37303840] - SpiCmdChipErase = 0xc7 - SpiCmdSectorErase = 0x20 + [VLI_USBHUB\\SPI_37303840] + VliSpiCmdChipErase = 0xc7 + VliSpiCmdSectorErase = 0x20 + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff -Nru fwupd-1.4.5/plugins/vli/vli-pd.quirk fwupd-1.5.8/plugins/vli/vli-pd.quirk --- fwupd-1.4.5/plugins/vli/vli-pd.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/vli/vli-pd.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,137 +1,134 @@ # Generic -[DeviceInstanceId=USB\VID_0800&PID_0800] +[USB\VID_0800&PID_0800] Plugin = vli GType = FuVliPdDevice -DeviceKind = VL100 -[DeviceInstanceId=USB\VID_2109&PID_0100] +VliDeviceKind = VL100 +[USB\VID_2109&PID_0100] Plugin = vli GType = FuVliPdDevice -DeviceKind = VL100 -[DeviceInstanceId=USB\VID_2109&PID_0101] +VliDeviceKind = VL100 +[USB\VID_2109&PID_0101] Plugin = vli GType = FuVliPdDevice -DeviceKind = VL101 -[DeviceInstanceId=USB\VID_2109&PID_0102] +VliDeviceKind = VL101 +[USB\VID_2109&PID_0102] Plugin = vli GType = FuVliPdDevice -DeviceKind = VL102 -[DeviceInstanceId=USB\VID_2109&PID_0103] +VliDeviceKind = VL102 +[USB\VID_2109&PID_0103] Plugin = vli GType = FuVliPdDevice Flags = dual-image -DeviceKind = VL103 -[DeviceInstanceId=USB\VID_2109&PID_0104] +VliDeviceKind = VL103 +[USB\VID_2109&PID_0104] Plugin = vli GType = FuVliPdDevice -DeviceKind = VL104 -[DeviceInstanceId=USB\VID_2109&PID_0105] +VliDeviceKind = VL104 +[USB\VID_2109&PID_0105] Plugin = vli GType = FuVliPdDevice -DeviceKind = VL105 -[DeviceInstanceId=USB\VID_2109&PID_0106] +VliDeviceKind = VL105 +[USB\VID_2109&PID_0106] Plugin = vli GType = FuVliPdDevice -DeviceKind = VL106 -[DeviceInstanceId=USB\VID_2109&PID_0107] +VliDeviceKind = VL106 +[USB\VID_2109&PID_0107] Plugin = vli GType = FuVliPdDevice -DeviceKind = VL107 +VliDeviceKind = VL107 -[DeviceInstanceId=USB\VID_2109&PID_D101] +[USB\VID_2109&PID_D101] Plugin = vli GType = FuVliPdDevice -[DeviceInstanceId=USB\VID_2109&PID_D102] +[USB\VID_2109&PID_D102] Plugin = vli GType = FuVliPdDevice # Lenovo VGA -[DeviceInstanceId=USB\VID_17EF&PID_7211] +[USB\VID_17EF&PID_7211] Plugin = vli GType = FuVliPdDevice # Lenovo HDMI -[DeviceInstanceId=USB\VID_17EF&PID_7212] +[USB\VID_17EF&PID_7212] Plugin = vli GType = FuVliPdDevice -Flag = dual-image +Flags = dual-image # Lenovo -[DeviceInstanceId=USB\VID_17EF&PID_7215] -Plugin = vli -GType = FuVliPdDevice -[DeviceInstanceId=USB\VID_17EF&PID_7217] +[USB\VID_17EF&PID_7215] Plugin = vli GType = FuVliPdDevice -[DeviceInstanceId=USB\VID_17EF&PID_721C] +[USB\VID_17EF&PID_7217] Plugin = vli GType = FuVliPdDevice -[DeviceInstanceId=USB\VID_17EF&PID_7223] +[USB\VID_17EF&PID_7223] Plugin = vli GType = FuVliPdDevice # Samsung -[DeviceInstanceId=USB\VID_04E8&PID_A025] +[USB\VID_04E8&PID_A025] Plugin = vli GType = FuVliPdDevice -[DeviceInstanceId=USB\VID_04E8&PID_A048] +[USB\VID_04E8&PID_A048] Plugin = vli GType = FuVliPdDevice -[DeviceInstanceId=USB\VID_2109&PID_8880] +[USB\VID_2109&PID_8880] Plugin = vli GType = FuVliPdDevice # VL671,U3TT, VT3547 -[DeviceInstanceId=USB\VID_2109&PID_8881] +[USB\VID_2109&PID_8881] Plugin = vli GType = FuVliPdDevice -[DeviceInstanceId=USB\VID_2109&PID_8882] +[USB\VID_2109&PID_8882] Plugin = vli GType = FuVliPdDevice -[DeviceInstanceId=USB\VID_2109&PID_8883] +[USB\VID_2109&PID_8883] Plugin = vli GType = FuVliPdDevice # Realtek -[DeviceInstanceId=USB\VID_2109&PID_8884] +[USB\VID_2109&PID_8884] Plugin = vli GType = FuVliPdDevice # VL650, VT3555 -[DeviceInstanceId=USB\VID_2109&PID_8885] +[USB\VID_2109&PID_8885] Plugin = vli GType = FuVliPdDevice # MStar, VT3518 -[DeviceInstanceId=USB\VID_2109&PID_8886] +[USB\VID_2109&PID_8886] Plugin = vli GType = FuVliPdDevice -[DeviceInstanceId=USB\VID_2109&PID_8887] +[USB\VID_2109&PID_8887] Plugin = vli GType = FuVliPdDevice -[DeviceInstanceId=USB\VID_2109&PID_8889] +[USB\VID_2109&PID_8889] Plugin = vli GType = FuVliPdDevice # Novatek, VT3538 -[DeviceInstanceId=USB\VID_2109&PID_888A] +[USB\VID_2109&PID_888A] Plugin = vli GType = FuVliPdDevice -[DeviceInstanceId=USB\VID_2109&PID_888B] +[USB\VID_2109&PID_888B] Plugin = vli GType = FuVliPdDevice -[DeviceInstanceId=USB\VID_2109&PID_888C] +[USB\VID_2109&PID_888C] Plugin = vli GType = FuVliPdDevice -[DeviceInstanceId=USB\VID_2109&PID_888D] +[USB\VID_2109&PID_888D] Plugin = vli GType = FuVliPdDevice -[DeviceInstanceId=USB\VID_2109&PID_888E] +[USB\VID_2109&PID_888E] Plugin = vli GType = FuVliPdDevice -[DeviceInstanceId=USB\VID_2109&PID_888F] +[USB\VID_2109&PID_888F] Plugin = vli GType = FuVliPdDevice diff -Nru fwupd-1.4.5/plugins/vli/vli-usbhub-hyper.quirk fwupd-1.5.8/plugins/vli/vli-usbhub-hyper.quirk --- fwupd-1.4.5/plugins/vli/vli-usbhub-hyper.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/plugins/vli/vli-usbhub-hyper.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,11 @@ +# Hyper USB-C Hub +[USB\VID_2D01&PID_0385] +Plugin = vli +GType = FuVliUsbhubDevice +Flags = usb3,has-shared-spi-pd +CounterpartGuid = USB\VID_2D01&PID_0382 +[USB\VID_2D01&PID_0382] +Plugin = vli +GType = FuVliUsbhubDevice +Flags = usb2 +ParentGuid = USB\VID_2D01&PID_0385 diff -Nru fwupd-1.4.5/plugins/vli/vli-usbhub-lenovo.quirk fwupd-1.5.8/plugins/vli/vli-usbhub-lenovo.quirk --- fwupd-1.4.5/plugins/vli/vli-usbhub-lenovo.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/vli/vli-usbhub-lenovo.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,266 +1,279 @@ # Lenovo CS18 Ultra Dock -[DeviceInstanceId=USB\VID_17EF&PID_3070] +[USB\VID_17EF&PID_3070] Plugin = vli GType = FuVliUsbhubDevice Flags = usb3 CounterpartGuid = USB\VID_17EF&PID_3071 -[DeviceInstanceId=USB\VID_17EF&PID_3072&HUB_0006] +[USB\VID_17EF&PID_3072&HUB_0006] ParentGuid = USB\VID_17EF&PID_3072&HUB_0002 -[DeviceInstanceId=USB\VID_17EF&PID_3071] +[USB\VID_17EF&PID_3071] Plugin = vli GType = FuVliUsbhubDevice Flags = usb2 -[DeviceInstanceId=USB\VID_17EF&PID_3071&HUB_0002] +[USB\VID_17EF&PID_3071&HUB_0002] ParentGuid = USB\VID_17EF&PID_3071&HUB_0006 # Lenovo CS18 Pro and Basic Dock -[DeviceInstanceId=USB\VID_17EF&PID_3072] +[USB\VID_17EF&PID_3072] Plugin = vli GType = FuVliUsbhubDevice Flags = usb3 CounterpartGuid = USB\VID_17EF&PID_3073 -[DeviceInstanceId=USB\VID_17EF&PID_3073] +[USB\VID_17EF&PID_3073] Plugin = vli GType = FuVliUsbhubDevice Flags = usb2 -[DeviceInstanceId=USB\VID_17EF&PID_3073&HUB_0006] +[USB\VID_17EF&PID_3073&HUB_0006] ParentGuid = USB\VID_17EF&PID_3073&HUB_0002 # Lenovo TR Dock -[DeviceInstanceId=USB\VID_17EF&PID_307F&HUB_0002] +[USB\VID_17EF&PID_307F&HUB_0002] ParentGuid = TBT-01081720 -[DeviceInstanceId=USB\VID_17EF&PID_307F] +[USB\VID_17EF&PID_307F] Plugin = vli GType = FuVliUsbhubDevice Flags = usb3,has-msp430 CounterpartGuid = USB\VID_17EF&PID_3080 -[DeviceInstanceId=USB\VID_17EF&PID_307F&HUB_0006] +[USB\VID_17EF&PID_307F&HUB_0006] ParentGuid = USB\VID_17EF&PID_307F&HUB_0002 -[DeviceInstanceId=USB\VID_17EF&PID_3080] +[USB\VID_17EF&PID_3080] Plugin = vli GType = FuVliUsbhubDevice -Flags = usb2,has-msp430 -[DeviceInstanceId=USB\VID_17EF&PID_3080&HUB_06] +Flags = usb2 +[USB\VID_17EF&PID_3080&HUB_06] ParentGuid = USB\VID_17EF&PID_3080&HUB_20 -[DeviceInstanceId=USB\VID_17EF&PID_3080&HUB_20] +[USB\VID_17EF&PID_3080&HUB_20] ParentGuid = TBT-01081720 # Lenovo CS13 KG Dock -[DeviceInstanceId=USB\VID_17EF&PID_1010] +[USB\VID_17EF&PID_1010] Plugin = vli GType = FuVliUsbhubDevice Flags = usb2,usb3 # Lenovo CS13 GD Dock -[DeviceInstanceId=USB\VID_17EF&PID_1012] +[USB\VID_17EF&PID_1012] Plugin = vli GType = FuVliUsbhubDevice Flags = usb2,usb3 # Lenovo CS13 MO Dock -[DeviceInstanceId=USB\VID_17EF&PID_1013] +[USB\VID_17EF&PID_1013] Plugin = vli GType = FuVliUsbhubDevice Flags = usb2,usb3 # Lenovo USB3 Ultra Dock -[DeviceInstanceId=USB\VID_17EF&PID_1014] +[USB\VID_17EF&PID_1014] Plugin = vli GType = FuVliUsbhubDevice Flags = usb2,usb3 -[DeviceInstanceId=USB\VID_17EF&PID_1015] +[USB\VID_17EF&PID_1015] Plugin = vli GType = FuVliUsbhubDevice Flags = usb2,usb3 ParentGuid = USB\VID_17EF&PID_1014 # Lenovo USB3 Pro Dock -[DeviceInstanceId=USB\VID_17EF&PID_1016] +[USB\VID_17EF&PID_1016] Plugin = vli GType = FuVliUsbhubDevice Flags = usb2,usb3 -[DeviceInstanceId=USB\VID_17EF&PID_1018] +[USB\VID_17EF&PID_1018] Plugin = vli GType = FuVliUsbhubDevice Flags = usb2,usb3 ParentGuid = USB\VID_17EF&PID_1016 # Lenovo Workstation D40 -[DeviceInstanceId=USB\VID_17EF&PID_1033] +[USB\VID_17EF&PID_1033] Plugin = vli GType = FuVliUsbhubDevice Flags = usb2,usb3 # Lenovo Workstation S40 -[DeviceInstanceId=USB\VID_17EF&PID_1034] +[USB\VID_17EF&PID_1034] Plugin = vli GType = FuVliUsbhubDevice Flags = usb2,usb3 # Lenovo Workstation v40 -[DeviceInstanceId=USB\VID_17EF&PID_1035] +[USB\VID_17EF&PID_1035] Plugin = vli GType = FuVliUsbhubDevice Flags = usb2,usb3 # Lenovo One Link Plus -[DeviceInstanceId=USB\VID_17EF&PID_1018] +[USB\VID_17EF&PID_1018] Plugin = vli GType = FuVliUsbhubDevice Flags = usb2,usb3 -[DeviceInstanceId=USB\VID_17EF&PID_1019] +[USB\VID_17EF&PID_1019] Plugin = vli GType = FuVliUsbhubDevice Flags = usb2,usb3 ParentGuid = USB\VID_17EF&PID_1018 # Lenovo Hybrid dock -[DeviceInstanceId=USB\VID_17EF&PID_A356] +[USB\VID_17EF&PID_A356] Plugin = vli GType = FuVliUsbhubDevice Flags = usb3 CounterpartGuid = USB\VID_17EF&PID_1028 -[DeviceInstanceId=USB\VID_17EF&PID_1028] +[USB\VID_17EF&PID_1028] Plugin = vli GType = FuVliUsbhubDevice Flags = usb2 -[DeviceInstanceId=USB\VID_17EF&PID_A357] +[USB\VID_17EF&PID_A357] Plugin = vli GType = FuVliUsbhubDevice Flags = usb3 ParentGuid = USB\VID_17EF&PID_A356 CounterpartGuid = USB\VID_17EF&PID_1029 -[DeviceInstanceId=USB\VID_17EF&PID_1029] +[USB\VID_17EF&PID_1029] Plugin = vli GType = FuVliUsbhubDevice Flags = usb2 ParentGuid = USB\VID_17EF&PID_1028 # Lenovo Travel hub -[DeviceInstanceId=USB\VID_17EF&PID_7216] +[USB\VID_17EF&PID_7216] Plugin = vli GType = FuVliUsbhubDevice Flags = usb3 CounterpartGuid = USB\VID_17EF&PID_7224 -[DeviceInstanceId=USB\VID_17EF&PID_7224] +[USB\VID_17EF&PID_7224] Plugin = vli GType = FuVliUsbhubDevice Flags = usb2 +ParentGuid = USB\VID_17EF&PID_7216 # Lenovo Travel hub Gen2 -[DeviceInstanceId=USB\VID_17EF&PID_721D] +[USB\VID_17EF&PID_721D] Plugin = vli GType = FuVliUsbhubDevice Flags = usb3,has-shared-spi-pd CounterpartGuid = USB\VID_17EF&PID_7225 -[DeviceInstanceId=USB\VID_17EF&PID_7225] +[USB\VID_17EF&PID_7225] +Plugin = vli +GType = FuVliUsbhubDevice +Flags = usb2 +ParentGuid = USB\VID_17EF&PID_721D +[USB\VID_17EF&PID_721C] Plugin = vli GType = FuVliUsbhubDevice -Flags = usb2,has-shared-spi-pd +Flags = has-rtd21xx +ParentGuid = USB\VID_17EF&PID_721D +[USB\VID_17EF&PID_721C&I2C_REALTEK] +Name = RTD2181S # Lenovo USB-C Mini dock -[DeviceInstanceId=USB\VID_17EF&PID_3094] +[USB\VID_17EF&PID_3094] Plugin = vli GType = FuVliUsbhubDevice Flags = usb3,has-shared-spi-pd,attach-with-gpiob CounterpartGuid = USB\VID_17EF&PID_3095 -[DeviceInstanceId=USB\VID_17EF&PID_3095] +[USB\VID_17EF&PID_3095] Plugin = vli GType = FuVliUsbhubDevice Flags = usb2,attach-with-gpiob ParentGuid = USB\VID_17EF&PID_3094 -[DeviceInstanceId=USB\VID_17EF&PID_3097] +[USB\VID_17EF&PID_3097] Plugin = vli GType = FuVliUsbhubDevice Flags = usb2 ParentGuid = USB\VID_17EF&PID_3094 -[DeviceInstanceId=USB\VID_17EF&PID_721C&APP_26] +[USB\VID_17EF&PID_3093] +Plugin = vli +GType = FuVliUsbhubDevice +Flags = has-rtd21xx +ParentGuid = USB\VID_17EF&PID_3094 +[USB\VID_17EF&PID_3093&I2C_REALTEK] +Name = RTD2181S +[USB\VID_17EF&PID_721C&APP_26] ProxyGuid = USB\VID_17EF&PID_3094 FirmwareSize = 0x8000 # Lenovo Travel Hub 1in3 -[DeviceInstanceId=USB\VID_17EF&PID_7228] +[USB\VID_17EF&PID_7228] Plugin = vli GType = FuVliUsbhubDevice Flags = usb3 CounterpartGuid = USB\VID_17EF -[DeviceInstanceId=USB\VID_17EF&PID_7226] +[USB\VID_17EF&PID_7226] Plugin = vli GType = FuVliUsbhubDevice Flags = usb2 +ParentGuid = USB\VID_17EF&PID_7228 # Lenovo USB-C 7-in-1 Hub -[DeviceInstanceId=USB\VID_17EF&PID_722A] +[USB\VID_17EF&PID_722A] Plugin = vli GType = FuVliUsbhubDevice Flags = usb3,has-shared-spi-pd CounterpartGuid = USB\VID_17EF&PID_7229 -[DeviceInstanceId=USB\VID_17EF&PID_7229] +[USB\VID_17EF&PID_7229] Plugin = vli GType = FuVliUsbhubDevice -Flags = usb2,has-shared-spi-pd +Flags = usb2 +ParentGuid = USB\VID_17EF&PID_722A # Lenovo USB-C to 4 USB-A Hub -[DeviceInstanceId=USB\VID_17EF&PID_1039] +[USB\VID_17EF&PID_1039] Plugin = vli GType = FuVliUsbhubDevice Flags = usb3,has-shared-spi-pd,attach-with-gpiob CounterpartGuid = USB\VID_17EF&PID_103A -[DeviceInstanceId=USB\VID_17EF&PID_103A] +[USB\VID_17EF&PID_103A] Plugin = vli GType = FuVliUsbhubDevice -Flags = usb2,has-shared-spi-pd,attach-with-gpiob +Flags = usb2 +ParentGuid = USB\VID_17EF&PID_1039 # Lenovo Gen2 dock -[DeviceInstanceId=USB\VID_17EF&PID_A391] +[USB\VID_17EF&PID_A391] Plugin = vli GType = FuVliUsbhubDevice Flags = usb3 CounterpartGuid = USB\VID_17EF&PID_A392 -[DeviceInstanceId=USB\VID_17EF&PID_A392] +[USB\VID_17EF&PID_A392] Plugin = vli GType = FuVliUsbhubDevice Flags = usb2 ParentGuid = USB\VID_17EF&PID_A391 -[DeviceInstanceId=USB\VID_17EF&PID_A393] +[USB\VID_17EF&PID_A393] Plugin = vli GType = FuVliUsbhubDevice Flags = usb3 ParentGuid = USB\VID_17EF&PID_A391 CounterpartGuid = USB\VID_17EF&PID_A394 -[DeviceInstanceId=USB\VID_17EF&PID_A394] +[USB\VID_17EF&PID_A394] Plugin = vli GType = FuVliUsbhubDevice Flags = usb2 ParentGuid = USB\VID_17EF&PID_A392 -[DeviceInstanceId=USB\VID_17EF&PID_A395] +[USB\VID_17EF&PID_A395] Plugin = vli GType = FuVliUsbhubDevice # Lenovo Modularized dock (with VIA USB PID?!) -[DeviceInstanceId=USB\VID_2109&PID_1822] +[USB\VID_2109&PID_1822] Plugin = vli GType = FuVliUsbhubDevice Flags = usb3 CounterpartGuid = USB\VID_2109&PID_2822 -[DeviceInstanceId=USB\VID_2109&PID_2822] +[USB\VID_2109&PID_2822] Plugin = vli GType = FuVliUsbhubDevice Flags = usb2 -[DeviceInstanceId=USB\VID_2109&PID_3822] +[USB\VID_2109&PID_3822] Plugin = vli GType = FuVliUsbhubDevice Flags = usb3 ParentGuid = USB\VID_2109&PID_1822 CounterpartGuid = USB\VID_2109&PID_4822 -[DeviceInstanceId=USB\VID_2109&PID_4822] +[USB\VID_2109&PID_4822] Plugin = vli GType = FuVliUsbhubDevice Flags = usb2 ParentGuid = USB\VID_2109&PID_2822 - -# Lenovo Powered Hub -[DeviceInstanceId=USB\VID_17EF&PID_721C] -Plugin = vli -GType = FuVliUsbhubDevice -Flags = usb2 diff -Nru fwupd-1.4.5/plugins/vli/vli-usbhub.quirk fwupd-1.5.8/plugins/vli/vli-usbhub.quirk --- fwupd-1.4.5/plugins/vli/vli-usbhub.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/vli/vli-usbhub.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,133 +1,133 @@ # 3470_Class -[DeviceInstanceId=USB\VID_2109&PID_0810] +[USB\VID_2109&PID_0810] Plugin = vli GType = FuVliUsbhubDevice -[DeviceInstanceId=USB\VID_2109&PID_0811] +[USB\VID_2109&PID_0811] Plugin = vli GType = FuVliUsbhubDevice -[DeviceInstanceId=USB\VID_2109&PID_0812] +[USB\VID_2109&PID_0812] Plugin = vli GType = FuVliUsbhubDevice -[DeviceInstanceId=USB\VID_2109&PID_0813] +[USB\VID_2109&PID_0813] Plugin = vli GType = FuVliUsbhubDevice Flags = needs-unlock-legacy813 -[DeviceInstanceId=USB\VID_2109&PID_8110] +[USB\VID_2109&PID_8110] Plugin = vli GType = FuVliUsbhubDevice -[DeviceInstanceId=USB\VID_2109&PID_8113] +[USB\VID_2109&PID_8113] Plugin = vli GType = FuVliUsbhubDevice # 3507_Class -[DeviceInstanceId=USB\VID_2109&PID_0210] +[USB\VID_2109&PID_0210] Plugin = vli GType = FuVliUsbhubDevice # 3545_Class -[DeviceInstanceId=USB\VID_2109&PID_0211] +[USB\VID_2109&PID_0211] Plugin = vli GType = FuVliUsbhubDevice -[DeviceInstanceId=USB\VID_2109&PID_2211] +[USB\VID_2109&PID_2211] Plugin = vli GType = FuVliUsbhubDevice -[DeviceInstanceId=USB\VID_2109&PID_0212] +[USB\VID_2109&PID_0212] Plugin = vli GType = FuVliUsbhubDevice -[DeviceInstanceId=USB\VID_2109&PID_2212] +[USB\VID_2109&PID_2212] Plugin = vli GType = FuVliUsbhubDevice # VL817 -[DeviceInstanceId=USB\VID_2109&PID_0817] +[USB\VID_2109&PID_0817] Plugin = vli GType = FuVliUsbhubDevice Flags = usb3 -[DeviceInstanceId=USB\VID_2109&PID_2817] +[USB\VID_2109&PID_2817] Plugin = vli GType = FuVliUsbhubDevice Flags = usb2 # VL820 -[DeviceInstanceId=USB\VID_2109&PID_0820] +[USB\VID_2109&PID_0820] Plugin = vli GType = FuVliUsbhubDevice Flags = usb3,has-shared-spi-pd -[DeviceInstanceId=USB\VID_2109&PID_2820] +[USB\VID_2109&PID_2820] Plugin = vli GType = FuVliUsbhubDevice Flags = usb2,has-shared-spi-pd # A25Lxxx -[Guid=VLI_USBHUB\\SPI_3730] -SpiCmdChipErase = 0xc7 -SpiCmdSectorErase = 0x20 +[VLI_USBHUB\\SPI_3730] +VliSpiCmdChipErase = 0xc7 +VliSpiCmdSectorErase = 0x20 # AT25F512A/B -[Guid=VLI_USBHUB\\SPI_1F65] -# SpiCmdReadId = 0x15 -SpiCmdChipErase = 0x62 -SpiCmdSectorErase = 0x00 +[VLI_USBHUB\\SPI_1F65] +# VliSpiCmdReadId = 0x15 +VliSpiCmdChipErase = 0x62 +VliSpiCmdSectorErase = 0x00 # EN25Fxx -[Guid=VLI_USBHUB\\SPI_1C31] -SpiCmdChipErase = 0x60 -SpiCmdSectorErase = 0x20 +[VLI_USBHUB\\SPI_1C31] +VliSpiCmdChipErase = 0x60 +VliSpiCmdSectorErase = 0x20 # GD25Qxxx -[Guid=VLI_USBHUB\SPI_C840] -SpiCmdChipErase = 0xC7 -SpiCmdSectorErase = 0x20 +[VLI_USBHUB\SPI_C840] +VliSpiCmdChipErase = 0xC7 +VliSpiCmdSectorErase = 0x20 # M25PxxA/xx -[Guid=VLI_USBHUB\\SPI_0020] -SpiCmdChipErase = 0xC7 -SpiCmdSectorErase = 0x00 +[VLI_USBHUB\\SPI_0020] +VliSpiCmdChipErase = 0xC7 +VliSpiCmdSectorErase = 0x00 # MX25Lxxx/xxxC/xxxE -[Guid=VLI_USBHUB\\SPI_C220] -SpiCmdChipErase = 0x60 -SpiCmdSectorErase = 0x20 +[VLI_USBHUB\\SPI_C220] +VliSpiCmdChipErase = 0x60 +VliSpiCmdSectorErase = 0x20 # MX25Lxxx1E -[Guid=VLI_USBHUB\\SPI_C222] -SpiCmdChipErase = 0x60 -SpiCmdSectorErase = 0x20 +[VLI_USBHUB\\SPI_C222] +VliSpiCmdChipErase = 0x60 +VliSpiCmdSectorErase = 0x20 # PCT/SST25VFxxx/xxxA -[Guid=VLI_USBHUB\\SPI_00BF] -# SpiCmdReadId = 0x90 -SpiCmdChipErase = 0x60 -SpiCmdSectorErase = 0x20 +[VLI_USBHUB\\SPI_00BF] +# VliSpiCmdReadId = 0x90 +VliSpiCmdChipErase = 0x60 +VliSpiCmdSectorErase = 0x20 # PM25LDxxx -[Guid=VLI_USBHUB\\SPI_009D] -# SpiCmdReadId = 0x90 -SpiCmdChipErase = 0xC7 -SpiCmdSectorErase = 0xD7 +[VLI_USBHUB\\SPI_009D] +# VliSpiCmdReadId = 0x90 +VliSpiCmdChipErase = 0xC7 +VliSpiCmdSectorErase = 0xD7 # PM25LVxxx -[Guid=VLI_USBHUB\\SPI_009D] -# SpiCmdReadId = 0xAB -SpiCmdChipErase = 0xC7 -SpiCmdSectorErase = 0xD7 +[VLI_USBHUB\\SPI_009D] +# VliSpiCmdReadId = 0xAB +VliSpiCmdChipErase = 0xC7 +VliSpiCmdSectorErase = 0xD7 # W25XxxBV/W25XxxCL -[Guid=VLI_USBHUB\\SPI_00EF] -SpiCmdChipErase = 0xC7 -SpiCmdSectorErase = 0x20 +[VLI_USBHUB\\SPI_00EF] +VliSpiCmdChipErase = 0xC7 +VliSpiCmdSectorErase = 0x20 # FM25Fxxx -#[Guid=VLI_USBHUB\\SPI_XXXX] -#SpiCmdChipErase = 0xC7 -#SpiCmdSectorErase = 0x20 +#[VLI_USBHUB\\SPI_XXXX] +#VliSpiCmdChipErase = 0xC7 +#VliSpiCmdSectorErase = 0x20 # KH25LxxxxE -#[Guid=VLI_USBHUB\\SPI_XXXX] -#SpiCmdChipErase = 0x60 -#SpiCmdSectorErase = 0x20 +#[VLI_USBHUB\\SPI_XXXX] +#VliSpiCmdChipErase = 0x60 +#VliSpiCmdSectorErase = 0x20 # MX25Vxxx -#[Guid=VLI_USBHUB\\SPI_XXXX] -#SpiCmdChipErase = 0x60 -#SpiCmdSectorErase = 0x20 +#[VLI_USBHUB\\SPI_XXXX] +#VliSpiCmdChipErase = 0x60 +#VliSpiCmdSectorErase = 0x20 diff -Nru fwupd-1.4.5/plugins/wacom-raw/fu-plugin-wacom-raw.c fwupd-1.5.8/plugins/wacom-raw/fu-plugin-wacom-raw.c --- fwupd-1.4.5/plugins/wacom-raw/fu-plugin-wacom-raw.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/wacom-raw/fu-plugin-wacom-raw.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2019 Richard Hughes + * Copyright (C) 2018 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -7,7 +7,6 @@ #include "config.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #include "fu-wacom-aes-device.h" #include "fu-wacom-emr-device.h" #include "fu-wacom-common.h" @@ -17,6 +16,9 @@ { fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_udev_subsystem (plugin, "hidraw"); + fu_plugin_add_possible_quirk_key (plugin, "WacomI2cFlashBlockSize"); + fu_plugin_add_possible_quirk_key (plugin, "WacomI2cFlashBaseAddr"); + fu_plugin_add_possible_quirk_key (plugin, "WacomI2cFlashSize"); /* register the custom types */ g_type_ensure (FU_TYPE_WACOM_AES_DEVICE); diff -Nru fwupd-1.4.5/plugins/wacom-raw/fu-wacom-aes-device.c fwupd-1.5.8/plugins/wacom-raw/fu-wacom-aes-device.c --- fwupd-1.4.5/plugins/wacom-raw/fu-wacom-aes-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/wacom-raw/fu-wacom-aes-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2019 Richard Hughes + * Copyright (C) 2018 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -130,7 +130,7 @@ if (!fu_wacom_aes_add_recovery_hwid (device, &error_local)) g_debug ("failed to get HwID: %s", error_local->message); } else { - guint32 fw_ver; + guint16 fw_ver; guint8 data[FU_WACOM_RAW_STATUS_REPORT_SZ] = { FU_WACOM_RAW_STATUS_REPORT_ID, 0x0 @@ -140,7 +140,9 @@ if (!fu_wacom_device_get_feature (FU_WACOM_DEVICE (self), data, sizeof(data), error)) return FALSE; - fw_ver = fu_common_read_uint16 (data + 11, G_LITTLE_ENDIAN); + if (!fu_common_read_uint16_safe (data, sizeof(data), 11, + &fw_ver, G_LITTLE_ENDIAN, error)) + return FALSE; version = g_strdup_printf ("%04x.%02x", fw_ver, data[13]); fu_device_set_version (device, version); } @@ -164,7 +166,7 @@ g_prefix_error (error, "failed to send eraseall command: "); return FALSE; } - g_usleep (2 * G_USEC_PER_SEC); + fu_device_sleep_with_progress (FU_DEVICE (self), 2); /* seconds */ return TRUE; } @@ -221,10 +223,10 @@ for (guint i = 0; i < chunks->len; i++) { FuChunk *chk = g_ptr_array_index (chunks, i); if (!fu_wacom_aes_device_write_block (self, - chk->idx, - chk->address, - chk->data, - chk->data_sz, + fu_chunk_get_idx (chk), + fu_chunk_get_address (chk), + fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk), error)) return FALSE; fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len); diff -Nru fwupd-1.4.5/plugins/wacom-raw/fu-wacom-aes-device.h fwupd-1.5.8/plugins/wacom-raw/fu-wacom-aes-device.h --- fwupd-1.4.5/plugins/wacom-raw/fu-wacom-aes-device.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/wacom-raw/fu-wacom-aes-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2019 Richard Hughes + * Copyright (C) 2018 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/wacom-raw/fu-wacom-common.c fwupd-1.5.8/plugins/wacom-raw/fu-wacom-common.c --- fwupd-1.4.5/plugins/wacom-raw/fu-wacom-common.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/wacom-raw/fu-wacom-common.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2019 Richard Hughes + * Copyright (C) 2018 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/wacom-raw/fu-wacom-common.h fwupd-1.5.8/plugins/wacom-raw/fu-wacom-common.h --- fwupd-1.4.5/plugins/wacom-raw/fu-wacom-common.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/wacom-raw/fu-wacom-common.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2019 Richard Hughes + * Copyright (C) 2018 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/wacom-raw/fu-wacom-device.c fwupd-1.5.8/plugins/wacom-raw/fu-wacom-device.c --- fwupd-1.4.5/plugins/wacom-raw/fu-wacom-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/wacom-raw/fu-wacom-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2019 Richard Hughes + * Copyright (C) 2018 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -30,6 +30,10 @@ { FuWacomDevice *self = FU_WACOM_DEVICE (device); FuWacomDevicePrivate *priv = GET_PRIVATE (self); + + /* FuUdevDevice->to_string */ + FU_DEVICE_CLASS (fu_wacom_device_parent_class)->to_string (device, idt, str); + fu_common_string_append_kx (str, idt, "FlashBlockSize", priv->flash_block_size); fu_common_string_append_kx (str, idt, "FlashBaseAddr", priv->flash_base_addr); fu_common_string_append_kx (str, idt, "FlashSize", priv->flash_size); @@ -90,12 +94,14 @@ } static gboolean -fu_wacom_device_probe (FuUdevDevice *device, GError **error) +fu_wacom_device_probe (FuDevice *device, GError **error) { - /* set the physical ID */ - if (!fu_udev_device_set_physical_id (device, "hid", error)) + /* FuUdevDevice->probe */ + if (!FU_DEVICE_CLASS (fu_wacom_device_parent_class)->probe (device, error)) return FALSE; - return TRUE; + + /* set the physical ID */ + return fu_udev_device_set_physical_id (FU_UDEV_DEVICE (device), "hid", error); } static gboolean @@ -351,9 +357,10 @@ static void fu_wacom_device_init (FuWacomDevice *self) { - fu_device_set_protocol (FU_DEVICE (self), "com.wacom.raw"); + fu_device_add_protocol (FU_DEVICE (self), "com.wacom.raw"); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL); + fu_device_add_internal_flag (FU_DEVICE (self), FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_PAIR); } @@ -361,12 +368,11 @@ fu_wacom_device_class_init (FuWacomDeviceClass *klass) { FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - FuUdevDeviceClass *klass_device_udev = FU_UDEV_DEVICE_CLASS (klass); klass_device->to_string = fu_wacom_device_to_string; klass_device->prepare_firmware = fu_wacom_device_prepare_firmware; klass_device->write_firmware = fu_wacom_device_write_firmware; klass_device->attach = fu_wacom_device_attach; klass_device->detach = fu_wacom_device_detach; klass_device->set_quirk_kv = fu_wacom_device_set_quirk_kv; - klass_device_udev->probe = fu_wacom_device_probe; + klass_device->probe = fu_wacom_device_probe; } diff -Nru fwupd-1.4.5/plugins/wacom-raw/fu-wacom-device.h fwupd-1.5.8/plugins/wacom-raw/fu-wacom-device.h --- fwupd-1.4.5/plugins/wacom-raw/fu-wacom-device.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/wacom-raw/fu-wacom-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2019 Richard Hughes + * Copyright (C) 2018 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/wacom-raw/fu-wacom-emr-device.c fwupd-1.5.8/plugins/wacom-raw/fu-wacom-emr-device.c --- fwupd-1.4.5/plugins/wacom-raw/fu-wacom-emr-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/wacom-raw/fu-wacom-emr-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2019 Richard Hughes + * Copyright (C) 2018 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -38,7 +38,9 @@ if (!fu_wacom_device_get_feature (FU_WACOM_DEVICE (self), data, sizeof(data), error)) return FALSE; - fw_ver = fu_common_read_uint16 (data + 11, G_LITTLE_ENDIAN); + if (!fu_common_read_uint16_safe (data, sizeof(data), 11, + &fw_ver, G_LITTLE_ENDIAN, error)) + return FALSE; fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER); version = fu_common_version_from_uint16 (fw_ver, FWUPD_VERSION_FORMAT_PAIR); fu_device_set_version (device, version); @@ -122,7 +124,7 @@ return FALSE; } if (!fu_wacom_common_rc_set_error (&rsp, error)) { - g_prefix_error (error, "failed to erase"); + g_prefix_error (error, "failed to erase: "); return FALSE; } g_usleep (50); @@ -207,13 +209,13 @@ fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); for (guint i = 0; i < chunks->len; i++) { FuChunk *chk = g_ptr_array_index (chunks, i); - if (fu_wacom_common_block_is_empty (chk->data, chk->data_sz)) + if (fu_wacom_common_block_is_empty (fu_chunk_get_data (chk), fu_chunk_get_data_sz (chk))) continue; if (!fu_wacom_emr_device_write_block (self, - chk->idx, - chk->address, - chk->data, - chk->data_sz, + fu_chunk_get_idx (chk), + fu_chunk_get_address (chk), + fu_chunk_get_data (chk), + fu_chunk_get_data_sz (chk), error)) return FALSE; fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len); diff -Nru fwupd-1.4.5/plugins/wacom-raw/fu-wacom-emr-device.h fwupd-1.5.8/plugins/wacom-raw/fu-wacom-emr-device.h --- fwupd-1.4.5/plugins/wacom-raw/fu-wacom-emr-device.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/wacom-raw/fu-wacom-emr-device.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2019 Richard Hughes + * Copyright (C) 2018 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/wacom-raw/meson.build fwupd-1.5.8/plugins/wacom-raw/meson.build --- fwupd-1.4.5/plugins/wacom-raw/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/wacom-raw/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,4 @@ +if get_option('gudev') cargs = ['-DG_LOG_DOMAIN="FuPluginWacomRaw"'] install_data(['wacom-raw.quirk'], @@ -29,3 +30,4 @@ fwupdplugin, ], ) +endif diff -Nru fwupd-1.4.5/plugins/wacom-raw/README.md fwupd-1.5.8/plugins/wacom-raw/README.md --- fwupd-1.4.5/plugins/wacom-raw/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/wacom-raw/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -32,7 +32,21 @@ | `WacomI2cFlashBaseAddr` | Base address for firmware | 1.2.4 | | `WacomI2cFlashSize` | Maximum size of the firmware zone | 1.2.4 | +Update Behavior +--------------- + +The device usually presents in runtime mode, but on detach re-enumerates with a +different HIDRAW PID in a bootloader mode. On attach the device re-enumerates +back to the runtime mode. + +For this reason the `REPLUG_MATCH_GUID` internal device flag is used so that +the bootloader and runtime modes are treated as the same device. + Vendor ID Security ------------------ The vendor ID is set from the udev vendor, in this instance set to `HIDRAW:0x056A` + +External interface access +------------------------- +This plugin requires ioctl `HIDIOCSFEATURE` access. diff -Nru fwupd-1.4.5/plugins/wacom-raw/wacom-raw.quirk fwupd-1.5.8/plugins/wacom-raw/wacom-raw.quirk --- fwupd-1.4.5/plugins/wacom-raw/wacom-raw.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/wacom-raw/wacom-raw.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -3,104 +3,104 @@ # constants are set correctly. # Dell Chromebook Enterprise 5300 -[DeviceInstanceId=HIDRAW\VEN_2D1F&DEV_4946] +[HIDRAW\VEN_2D1F&DEV_4946] Plugin = wacom_raw Guid = WacomAES # Moffet 14-LGD-TPK -[DeviceInstanceId=HIDRAW\VEN_2D1F&DEV_4970] +[HIDRAW\VEN_2D1F&DEV_4970] Plugin = wacom_raw Guid = WacomAES Flags = self-recovery # Moffet 14-Sharp-HH -[DeviceInstanceId=HIDRAW\VEN_2D1F&DEV_4971] +[HIDRAW\VEN_2D1F&DEV_4971] Plugin = wacom_raw Guid = WacomAES Flags = self-recovery # Moffet 14-Sharp-VIA -[DeviceInstanceId=HIDRAW\VEN_2D1F&DEV_4972] +[HIDRAW\VEN_2D1F&DEV_4972] Plugin = wacom_raw Guid = WacomAES Flags = self-recovery # Dell Latitude 5175 -[DeviceInstanceId=HIDRAW\VEN_056A&DEV_4807] +[HIDRAW\VEN_056A&DEV_4807] Plugin = wacom_raw Guid = WacomAES # Dell XPS 12 9250 -[DeviceInstanceId=HIDRAW\VEN_056A&DEV_4822] +[HIDRAW\VEN_056A&DEV_4822] Plugin = wacom_raw Guid = WacomAES # Dell Venue 8 Pro 5855 -[DeviceInstanceId=HIDRAW\VEN_056A&DEV_4824] +[HIDRAW\VEN_056A&DEV_4824] Plugin = wacom_raw Guid = WacomAES # Dell XPS 13 9365 -[DeviceInstanceId=HIDRAW\VEN_056A&DEV_4831] +[HIDRAW\VEN_056A&DEV_4831] Plugin = wacom_raw Guid = WacomAES # Dell Latitude 5285 -[DeviceInstanceId=HIDRAW\VEN_056A&DEV_484C] +[HIDRAW\VEN_056A&DEV_484C] Plugin = wacom_raw Guid = WacomAES # Dell Latitude 7390 2-in-1 -[DeviceInstanceId=HIDRAW\VEN_056A&DEV_4841] +[HIDRAW\VEN_056A&DEV_4841] Plugin = wacom_raw Guid = WacomAES # Dell XPS-15 9575 -[DeviceInstanceId=HIDRAW\VEN_056A&DEV_4875] +[HIDRAW\VEN_056A&DEV_4875] Plugin = wacom_raw Guid = WacomAES # Dell Latitude 7400 2-in-1 -[DeviceInstanceId=HIDRAW\VEN_056A&DEV_48C9] +[HIDRAW\VEN_056A&DEV_48C9] Plugin = wacom_raw Guid = WacomAES # Dell XPS-15 9570 -[DeviceInstanceId=HIDRAW\VEN_056A&DEV_488F] +[HIDRAW\VEN_056A&DEV_488F] Plugin = wacom_raw Guid = WacomAES # Dell XPS 13 7390 2-in-1 -[DeviceInstanceId=HIDRAW\VEN_056A&DEV_48ED] +[HIDRAW\VEN_056A&DEV_48ED] Plugin = wacom_raw Guid = WacomAES # AES bootloader mode -[DeviceInstanceId=HIDRAW\VEN_056A&DEV_0094] +[HIDRAW\VEN_056A&DEV_0094] Plugin = wacom_raw Guid = WacomAES Flags = is-bootloader # EMR bootloader mode -[DeviceInstanceId=HIDRAW\VEN_056A&DEV_012B] +[HIDRAW\VEN_056A&DEV_012B] Plugin = wacom_raw Guid = WacomEMR Flags = is-bootloader -[Guid=WacomEMR_W9013] +[WacomEMR_W9013] WacomI2cFlashBlockSize=64 WacomI2cFlashBaseAddr=0x2000 WacomI2cFlashSize=0x1e000 -[Guid=WacomEMR_W9021] +[WacomEMR_W9021] WacomI2cFlashBlockSize=256 WacomI2cFlashBaseAddr=0x3000 WacomI2cFlashSize=0x3c000 -[Guid=WacomEMR] +[WacomEMR] GType=FuWacomEmrDevice -[Guid=WacomAES] +[WacomAES] GType=FuWacomAesDevice WacomI2cFlashBlockSize=128 WacomI2cFlashBaseAddr=0x8000 diff -Nru fwupd-1.4.5/plugins/wacom-usb/fu-plugin-wacom-usb.c fwupd-1.5.8/plugins/wacom-usb/fu-plugin-wacom-usb.c --- fwupd-1.4.5/plugins/wacom-usb/fu-plugin-wacom-usb.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/wacom-usb/fu-plugin-wacom-usb.c 2021-03-31 20:08:32.000000000 +0000 @@ -7,7 +7,6 @@ #include "config.h" #include "fu-plugin-vfuncs.h" -#include "fu-hash.h" #include "fu-wac-device.h" #include "fu-wac-firmware.h" diff -Nru fwupd-1.4.5/plugins/wacom-usb/fu-self-test.c fwupd-1.5.8/plugins/wacom-usb/fu-self-test.c --- fwupd-1.4.5/plugins/wacom-usb/fu-self-test.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/wacom-usb/fu-self-test.c 2021-03-31 20:08:32.000000000 +0000 @@ -27,7 +27,7 @@ g_autoptr(GError) error = NULL; /* parse the test file */ - fn = g_build_filename (TESTDATADIR, "test.wac", NULL); + fn = g_test_build_filename (G_TEST_DIST, "tests", "test.wac", NULL); if (!g_file_test (fn, G_FILE_TEST_EXISTS)) { g_test_skip ("no data file found"); return; diff -Nru fwupd-1.4.5/plugins/wacom-usb/fu-wac-common.c fwupd-1.5.8/plugins/wacom-usb/fu-wac-common.c --- fwupd-1.4.5/plugins/wacom-usb/fu-wac-common.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/wacom-usb/fu-wac-common.c 2021-03-31 20:08:32.000000000 +0000 @@ -15,7 +15,7 @@ fu_wac_calculate_checksum32le (const guint8 *data, gsize len) { guint32 csum = 0x0; - g_return_val_if_fail (len % 4 == 0, 0xff); + g_return_val_if_fail (len % 4 == 0, G_MAXUINT32); for (guint i = 0; i < len; i += 4) { guint32 tmp; memcpy (&tmp, &data[i], sizeof(guint32)); diff -Nru fwupd-1.4.5/plugins/wacom-usb/fu-wac-device.c fwupd-1.5.8/plugins/wacom-usb/fu-wac-device.c --- fwupd-1.4.5/plugins/wacom-usb/fu-wac-device.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/wacom-usb/fu-wac-device.c 2021-03-31 20:08:32.000000000 +0000 @@ -199,9 +199,15 @@ for (guint i = 0; i < self->nr_flash_blocks; i++) { FuWacFlashDescriptor *fd = g_new0 (FuWacFlashDescriptor, 1); const guint blksz = sizeof(FuWacFlashDescriptor); - fd->start_addr = fu_common_read_uint32 (buf + (i * blksz) + 1, G_LITTLE_ENDIAN); - fd->block_sz = fu_common_read_uint32 (buf + (i * blksz) + 5, G_LITTLE_ENDIAN); - fd->write_sz = fu_common_read_uint16 (buf + (i * blksz) + 9, G_LITTLE_ENDIAN); + if (!fu_common_read_uint32_safe (buf, sz, (i * blksz) + 1, + &fd->start_addr, G_LITTLE_ENDIAN, error)) + return FALSE; + if (!fu_common_read_uint32_safe (buf, sz, (i * blksz) + 5, + &fd->block_sz, G_LITTLE_ENDIAN, error)) + return FALSE; + if (!fu_common_read_uint16_safe (buf, sz, (i * blksz) + 9, + &fd->write_sz, G_LITTLE_ENDIAN, error)) + return FALSE; g_ptr_array_add (self->flash_descriptors, fd); } g_debug ("added %u flash descriptors", self->flash_descriptors->len); @@ -435,7 +441,6 @@ GError **error) { g_autoptr(FuFirmware) firmware = fu_wac_firmware_new (); - fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); if (!fu_firmware_parse (firmware, fw, flags, error)) return NULL; return g_steal_pointer (&firmware); @@ -548,8 +553,11 @@ self->write_block_sz); for (guint j = 0; j < chunks->len; j++) { FuChunk *chk = g_ptr_array_index (chunks, j); - g_autoptr(GBytes) blob_chunk = g_bytes_new (chk->data, chk->data_sz); - if (!fu_wac_device_write_block (self, chk->address, blob_chunk, error)) + g_autoptr(GBytes) blob_chunk = fu_chunk_get_bytes (chk); + if (!fu_wac_device_write_block (self, + fu_chunk_get_address (chk), + blob_chunk, + error)) return FALSE; } @@ -756,9 +764,9 @@ } static gboolean -fu_wac_device_close (FuUsbDevice *device, GError **error) +fu_wac_device_close (FuDevice *device, GError **error) { - GUsbDevice *usb_device = fu_usb_device_get_dev (device); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); /* reattach wacom.ko */ if (!g_usb_device_release_interface (usb_device, 0x00, /* HID */ @@ -775,8 +783,8 @@ * this should let the kernel unstick itself. */ g_usleep (20 * 1000); - /* success */ - return TRUE; + /* FuUsbDevice->close */ + return FU_DEVICE_CLASS (fu_wac_device_parent_class)->close (device, error); } static gboolean @@ -794,7 +802,7 @@ self->checksums = g_array_new (FALSE, FALSE, sizeof(guint32)); self->configuration = 0xffff; self->firmware_index = 0xffff; - fu_device_set_protocol (FU_DEVICE (self), "com.wacom.usb"); + fu_device_add_protocol (FU_DEVICE (self), "com.wacom.usb"); fu_device_add_icon (FU_DEVICE (self), "input-tablet"); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_PAIR); @@ -818,12 +826,11 @@ { GObjectClass *object_class = G_OBJECT_CLASS (klass); FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); object_class->finalize = fu_wac_device_finalize; klass_device->prepare_firmware = fu_wac_device_prepare_firmware; klass_device->write_firmware = fu_wac_device_write_firmware; klass_device->to_string = fu_wac_device_to_string; klass_device->setup = fu_wac_device_setup; klass_device->cleanup = fu_wac_device_cleanup; - klass_usb_device->close = fu_wac_device_close; + klass_device->close = fu_wac_device_close; } diff -Nru fwupd-1.4.5/plugins/wacom-usb/fu-wac-firmware.c fwupd-1.5.8/plugins/wacom-usb/fu-wac-firmware.c --- fwupd-1.4.5/plugins/wacom-usb/fu-wac-firmware.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/wacom-usb/fu-wac-firmware.c 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2019 Richard Hughes + * Copyright (C) 2018 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -44,7 +44,7 @@ /* check the prefix (BE) */ data = (guint8 *) g_bytes_get_data (fw, &len); - if (memcmp (data, "WACOM", 5) != 0) { + if (len < 5 || memcmp (data, "WACOM", 5) != 0) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -62,27 +62,41 @@ /* Wacom-specific metadata */ if (g_strcmp0 (cmd, "WA") == 0) { - guint cmdlen = strlen (lines[i]); + gsize cmdlen = strlen (lines[i]); /* header info record */ - if (memcmp (lines[i] + 2, "COM", 3) == 0) { + if (cmdlen > 3 && memcmp (lines[i] + 2, "COM", 3) == 0) { guint8 header_image_cnt = 0; if (cmdlen != 40) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, - "invalid header, got %u bytes", + "invalid header, got %" G_GSIZE_FORMAT " bytes", cmdlen); return FALSE; } - header_image_cnt = fu_firmware_strparse_uint4 (lines[i] + 5); + if (!fu_firmware_strparse_uint4_safe (lines[i], + cmdlen, + 5, + &header_image_cnt, + error)) + return FALSE; for (guint j = 0; j < header_image_cnt; j++) { - FuFirmwareWacHeaderRecord *hdr = g_new0 (FuFirmwareWacHeaderRecord, 1); - hdr->addr = fu_firmware_strparse_uint32 (lines[i] + (j * 16) + 6); - hdr->sz = fu_firmware_strparse_uint32 (lines[i] + (j * 16) + 14); - g_ptr_array_add (header_infos, hdr); + g_autofree FuFirmwareWacHeaderRecord *hdr = NULL; + hdr = g_new0 (FuFirmwareWacHeaderRecord, 1); + if (!fu_firmware_strparse_uint32_safe (lines[i], cmdlen, + (j * 16) + 6, + &hdr->addr, + error)) + return FALSE; + if (!fu_firmware_strparse_uint32_safe (lines[i], cmdlen, + (j * 16) + 14, + &hdr->sz, + error)) + return FALSE; g_debug ("header_fw%u_addr: 0x%x", j, hdr->addr); g_debug ("header_fw%u_sz: 0x%x", j, hdr->sz); + g_ptr_array_add (header_infos, g_steal_pointer (&hdr)); } continue; } @@ -90,7 +104,13 @@ /* firmware headline record */ if (cmdlen == 13) { FuFirmwareWacHeaderRecord *hdr; - guint8 idx = fu_firmware_strparse_uint4 (lines[i] + 2); + guint8 idx = 0; + if (!fu_firmware_strparse_uint4_safe (lines[i], + cmdlen, + 2, + &idx, + error)) + return FALSE; if (idx == 0) { g_set_error (error, FWUPD_ERROR, @@ -108,7 +128,12 @@ return FALSE; } hdr = g_ptr_array_index (header_infos, idx - 1); - hdr->prog_start_addr = fu_firmware_strparse_uint32 (lines[i] + 3); + if (!fu_firmware_strparse_uint32_safe (lines[i], + cmdlen, + 3, + &hdr->prog_start_addr, + error)) + return FALSE; if (hdr->prog_start_addr != hdr->addr) { g_set_error (error, FWUPD_ERROR, diff -Nru fwupd-1.4.5/plugins/wacom-usb/fu-wac-firmware.h fwupd-1.5.8/plugins/wacom-usb/fu-wac-firmware.h --- fwupd-1.4.5/plugins/wacom-usb/fu-wac-firmware.h 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/wacom-usb/fu-wac-firmware.h 2021-03-31 20:08:32.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2019 Richard Hughes + * Copyright (C) 2018 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ diff -Nru fwupd-1.4.5/plugins/wacom-usb/fu-wac-module.c fwupd-1.5.8/plugins/wacom-usb/fu-wac-module.c --- fwupd-1.4.5/plugins/wacom-usb/fu-wac-module.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/wacom-usb/fu-wac-module.c 2021-03-31 20:08:32.000000000 +0000 @@ -305,7 +305,7 @@ static void fu_wac_module_init (FuWacModule *self) { - fu_device_set_protocol (FU_DEVICE (self), "com.wacom.usb"); + fu_device_add_protocol (FU_DEVICE (self), "com.wacom.usb"); fu_device_set_version_format (FU_DEVICE (self), FWUPD_VERSION_FORMAT_PAIR); fu_device_set_remove_delay (FU_DEVICE (self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); } @@ -320,7 +320,7 @@ /* set vendor ID */ vendor_id = g_strdup_printf ("USB:0x%04X", g_usb_device_get_vid (priv->usb_device)); - fu_device_set_vendor_id (FU_DEVICE (self), vendor_id); + fu_device_add_vendor_id (FU_DEVICE (self), vendor_id); /* set USB physical and logical IDs */ fu_device_set_physical_id (FU_DEVICE (self), diff -Nru fwupd-1.4.5/plugins/wacom-usb/fu-wac-module-touch.c fwupd-1.5.8/plugins/wacom-usb/fu-wac-module-touch.c --- fwupd-1.4.5/plugins/wacom-usb/fu-wac-module-touch.c 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/wacom-usb/fu-wac-module-touch.c 2021-03-31 20:08:32.000000000 +0000 @@ -80,14 +80,14 @@ /* build G11T data packet */ memset (buf, 0xff, sizeof(buf)); buf[0] = 0x01; /* writing */ - buf[1] = chk->idx + 1; - fu_common_write_uint32 (&buf[2], chk->address, G_LITTLE_ENDIAN); + buf[1] = fu_chunk_get_idx (chk) + 1; + fu_common_write_uint32 (&buf[2], fu_chunk_get_address (chk), G_LITTLE_ENDIAN); buf[6] = 0x10; /* no idea! */ - memcpy (&buf[7], chk->data, chk->data_sz); + memcpy (&buf[7], fu_chunk_get_data (chk), fu_chunk_get_data_sz (chk)); blob_chunk = g_bytes_new (buf, sizeof(buf)); if (!fu_wac_module_set_feature (self, FU_WAC_MODULE_COMMAND_DATA, blob_chunk, error)) { - g_prefix_error (error, "failed to write block %u: ", chk->idx); + g_prefix_error (error, "failed to write block %u: ", fu_chunk_get_idx (chk)); return FALSE; } diff -Nru fwupd-1.4.5/plugins/wacom-usb/meson.build fwupd-1.5.8/plugins/wacom-usb/meson.build --- fwupd-1.4.5/plugins/wacom-usb/meson.build 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/wacom-usb/meson.build 2021-03-31 20:08:32.000000000 +0000 @@ -1,3 +1,4 @@ +if get_option('gusb') cargs = ['-DG_LOG_DOMAIN="FuPluginWacomUsb"'] install_data(['wacom-usb.quirk'], @@ -9,7 +10,7 @@ sources : [ 'fu-wac-common.c', 'fu-wac-device.c', - 'fu-wac-firmware.c', + 'fu-wac-firmware.c', # fuzzing 'fu-wac-module.c', 'fu-wac-module-bluetooth.c', 'fu-wac-module-touch.c', @@ -33,8 +34,9 @@ ) if get_option('tests') - testdatadir = join_paths(meson.current_source_dir(), 'tests') - cargs += '-DTESTDATADIR="' + testdatadir + '"' + testdatadirs = environment() + testdatadirs.set('G_TEST_SRCDIR', meson.current_source_dir()) + testdatadirs.set('G_TEST_BUILDDIR', meson.current_build_dir()) e = executable( 'wacom-usb-self-test', fu_hash, @@ -59,7 +61,10 @@ fwupd, fwupdplugin, ], - c_args : cargs + c_args : cargs, + install : true, + install_dir : installed_test_bindir, ) - test('wacom-usb-self-test', e) + test('wacom-usb-self-test', e, env : testdatadirs) # added to installed-tests +endif endif diff -Nru fwupd-1.4.5/plugins/wacom-usb/README.md fwupd-1.5.8/plugins/wacom-usb/README.md --- fwupd-1.4.5/plugins/wacom-usb/README.md 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/wacom-usb/README.md 2021-03-31 20:08:32.000000000 +0000 @@ -9,7 +9,7 @@ From 2016 Wacom has been using a HID-based proprietary flashing algorithm which has been documented by support team at Wacom and provided under NDA under the -understanding it would be used to build a plugin under a LGPLv2+ licence. +understanding it would be used to build a plugin under a LGPLv2+ license. Wacom devices are actually composite devices, with the main ARM CPU being programmed using a more complicated erase, write, verify algorithm based @@ -40,7 +40,17 @@ * `USB\VID_056A&PID_0378` * `USB\VID_056A` +Update Behavior +--------------- + +The firmware is deployed when the device is in normal runtime mode, and the +device will reset when the new firmware has been written. + Vendor ID Security ------------------ The vendor ID is set from the USB vendor, for example set to `USB:0x056A` + +External interface access +------------------------- +This plugin requires read/write access to `/dev/bus/usb`. diff -Nru fwupd-1.4.5/plugins/wacom-usb/wacom-usb.quirk fwupd-1.5.8/plugins/wacom-usb/wacom-usb.quirk --- fwupd-1.4.5/plugins/wacom-usb/wacom-usb.quirk 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/plugins/wacom-usb/wacom-usb.quirk 2021-03-31 20:08:32.000000000 +0000 @@ -1,34 +1,34 @@ # Intuos Pro medium (2nd-gen USB) [PTH-660] -[DeviceInstanceId=USB\VID_056A&PID_0357] +[USB\VID_056A&PID_0357] Plugin = wacom_usb Flags = use-runtime-version # Intuos Pro large (2nd-gen USB) [PTH-860] -[DeviceInstanceId=USB\VID_056A&PID_0358] +[USB\VID_056A&PID_0358] Plugin = wacom_usb Flags = use-runtime-version # Intuos S 3rd-gen (USB) [CTL-4100] -[DeviceInstanceId=USB\VID_056A&PID_0374] +[USB\VID_056A&PID_0374] Plugin = wacom_usb Flags = use-runtime-version # Intuos M 3rd-gen (USB) [NA] -[DeviceInstanceId=USB\VID_056A&PID_0375] +[USB\VID_056A&PID_0375] Plugin = wacom_usb Flags = use-runtime-version # Intuos BT S 3rd-gen (USB) [CTL-4100WL] -[DeviceInstanceId=USB\VID_056A&PID_0376] +[USB\VID_056A&PID_0376] Plugin = wacom_usb Flags = use-runtime-version # Intuos BT M 3rd-gen (USB) [CTL-6100WL] -[DeviceInstanceId=USB\VID_056A&PID_0378] +[USB\VID_056A&PID_0378] Plugin = wacom_usb Flags = use-runtime-version # Intuos Pro Small (2nd-gen USB) [PTH-460] -[DeviceInstanceId=USB\VID_056A&PID_0392] +[USB\VID_056A&PID_0392] Plugin = wacom_usb diff -Nru fwupd-1.4.5/po/af.po fwupd-1.5.8/po/af.po --- fwupd-1.4.5/po/af.po 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/po/af.po 2021-03-31 20:08:32.000000000 +0000 @@ -50,10 +50,6 @@ msgstr[0] "%u sekonde" msgstr[1] "%u sekondes" -#. TRANSLATORS: this is when a device is hotplugged -msgid "Added" -msgstr "Bygevoeg" - #. TRANSLATORS: the age of the metadata msgid "Age" msgstr "Ouderdom" @@ -74,7 +70,6 @@ msgid "Cancelled" msgstr "Gekanselleer" -#. TRANSLATORS: this is when a device is hotplugged #. TRANSLATORS: this is when the daemon state changes msgid "Changed" msgstr "Verander" @@ -123,6 +118,7 @@ msgid "Devices that were not updated correctly:" msgstr "Toestelle wat nie korrek bygewerk is nie:" +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Klaar!" @@ -143,6 +139,8 @@ msgid "Downloading…" msgstr "Laai tans af…" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Geaktiveer" @@ -151,22 +149,6 @@ msgid "Erasing…" msgstr "Vee tans uit…" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "Kon nie aflaai nie a.g.v. bedienerlimiet" - -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "Kry tans lêer" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "Kry tans metadata" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "Kry tans handtekening" - #. TRANSLATORS: filename of the local file msgid "Filename" msgstr "Lêernaam" @@ -175,6 +157,15 @@ msgid "Filename Signature" msgstr "Lêernaamhandtekening" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Gevind" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgctxt "A single GUID" +msgid "GUID" +msgstr "GUID" + #. TRANSLATORS: daemon is inactive msgid "Idle…" msgstr "Ledig…" @@ -199,6 +190,10 @@ msgid "Metadata URI" msgstr "Metadata-URI" +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "Goed" + #. TRANSLATORS: remote filename base msgid "Password" msgstr "Wagwoord" @@ -224,10 +219,6 @@ msgid "Reinstalling %s with %s... " msgstr "Herinstalleer tans %s met %s… " -#. TRANSLATORS: this is when a device is hotplugged -msgid "Removed" -msgstr "Verwyder" - #. TRANSLATORS: metadata is downloaded from the Internet msgid "Requires internet connection" msgstr "Internetverbinding is nodig" @@ -285,10 +276,6 @@ msgid "Updating %s…" msgstr "Werk tans %s by…" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Oplaaiboodskap:" - #. TRANSLATORS: ask the user to upload msgid "Upload report now?" msgstr "Laai verslag nou op?" @@ -301,6 +288,10 @@ msgid "Verifying…" msgstr "Verifieer tans…" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Weergawe" + #. TRANSLATORS: waiting for device to do something msgid "Waiting…" msgstr "Wag tans…" diff -Nru fwupd-1.4.5/po/ca.po fwupd-1.5.8/po/ca.po --- fwupd-1.4.5/po/ca.po 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/po/ca.po 2021-03-31 20:08:32.000000000 +0000 @@ -3,7 +3,7 @@ # This file is distributed under the same license as the fwupd package. # # Translators: -# Antoni Bella Pérez , 2017-2020 +# Antoni Bella Pérez , 2017-2021 # Robert Antoni Buj Gelonch , 2017 msgid "" msgstr "" @@ -29,6 +29,12 @@ msgid "%s CPU Microcode Update" msgstr "%s Actualitza el microprogramari de la CPU" +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Secure Boot` +#, c-format +msgid "%s Configuration Update" +msgstr "Actualització de la configuració %s" + #. TRANSLATORS: ME stands for Management Engine, where #. * the first %s is the device name, e.g. 'ThinkPad P50` #, c-format @@ -52,7 +58,7 @@ #. * the first %s is the device name, e.g. 'Unifying Receiver` #, c-format msgid "%s Device Update" -msgstr "Actualizació del dispositiu %s" +msgstr "Actualització del dispositiu %s" #. TRANSLATORS: the EC is typically the keyboard controller chip, #. * the first %s is the device name, e.g. 'ThinkPad P50` @@ -70,7 +76,7 @@ #. * the first %s is the device name, e.g. 'ThinkPad P50` #, c-format msgid "%s System Update" -msgstr "Actualizació del sistema %s" +msgstr "Actualització del sistema %s" #. TRANSLATORS: the Thunderbolt controller is a device that #. * has other high speed Thunderbolt devices plugged into it; @@ -92,15 +98,35 @@ msgid "%s and all connected devices may not be usable while updating." msgstr "%s i tots els dispositius connectats poden no ser usables en actualitzar." +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s manufacturing mode" +msgstr "Mode de fabricació %s" + #. TRANSLATORS: warn the user before updating, %1 is a device name #, c-format msgid "%s must remain connected for the duration of the update to avoid damage." -msgstr "%s haurà d'estar connectat durant tota l'actualització per evitar danys." +msgstr "%s haurà d'estar connectat durant tota l'actualització per a evitar danys." #. TRANSLATORS: warn the user before updating, %1 is a machine name #, c-format msgid "%s must remain plugged into a power source for the duration of the update to avoid damage." -msgstr "%s haurà de romandre connectat a una font d'alimentació durant tota l'actualització per evitar danys." +msgstr "%s haurà de romandre connectat a una font d'alimentació durant tota l'actualització per a evitar danys." + +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s override" +msgstr "Superposa %s" + +#. TRANSLATORS: Title: %1 is ME kind, e.g. CSME/TXT, %2 is a version number +#, c-format +msgid "%s v%s" +msgstr "%s versió %s" + +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s version" +msgstr "Versió %s" #. TRANSLATORS: duration in days! #, c-format @@ -143,13 +169,17 @@ msgstr[0] "%u segon" msgstr[1] "%u segons" +#. TRANSLATORS: this is shown as a suffix for obsoleted tests +msgid "(obsoleted)" +msgstr "(obsolet)" + #. TRANSLATORS: command description msgid "Activate devices" -msgstr "Activa els dispositius" +msgstr "Activa els dispositius." #. TRANSLATORS: command description msgid "Activate pending devices" -msgstr "Activa els dispositius pendents" +msgstr "Activa els dispositius pendents." msgid "Activate the new firmware on the device" msgstr "Activa el microprogramari nou al dispositiu" @@ -160,11 +190,7 @@ #. TRANSLATORS: shown when shutting down to switch to the new version msgid "Activating firmware update for" -msgstr "Activa l’actualització del microprogramari per a" - -#. TRANSLATORS: this is when a device is hotplugged -msgid "Added" -msgstr "S'ha afegit" +msgstr "Activa l'actualització del microprogramari per a" #. TRANSLATORS: the age of the metadata msgid "Age" @@ -177,7 +203,7 @@ #. TRANSLATORS: this is a command alias, e.g. 'get-devices' #, c-format msgid "Alias to %s" -msgstr "Àlies per a %s" +msgstr "Àlies per a «%s»" #. TRANSLATORS: command line option msgid "Allow downgrading firmware versions" @@ -187,6 +213,10 @@ msgid "Allow reinstalling existing firmware versions" msgstr "Permetre tornar a instal·lar les versions existents del microprogramari" +#. TRANSLATORS: command line option +msgid "Allow switching firmware branch" +msgstr "Permet canviar de branca de microprogramari" + #. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Una actualització requereix un reinici per a completar-se." @@ -201,7 +231,19 @@ #. TRANSLATORS: command line option msgid "Apply firmware updates" -msgstr "Aplica les actualizacions de microprogramari" +msgstr "Aplica les actualitzacions de microprogramari" + +#. TRANSLATORS: command line option +msgid "Apply update even when not advised" +msgstr "Aplica una actualització fins i tot quan no se us aconselli." + +#. TRANSLATORS: command line option +msgid "Apply update files" +msgstr "Aplica els fitxers d'actualització." + +#. TRANSLATORS: actually sending the update to the hardware +msgid "Applying update…" +msgstr "S'està aplicant l'actualització" #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator @@ -210,9 +252,13 @@ msgstr[0] "Microprogramari aprovat:" msgstr[1] "Microprogramari aprovat:" +#. TRANSLATORS: stop nagging the user +msgid "Ask again next time?" +msgstr "Demana-m'ho de nou la propera vegada?" + #. TRANSLATORS: command description msgid "Attach to firmware mode" -msgstr "Ajunta al mode microprogramari" +msgstr "Adjunta al mode microprogramari." #. TRANSLATORS: waiting for user to authenticate msgid "Authenticating…" @@ -220,7 +266,7 @@ #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on a removable device" -msgstr "Es requereix autenticació per a desactualitzar el microprogramari en un dispositiu extraible" +msgstr "Es requereix autenticació per a desactualitzar el microprogramari en un dispositiu extraïble" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on this machine" @@ -244,7 +290,7 @@ #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to switch to the new firmware version" -msgstr "Es requereix autenticació per a canviar a la nova versió del micropogramari" +msgstr "Es requereix autenticació per a canviar a la nova versió del microprogramari" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to unlock a device" @@ -252,27 +298,66 @@ #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to update the firmware on a removable device" -msgstr "Es requereix autenticació per actualitzar el microprogramari en un dispositiu extraible" +msgstr "Es requereix autenticació per a actualitzar el microprogramari en un dispositiu extraïble" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to update the firmware on this machine" -msgstr "Es requereix autenticació per actualitzar el microprogramari en aquesta màquina" +msgstr "Es requereix autenticació per a actualitzar el microprogramari en aquesta màquina" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to update the stored checksums for the device" -msgstr "Es requereix autenticació per actualitzar les sumes de verificació emmagatzemades pels dispositius" +msgstr "Es requereix autenticació per a actualitzar les sumes de verificació emmagatzemades pels dispositius" #. TRANSLATORS: Boolean value to automatically send reports msgid "Automatic Reporting" msgstr "Informa automàticament" +#. TRANSLATORS: can we JFDI? +msgid "Automatically upload every time?" +msgstr "El pujo automàticament cada vegada?" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "BUILDER-XML FILENAME-DST" +msgstr "CONSTRUCTOR_XML NOM_FITXER_DEST" + +msgid "BYTES" +msgstr "BYTES" + +#. TRANSLATORS: command description +msgid "Bind new kernel driver" +msgstr "Vincula el controlador actual." + +#. TRANSLATORS: there follows a list of hashes +msgid "Blocked firmware files:" +msgstr "Fitxers del microprogramari bloquejat:" + +#. TRANSLATORS: we will not offer this firmware to the user +msgid "Blocking firmware:" +msgstr "Microprogramari bloquejat:" + +#. TRANSLATORS: command description +msgid "Blocks a specific firmware from being installed" +msgstr "Bloqueja la instal·lació d'un microprogramari específic." + #. TRANSLATORS: firmware version of bootloader msgid "Bootloader Version" msgstr "Versió del carregador d'arrencada" +#. TRANSLATORS: the stream of firmware, e.g. nonfree or open-source +msgid "Branch" +msgstr "Branca" + +#. TRANSLATORS: command description +msgid "Build a firmware file" +msgstr "Construeix un fitxer de microprogramari." + #. TRANSLATORS: command description msgid "Build firmware using a sandbox" -msgstr "Construeix el microprogramari usant un entorn de proves" +msgstr "Construeix el microprogramari usant un entorn de proves." + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "CHECKSUM1[,CHECKSUM2][,CHECKSUM3]" +msgstr "SUMA_DE_VERIFICACIÓ_1[,SUMA_DE_VERIFICACIÓ_2][,SUMA_DE_VERIFICACIÓ_3]" #. TRANSLATORS: this is to abort the interactive prompt msgid "Cancel" @@ -282,19 +367,31 @@ msgid "Cancelled" msgstr "S'ha cancel·lat" -#. TRANSLATORS: this is when a device is hotplugged +#. TRANSLATORS: same or newer update already applied +msgid "Cannot apply as dbx update has already been applied." +msgstr "No s'ha pogut aplicar perquè l'actualització de la dbx ja s'ha aplicat." + +#. TRANSLATORS: the user is using a LiveCD or LiveUSB install disk +msgid "Cannot apply updates on live media" +msgstr "No s'han pogut aplicar les actualitzacions en els suports en viu" + #. TRANSLATORS: this is when the daemon state changes msgid "Changed" msgstr "S'ha canviat" #. TRANSLATORS: command description msgid "Checks cryptographic hash matches firmware" -msgstr "Comprova que la suma criptogràfica coincideix amb el microprogramari" +msgstr "Comprova que la suma criptogràfica coincideix amb el microprogramari." #. TRANSLATORS: remote checksum msgid "Checksum" msgstr "Suma de comprovació" +#. TRANSLATORS: get interactive prompt, where branch is the +#. * supplier of the firmware, e.g. "non-free" or "free" +msgid "Choose a branch:" +msgstr "Trieu una branca:" + #. TRANSLATORS: get interactive prompt msgid "Choose a device:" msgstr "Trieu un dispositiu:" @@ -307,13 +404,17 @@ msgid "Choose a release:" msgstr "Trieu un alliberament:" +#. TRANSLATORS: get interactive prompt +msgid "Choose a volume:" +msgstr "Trieu un volum:" + #. TRANSLATORS: command description msgid "Clears any updates scheduled to be updated offline" -msgstr "Neteja qualsevol actualització programyada per a ser actualitzada sense connexió" +msgstr "Neteja qualsevol actualització programada per a ser actualitzada sense connexió." #. TRANSLATORS: command description msgid "Clears the results from the last update" -msgstr "Esborra els resultats de l'última actualització" +msgstr "Esborra els resultats de l'última actualització." #. TRANSLATORS: error message msgid "Command not found" @@ -325,7 +426,7 @@ #. TRANSLATORS: command description msgid "Convert a firmware file" -msgstr "Converteix un fitxer de microprogramari" +msgstr "Converteix un fitxer de microprogramari." #. TRANSLATORS: when the update was built msgid "Created" @@ -343,6 +444,10 @@ msgid "Current version" msgstr "Versió actual" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "DEVICE-ID|GUID" +msgstr "ID_DISPOSITIU|GUID" + #. TRANSLATORS: DFU stands for device firmware update msgid "DFU Utility" msgstr "Utilitat DFU" @@ -361,7 +466,7 @@ #. TRANSLATORS: command description msgid "Detach to bootloader mode" -msgstr "Separa del mode carregador d'arrencada" +msgstr "Separa del mode carregador d'arrencada." #. TRANSLATORS: more details about the update link msgid "Details" @@ -397,7 +502,7 @@ #. TRANSLATORS: a version check is required for all firmware msgid "Device is required to install all provided releases" -msgstr "El dispositiu és necessari per instal·lar totes les versions llançades" +msgstr "El dispositiu és necessari per a instal·lar totes les versions subministrades" #. TRANSLATORS: Device remains usable during update msgid "Device is usable for the duration of the update" @@ -411,10 +516,18 @@ msgid "Device stages updates" msgstr "Etapes d'actualització del dispositiu" +#. TRANSLATORS: there is more than one supplier of the firmware +msgid "Device supports switching to a different branch of firmware" +msgstr "El dispositiu admet el canvi a una branca diferent de microprogramari" + #. TRANSLATORS: Device update needs to be separately activated msgid "Device update needs activation" msgstr "Cal activar l'actualització del dispositiu" +#. TRANSLATORS: save the old firmware to disk before installing the new one +msgid "Device will backup firmware before installing" +msgstr "El dispositiu farà una còpia de seguretat del microprogramari abans d'instal·lar" + #. TRANSLATORS: Device will not return after update completes msgid "Device will not re-appear after update completes" msgstr "El dispositiu no tornarà a aparèixer un cop finalitzada l'actualització" @@ -427,12 +540,26 @@ msgid "Devices that were not updated correctly:" msgstr "Els dispositius que no s'han actualitzat correctament:" +#. TRANSLATORS: message letting the user know no device upgrade available due +#. to missing on LVFS +msgid "Devices with no available firmware updates: " +msgstr "Dispositius sense actualitzacions de microprogramari disponibles:" + +#. TRANSLATORS: message letting the user know no device upgrade available +msgid "Devices with the latest available firmware version:" +msgstr "Dispositius amb la versió més recent del microprogramari disponible:" + +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is inactive and not used +msgid "Disabled" +msgstr "Inhabilitada" + msgid "Disabled fwupdate debugging" msgstr "La depuració del «fwupdate» està inhabilitada" #. TRANSLATORS: command description msgid "Disables a given remote" -msgstr "Inhabilita un remot indicat" +msgstr "Inhabilita un remot indicat." #. TRANSLATORS: command line option msgid "Display version" @@ -450,6 +577,10 @@ msgid "Do not check for unreported history" msgstr "No comprovar si hi ha un historial sense informar" +#. TRANSLATORS: command line option +msgid "Do not check if download remotes should be enabled" +msgstr "No comprovar si la baixada des del remot ha d'estar habilitada" + #. TRANSLATORS: turn on all debugging msgid "Do not include log domain prefix" msgstr "No incloure el prefix de domini del registre" @@ -476,13 +607,18 @@ msgid "Do not write to the history database" msgstr "No escriure a la base de dades de l'historial" +#. TRANSLATORS: should the branch be changed +msgid "Do you understand the consequences of changing the firmware branch?" +msgstr "Enteneu les conseqüències de canviar la branca del microprogramari?" + +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Fet!" #. TRANSLATORS: command description msgid "Downgrades the firmware on a device" -msgstr "Desactualitza el microprogramari en un dispositiu" +msgstr "Desactualitza el microprogramari en un dispositiu." #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second and third are @@ -502,7 +638,7 @@ #. TRANSLATORS: command description msgid "Dump SMBIOS data from a file" -msgstr "Bolca les dades al SMBIOS des d'un fitxer" +msgstr "Bolca les dades al SMBIOS des d'un fitxer." #. TRANSLATORS: length of time the update takes to apply msgid "Duration" @@ -520,6 +656,8 @@ msgid "Enable this remote?" msgstr "Habilito aquest remot?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Habilitat" @@ -529,7 +667,7 @@ #. TRANSLATORS: command description msgid "Enables a given remote" -msgstr "Habilita un remot indicat" +msgstr "Habilita un remot indicat." msgid "Enabling this functionality is done at your own risk, which means you have to contact your original equipment manufacturer regarding any problems caused by these updates. Only problems with the update process itself should be filed at $OS_RELEASE:BUG_REPORT_URL$." msgstr "Si habiliteu aquesta funcionalitat, ho fareu sota el vostre propi risc, el qual significa que haureu de posar-vos en contacte amb el fabricant original de l'equip quant a qualsevol problema causat per aquestes actualitzacions. A $OS_RELEASE:BUG_REPORT_URL$, només s'han de presentar els problemes amb el procés d'actualització." @@ -538,9 +676,17 @@ msgid "Enabling this remote is done at your own risk." msgstr "Si habiliteu aquest remot, ho fareu sota el vostre propi risc." +#. TRANSLATORS: Suffix: the HSI result +msgid "Encrypted" +msgstr "Encriptada" + +#. TRANSLATORS: Title: Memory contents are encrypted, e.g. Intel TME +msgid "Encrypted RAM" +msgstr "RAM encriptada" + #. TRANSLATORS: command description msgid "Erase all firmware update history" -msgstr "Esborra tot l'historial de les actualitzacions de microprogramari" +msgstr "Esborra tot l'historial de les actualitzacions de microprogramari." #. TRANSLATORS: erasing contents of the flash chips msgid "Erasing…" @@ -554,26 +700,84 @@ msgid "Exit after the engine has loaded" msgstr "Sur una vegada s'hagi carregat el motor" +#. TRANSLATORS: command description +msgid "Extract a firmware blob to images" +msgstr "Extreu un blob de microprogramari en imatges." + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILE" +msgstr "FITXER" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILE [DEVICE-ID|GUID]" +msgstr "FITXER [ID_DISPOSITIU|GUID]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILE-IN FILE-OUT [SCRIPT] [OUTPUT]" +msgstr "FITXER_ENTRADA FITXER_SORTIDA [SCRIPT] [SORTIDA]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME" +msgstr "NOM_FITXER" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME DEVICE-ALT-NAME|DEVICE-ALT-ID" +msgstr "NOM_FITXER NOM_ALT_DISPOSITIU|ID_ALT_DISPOSITIU" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME DEVICE-ALT-NAME|DEVICE-ALT-ID [IMAGE-ALT-NAME|IMAGE-ALT-ID]" +msgstr "NOM_FITXER NOM_ALT_DISPOSITIU|ID_ALT_DISPOSITIU [NOM_ALT_IMATGE|NOM_ALT_IMTAGE]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME DEVICE-ID" +msgstr "NOM_FITXER ID_DISPOSITIU" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME [DEVICE-ID|GUID]" +msgstr "NOM_FITXER [ID_DISPOSITIU|GUID]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME [FIRMWARE-TYPE]" +msgstr "NOM_FITXER [TIPUS_MICROPROGRAMARI]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME-SRC FILENAME-DST [FIRMWARE-TYPE-SRC] [FIRMWARE-TYPE-DST]" +msgstr "NOM_FITXER_ORIG NOM_FITXER_DEST [TIPUS_MICROPROGRAMARI_ORIG] [TIPUS_MICROPROGRAMARI_DEST]" + +#. TRANSLATORS: Suffix: the fallback HSI result +#. TRANSLATORS: The update state of the specific device +msgid "Failed" +msgstr "Ha fallat" + +#. TRANSLATORS: dbx file failed to be applied as an update +msgid "Failed to apply update" +msgstr "Ha fallat en aplicar l'actualització" + #. TRANSLATORS: we could not talk to the fwupd daemon msgid "Failed to connect to daemon" msgstr "Ha fallat en connectar amb el dimoni" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "La baixada ha fallat a causa del límit del servidor" - #. TRANSLATORS: we could not get the devices to update offline msgid "Failed to get pending devices" msgstr "Ha fallat en obtenir els dispositius pendents" #. TRANSLATORS: we could not install for some reason msgid "Failed to install firmware update" -msgstr "Ha fallat en instal·lar l’actualització del microprogramari" +msgstr "Ha fallat en instal·lar l'actualització del microprogramari" + +#. TRANSLATORS: could not read existing system data +#. TRANSLATORS: could not read file +msgid "Failed to load local dbx" +msgstr "Ha fallat en carregar una dbx local" #. TRANSLATORS: quirks are device-specific workarounds msgid "Failed to load quirks" msgstr "No s'han pogut carregar les peculiaritats" +#. TRANSLATORS: could not read existing system data +msgid "Failed to load system dbx" +msgstr "Ha fallat en carregar una dbx del sistema" + #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Ha fallat en analitzar els arguments" @@ -586,6 +790,10 @@ msgid "Failed to parse flags for --filter" msgstr "Ha fallat en analitzar les etiquetes per a --filter" +#. TRANSLATORS: could not parse file +msgid "Failed to parse local dbx" +msgstr "Ha fallat en analitzar una dbx local" + #. TRANSLATORS: we could not reboot for some reason msgid "Failed to reboot" msgstr "Ha fallat en tornar a arrencar" @@ -594,21 +802,10 @@ msgid "Failed to set splash mode" msgstr "Ha fallat en establir el mode de presentació" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "S'està obtenint el fitxer" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "S'està obtenint el microprogramari" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "S'estan obtenint les metadades" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "S'està obtenint la signatura" +#. TRANSLATORS: something with a blocked hash exists +#. * in the users ESP -- which would be bad! +msgid "Failed to validate ESP contents" +msgstr "Ha fallat en validar el contingut ESP" #. TRANSLATORS: filename of the local file msgid "Filename" @@ -618,6 +815,10 @@ msgid "Filename Signature" msgstr "Signatura del nom del fitxer" +#. TRANSLATORS: user did not include a filename parameter +msgid "Filename required" +msgstr "El nom del fitxer és obligatori" + #. TRANSLATORS: command line option msgid "Filter with a set of device flags using a ~ prefix to exclude, e.g. 'internal,~needs-reboot'" msgstr "Filtra amb un conjunt d'etiquetes del dispositiu amb un prefix «~» per a excloure, p. ex., «internal,~needs-reboot»" @@ -642,6 +843,22 @@ msgid "Firmware Utility" msgstr "Utilitat per al microprogramari" +#. TRANSLATORS: Title: if we can verify the firmware checksums +msgid "Firmware attestation" +msgstr "Atestat del microprogramari" + +#. TRANSLATORS: system is not booted in UEFI mode +msgid "Firmware can not be updated in legacy BIOS mode" +msgstr "El microprogramari no es pot actualitzar en el mode BIOS heretat" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is already blocked" +msgstr "El microprogramari ja està bloquejat" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is not already blocked" +msgstr "El microprogramari ja no està bloquejat" + #. TRANSLATORS: the metadata is very out of date; %u is a number > 1 #, c-format msgid "Firmware metadata has not been updated for %u day and may not be up to date." @@ -649,64 +866,98 @@ msgstr[0] "Les metadades del microprogramari no s'han actualitzat durant %u dia i podria ser que no estiguin actualitzades." msgstr[1] "Les metadades del microprogramari no s'han actualitzat durant %u dies i podria ser que no estiguin actualitzades." +#. TRANSLATORS: Title: if firmware updates are available +msgid "Firmware updates" +msgstr "Actualitzacions del microprogramari" + msgid "Firmware updates are not supported on this machine." msgstr "Les actualitzacions de microprogramari no estan admeses en aquesta màquina." msgid "Firmware updates are supported on this machine." msgstr "Les actualitzacions de microprogramari estan admeses en aquesta màquina." +#. TRANSLATORS: user needs to run a command +msgid "Firmware updates disabled; run 'fwupdmgr unlock' to enable" +msgstr "Actualitzacions de microprogramari inhabilitades: executeu «fwupdmgr unlock» per a habilitar-les" + +#. TRANSLATORS: description of plugin state, e.g. disabled #. TRANSLATORS: release properties msgid "Flags" msgstr "Etiquetes" +#. TRANSLATORS: command line option +msgid "Force the action by relaxing some runtime checks" +msgstr "Força l'acció relaxant algunes comprovacions del temps d'execució" + msgid "Force the action ignoring all warnings" msgstr "Força l'acció ignorant tots els avisos" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "S'ha trobat" + #. TRANSLATORS: global ID common to all similar hardware msgid "GUID" msgid_plural "GUIDs" msgstr[0] "El GUID" msgstr[1] "Els GUID" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgctxt "A single GUID" +msgid "GUID" +msgstr "GUID" + #. TRANSLATORS: command description msgid "Get all device flags supported by fwupd" -msgstr "Obté totes les etiquetes admeses per «fwupd»" +msgstr "Obté totes les etiquetes admeses per «fwupd»." #. TRANSLATORS: command description msgid "Get all devices and possible releases" -msgstr "Obtén tots els dispositius i possibles llançaments" +msgstr "Obté tots els dispositius i possibles llançaments." #. TRANSLATORS: command description msgid "Get all devices that support firmware updates" -msgstr "Obté tots els dispositius que admeten actualitzacions de microprogramari" +msgstr "Obté tots els dispositius que admeten actualitzacions de microprogramari." #. TRANSLATORS: command description msgid "Get all enabled plugins registered with the system" -msgstr "Obtén tots els connectors habilitats registrats amb el sistema" +msgstr "Obté tots els connectors habilitats registrats amb el sistema." #. TRANSLATORS: command description msgid "Gets details about a firmware file" -msgstr "Obté la informació sobre un fitxer de microprogramari" +msgstr "Obté la informació sobre un fitxer de microprogramari." #. TRANSLATORS: command description msgid "Gets the configured remotes" -msgstr "Obtén els remots configurats" +msgstr "Obté els remots configurats." + +#. TRANSLATORS: command description +msgid "Gets the host security attributes" +msgstr "Obté els atributs de seguretat de l'amfitrió." #. TRANSLATORS: firmware approved by the admin -msgid "Gets the list of approved firmware." -msgstr "Obtén la llista del microprogramari aprovat." +msgid "Gets the list of approved firmware" +msgstr "Obtén la llista del microprogramari aprovat" + +#. TRANSLATORS: command description +msgid "Gets the list of blocked firmware" +msgstr "Obté la llista del microprogramari bloquejat." #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" -msgstr "Obté la llista d'actualitzacions per al maquinari connectat" +msgstr "Obté la llista d'actualitzacions per al maquinari connectat." #. TRANSLATORS: command description msgid "Gets the releases for a device" -msgstr "Obté els alliberaments per a un dispositiu" +msgstr "Obté els alliberaments per a un dispositiu." #. TRANSLATORS: command description msgid "Gets the results from the last update" -msgstr "Obté els resultats de l'última actualització" +msgstr "Obté els resultats de l'última actualització." + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "HWIDS-FILE" +msgstr "FITXER-HWIDS" #. TRANSLATORS: The hardware is waiting to be replugged msgid "Hardware is waiting to be replugged" @@ -716,6 +967,15 @@ msgid "High" msgstr "Alta" +#. TRANSLATORS: this is a string like 'HSI:2-U' +msgid "Host Security ID:" +msgstr "ID de seguretat de l'amfitrió:" + +#. TRANSLATORS: Title: +#. https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit +msgid "IOMMU" +msgstr "IOMMU" + #. TRANSLATORS: daemon is inactive msgid "Idle…" msgstr "Està ociós..." @@ -724,21 +984,37 @@ msgid "Ignore SSL strict checks when downloading files" msgstr "Ignora les comprovacions estrictes de SSL quan es baixin els fitxers" +#. TRANSLATORS: command line option +msgid "Ignore firmware checksum failures" +msgstr "Ignora les falles de la suma de comprovació del microprogramari" + +#. TRANSLATORS: command line option +msgid "Ignore firmware hardware mismatch failures" +msgstr "Ignora les falles de discrepància del maquinari del microprogramari" + +#. TRANSLATORS: command line option +msgid "Ignore requirement of external power source" +msgstr "Ignora el requisit de la font d'alimentació externa" + #. TRANSLATORS: Ignore validation safety checks when flashing this device msgid "Ignore validation safety checks" msgstr "Ignora les comprovacions de seguretat de validació" +#. TRANSLATORS: try to help +msgid "Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" +msgstr "S'ignoren les comprovacions estrictes de SSL, per a fer-ho automàticament en el futur, exporteu DISABLE_SSL_STRICT en el vostre entorn" + #. TRANSLATORS: length of time the update takes to apply msgid "Install Duration" msgstr "Durada de la instal·lació" #. TRANSLATORS: command description msgid "Install a firmware blob on a device" -msgstr "Instal·la un blob de microprogramari en un dispositiu" +msgstr "Instal·la un blob de microprogramari en un dispositiu." #. TRANSLATORS: command description msgid "Install a firmware file on this hardware" -msgstr "Instal·la un fitxer de microprogramari en aquest maquinari" +msgstr "Instal·la un fitxer de microprogramari en aquest maquinari." msgid "Install old version of system firmware" msgstr "Instal·la la versió antiga del microprogramari per al sistema" @@ -770,12 +1046,59 @@ #. TRANSLATORS: %1 is a device name #, c-format msgid "Installing on %s…" -msgstr "S'està intal·lant a %s…" +msgstr "S'està instal·lant a %s…" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel +msgid "Intel BootGuard" +msgstr "BootGuard d'Intel" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * ACM means to verify the integrity of Initial Boot Block +msgid "Intel BootGuard ACM protected" +msgstr "Protegit amb l'ACM per al BootGuard d'Intel" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * OTP = one time programmable +msgid "Intel BootGuard OTP fuse" +msgstr "Fusible OTP del BootGuard d'Intel" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * error policy is what to do on failure +msgid "Intel BootGuard error policy" +msgstr "Política d'error del BootGuard d'Intel" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * verified boot refers to the way the boot process is verified +msgid "Intel BootGuard verified boot" +msgstr "Arrencada verificada per al BootGuard d'Intel" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * active means being used by the OS +msgid "Intel CET Active" +msgstr "CET d'Intel actiu" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * enabled means supported by the processor +msgid "Intel CET Enabled" +msgstr "CET d'Intel habilitat" + +#. TRANSLATORS: Title: Direct Connect Interface (DCI) allows +#. * debugging of Intel processors using the USB3 port +msgid "Intel DCI debugger" +msgstr "Depurador DCI d'Intel" + +#. TRANSLATORS: Title: SMAP = Supervisor Mode Access Prevention +msgid "Intel SMAP" +msgstr "SMAP d'Intel" #. TRANSLATORS: Device cannot be removed easily msgid "Internal device" msgstr "Dispositiu intern" +#. TRANSLATORS: Suffix: the HSI result +msgid "Invalid" +msgstr "No vàlid" + #. TRANSLATORS: Is currently in bootloader mode msgid "Is in bootloader mode" msgstr "Està en el mode carregador d'arrencada" @@ -786,6 +1109,10 @@ msgstr[0] "Problema" msgstr[1] "Problemes" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "KEY,VALUE" +msgstr "CLAU,VALOR" + msgid "Keyring" msgstr " Anell de claus" @@ -807,25 +1134,63 @@ msgid "Linux Vendor Firmware Service (testing firmware)" msgstr "Servei de microprogramari del proveïdor Linux (microprogramari en proves)" +#. TRANSLATORS: Title: if it's tainted or not +msgid "Linux kernel" +msgstr "Nucli Linux" + +#. TRANSLATORS: Title: lockdown is a security mode of the kernel +msgid "Linux kernel lockdown" +msgstr "Bloqueig del nucli Linux" + +#. TRANSLATORS: Title: swap space or swap partition +msgid "Linux swap" +msgstr "Intercanvi de Linux" + +#. TRANSLATORS: command line option +msgid "List entries in dbx" +msgstr "Llista les entrades a la dbx." + #. TRANSLATORS: command line option msgid "List supported firmware updates" msgstr "Llista les actualitzacions de microprogramari compatibles" #. TRANSLATORS: command description msgid "List the available firmware types" -msgstr "Llista els tipus de microprogramari disponibles" +msgstr "Llista els tipus de microprogramari disponibles." + +#. TRANSLATORS: command description +msgid "Lists files on the ESP" +msgstr "Llista els fitxers en l'ESP." #. TRANSLATORS: parsing the firmware information msgid "Loading…" msgstr "S'està carregant..." +#. TRANSLATORS: Suffix: the HSI result +msgid "Locked" +msgstr "Blocada" + #. TRANSLATORS: the release urgency msgid "Low" msgstr "Baixa" +#. TRANSLATORS: Title: MEI = Intel Management Engine +msgid "MEI manufacturing mode" +msgstr "Mode de fabricació MEI" + +#. TRANSLATORS: Title: MEI = Intel Management Engine, and the +#. * "override" is the physical PIN that can be driven to +#. * logic high -- luckily it is probably not accessible to +#. * end users on consumer boards +msgid "MEI override" +msgstr "Superposa el MEI" + +msgid "MEI version" +msgstr "Versió del MEI" + #. TRANSLATORS: command line option -msgid "Manually whitelist specific plugins" -msgstr "Connectors especíificats manualment a la llista blanca" +msgid "Manually enable specific plugins" +msgstr "Habilita manualment connectors específics" #. TRANSLATORS: the release urgency msgid "Medium" @@ -853,12 +1218,12 @@ msgstr "El dimoni i el client no coincideixin, useu %s en el seu lloc" #. TRANSLATORS: sets something in daemon.conf -msgid "Modifies a daemon configuration value." -msgstr "Modifica un valor de la configuració del dimoni." +msgid "Modifies a daemon configuration value" +msgstr "Modifica un valor de la configuració del dimoni" #. TRANSLATORS: command description msgid "Modifies a given remote" -msgstr "Modifica un remot indicat" +msgstr "Modifica un remot indicat." msgid "Modify a configured remote" msgstr "Modifica un remot configurat" @@ -868,12 +1233,20 @@ #. TRANSLATORS: command description msgid "Monitor the daemon for events" -msgstr "Monitora el dimoni pels esdeveniments" +msgstr "Monitora el dimoni per als esdeveniments." + +#. TRANSLATORS: command description +msgid "Mounts the ESP" +msgstr "Munta l'ESP." #. TRANSLATORS: Requires a reboot to apply firmware or to reload hardware msgid "Needs a reboot after installation" msgstr "Requereix un reinici després de la instal·lació" +#. TRANSLATORS: The update state of the specific device +msgid "Needs reboot" +msgstr "Cal reiniciar" + #. TRANSLATORS: Requires system shutdown to apply firmware msgid "Needs shutdown after installation" msgstr "Requereix aturar després de la instal·lació" @@ -882,6 +1255,7 @@ msgid "New version" msgstr "Versió nova" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "No s'ha especificat cap acció!" @@ -917,15 +1291,27 @@ #. TRANSLATORS: nothing was updated offline msgid "No updates were applied" -msgstr "No s’han aplicat les actualitzacions" +msgstr "No s'han aplicat les actualitzacions" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Not found" +msgstr "No s'ha trobat" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Not supported" +msgstr "No admesa" + +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "D'acord" #. TRANSLATORS: command line option msgid "Only show single PCR value" msgstr "Mostra només un únic valor de PCR" #. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Passa per alt els avisos del connector" +msgid "Only use IPFS when downloading files" +msgstr "Empra només IPFS quan es baixin els fitxers" #. TRANSLATORS: command line option msgid "Override the default ESP path" @@ -935,9 +1321,21 @@ msgid "Override warnings and force the action" msgstr "Anul·la els avisos i força l'acció" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "PATH" +msgstr "CAMÍ" + #. TRANSLATORS: command description msgid "Parse and show details about a firmware file" -msgstr "Analitza i mostra els detalls sobre un fitxer de microprogramari" +msgstr "Analitza i mostra els detalls sobre un fitxer de microprogramari." + +#. TRANSLATORS: reading new dbx from the update +msgid "Parsing dbx update…" +msgstr "S'està analitzant l'actualització de la dbx..." + +#. TRANSLATORS: reading existing dbx from the system +msgid "Parsing system dbx…" +msgstr "S'està analitzant la dbx del sistema..." #. TRANSLATORS: remote filename base msgid "Password" @@ -946,6 +1344,10 @@ msgid "Payload" msgstr "Carrega útil" +#. TRANSLATORS: The update state of the specific device +msgid "Pending" +msgstr "Pendent" + #. TRANSLATORS: console message when not using plymouth msgid "Percentage complete" msgstr "Percentatge completat" @@ -955,6 +1357,14 @@ msgid "Please enter a number from 0 to %u: " msgstr "Introduïu un número del 0 al %u: " +#. TRANSLATORS: Failed to open plugin, hey Arch users +msgid "Plugin dependencies missing" +msgstr "Manquen les dependències del connector" + +#. TRANSLATORS: Title: DMA as in https://en.wikipedia.org/wiki/DMA_attack +msgid "Pre-boot DMA protection" +msgstr "Protecció DMA durant la prearrencada" + #. TRANSLATORS: version number of previous firmware msgid "Previous version" msgstr "Versió anterior" @@ -974,23 +1384,31 @@ #. TRANSLATORS: a non-free software license msgid "Proprietary" -msgstr "Proprietari" +msgstr "Propietari" #. TRANSLATORS: command line option msgid "Query for firmware update support" msgstr "Consulta el suport per a l'actualització del microprogramari" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "REMOTE-ID" +msgstr "ID_REMOT" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "REMOTE-ID KEY VALUE" +msgstr "ID_REMOT CLAU VALOR" + #. TRANSLATORS: command description msgid "Read a firmware blob from a device" -msgstr "Llegeix un blob de microprogramari des d'un dispositiu" +msgstr "Llegeix un blob de microprogramari des d'un dispositiu." #. TRANSLATORS: command description msgid "Read firmware from device into a file" -msgstr "Llegeix el microprogramari des del dispositiu a un fitxer" +msgstr "Llegeix el microprogramari des del dispositiu a un fitxer." #. TRANSLATORS: command description msgid "Read firmware from one partition into a file" -msgstr "Llegeix el microprogramari des d'una partició a un fitxer" +msgstr "Llegeix el microprogramari des d'una partició a un fitxer." #. TRANSLATORS: %1 is a device name #, c-format @@ -1003,19 +1421,19 @@ #. TRANSLATORS: console message when not using plymouth msgid "Rebooting…" -msgstr "S'està tornant a arencar..." +msgstr "S'està tornant a arrencar..." #. TRANSLATORS: command description msgid "Refresh metadata from remote server" -msgstr "Refresca les metadades des del servidor remot" +msgstr "Refresca les metadades des del servidor remot." #. TRANSLATORS: command description -msgid "Reinstall current firmware on the device." -msgstr "Torna a instal·lar el microprogramari actual al dispositiu." +msgid "Reinstall current firmware on the device" +msgstr "Torna a instal·lar el microprogramari actual en el dispositiu." #. TRANSLATORS: command description msgid "Reinstall firmware on a device" -msgstr "Torna a instal·lar el microprogramari a un dispositiu" +msgstr "Torna a instal·lar el microprogramari a un dispositiu." #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second is a version number @@ -1024,18 +1442,18 @@ msgid "Reinstalling %s with %s... " msgstr "S'està reinstal·lant %s amb %s... " +#. TRANSLATORS: the stream of firmware, e.g. nonfree or open-source +msgid "Release Branch" +msgstr "Branca de llançament" + #. TRANSLATORS: the server the file is coming from #. TRANSLATORS: remote identifier, e.g. lvfs-testing msgid "Remote ID" msgstr "ID remot" -#. TRANSLATORS: this is when a device is hotplugged -msgid "Removed" -msgstr "S'ha eliminat" - #. TRANSLATORS: command description msgid "Replace data in an existing firmware file" -msgstr "Substitueix les dades en un fitxer de microprogramari existent" +msgstr "Substitueix les dades en un fitxer de microprogramari existent." #. TRANSLATORS: URI to send success/failure reports msgid "Report URI" @@ -1045,13 +1463,17 @@ msgid "Reported to remote server" msgstr "Informat al servidor remot" -#. TRANSLATORS: Must be plugged in to an outlet -msgid "Requires AC power" -msgstr "Requereix una font d'alimentació" +#. TRANSLATORS: the user is using Gentoo/Arch and has screwed something up +msgid "Required efivarfs filesystem was not found" +msgstr "No s'ha trobat el sistema de fitxers «efivarfs» requerit" + +#. TRANSLATORS: not required for this system +msgid "Required hardware was not found" +msgstr "No s'ha trobat el maquinari requerit" #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user msgid "Requires a bootloader" -msgstr "Requereix un carregador d’arrencada" +msgstr "Requereix un carregador d'arrencada" #. TRANSLATORS: metadata is downloaded from the Internet msgid "Requires internet connection" @@ -1071,7 +1493,7 @@ #. TRANSLATORS: command description msgid "Return all the hardware IDs for the machine" -msgstr "Retorna tots els ID del maquinari de la màquina" +msgstr "Retorna tots els ID del maquinari de la màquina." msgid "Run `fwupdmgr get-upgrades` for more information." msgstr "Per a més informació executeu «fwupdmgr get-upgrades»." @@ -1084,22 +1506,55 @@ msgid "Run the plugin composite prepare routine when using install-blob" msgstr "Executa la rutina de preparació de la composició del connector en usar install-blob" +#. TRANSLATORS: this is the HSI suffix +msgid "Runtime Suffix" +msgstr "Sufix d'execució" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI BIOS region" +msgstr "regió del BIOS per a l'SPI" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI lock" +msgstr "Bloca l'SPI" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI write" +msgstr "Escriu l'SPI" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "SUBSYSTEM DRIVER [DEVICE-ID|GUID]" +msgstr "SUBSISTEMA CONTROLADOR [ID_DISPOSITIU|GUID]" + +#. TRANSLATORS: command description +msgid "Save a file that allows generation of hardware IDs" +msgstr "Desa un fitxer que permet la generació dels ID de maquinari" + #. TRANSLATORS: command line option msgid "Save device state into a JSON file between executions" msgstr "Desa l'estat del dispositiu en un fitxer JSON entre les execucions" #. TRANSLATORS: command line option msgid "Schedule installation for next reboot when possible" -msgstr "Planifica la instal·lació per al següent reinici quan sigui posible" +msgstr "Planifica la instal·lació per al següent reinici quan sigui possible" #. TRANSLATORS: scheduling an update to be done on the next boot msgid "Scheduling…" msgstr "Planificació..." +#. TRANSLATORS: %s is a link to a website +#, c-format +msgid "See %s for more information." +msgstr "Per a més informació, vegeu %s." + #. TRANSLATORS: Device has been chosen by the daemon for the user msgid "Selected device" msgstr "Dispositiu seleccionat" +#. TRANSLATORS: Volume has been chosen by the user +msgid "Selected volume" +msgstr "Volum seleccionat" + #. TRANSLATORS: serial number of hardware msgid "Serial Number" msgstr "Número de sèrie" @@ -1108,16 +1563,17 @@ msgid "Set the debugging flag during update" msgstr "Estableix l'indicador de depuració durant l'actualització" +#. TRANSLATORS: firmware approved by the admin msgid "Sets the list of approved firmware" msgstr "Estableix la llista de microprogramari aprovat" -#. TRANSLATORS: firmware approved by the admin -msgid "Sets the list of approved firmware." -msgstr "Estableix la llista del microprogramari aprovat." - #. TRANSLATORS: command description msgid "Share firmware history with the developers" -msgstr "Comparteix l'historial de microprogramari amb els desenvolupadors" +msgstr "Comparteix l'historial de microprogramari amb els desenvolupadors." + +#. TRANSLATORS: command line option +msgid "Show all results" +msgstr "Mostra tots els resultats" #. TRANSLATORS: command line option msgid "Show client and daemon versions" @@ -1141,17 +1597,21 @@ #. TRANSLATORS: command line option msgid "Show extra debugging information" -msgstr "Mostra la informació de depuració addicional" +msgstr "Mostra la informació de depuració addicional." #. TRANSLATORS: command description msgid "Show history of firmware updates" -msgstr "Mostra l'historial de les actualitzacions de microprogramari" +msgstr "Mostra l'historial de les actualitzacions de microprogramari." #. TRANSLATORS: this is for plugin development msgid "Show plugin verbose information" msgstr "Mostra la informació detallada del connector" #. TRANSLATORS: command line option +msgid "Show the calculated version of the dbx" +msgstr "Mostra la versió calculada de la dbx." + +#. TRANSLATORS: command line option msgid "Show the debug log from the last attempted update" msgstr "Mostra el registre de depuració del darrer intent d'actualització" @@ -1188,9 +1648,17 @@ msgid "Specify Vendor/Product ID(s) of DFU device" msgstr "Especifiqueu el proveïdor/ID del producte del dispositiu DFU" +#. TRANSLATORS: command line option +msgid "Specify the dbx database file" +msgstr "Especifica el fitxer de base de dades dbx." + msgid "Specify the number of bytes per USB transfer" msgstr "Especifiqueu el nombre de bytes per a la transferència USB" +#. TRANSLATORS: The update state of the specific device +msgid "Success" +msgstr "Amb èxit" + #. TRANSLATORS: success message -- where activation is making the new #. * firmware take effect, usually after updating offline msgid "Successfully activated all devices" @@ -1245,10 +1713,46 @@ msgid "Summary" msgstr "Resum" +#. TRANSLATORS: Suffix: the HSI result +msgid "Supported" +msgstr "Admesa" + #. TRANSLATORS: Is found in current metadata msgid "Supported on remote server" msgstr "Admès en el servidor remot" +#. TRANSLATORS: Title: a better sleep state +msgid "Suspend-to-idle" +msgstr "Suspensió a inactiu" + +#. TRANSLATORS: Title: sleep state +msgid "Suspend-to-ram" +msgstr "Suspensió a la RAM" + +#. TRANSLATORS: command description +msgid "Switch the firmware branch on the device" +msgstr "Canvia la branca de microprogramari en el dispositiu." + +#. TRANSLATORS: Must be plugged in to an outlet +msgid "System requires external power source" +msgstr "El sistema requereix una font d'alimentació externa" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "TEXT" +msgstr "TEXT" + +#. TRANSLATORS: Title: the PCR is rebuilt from the TPM event log +msgid "TPM PCR0 reconstruction" +msgstr "Reconstrucció PCR0 del TPM" + +#. TRANSLATORS: Title: TPM = Trusted Platform Module +msgid "TPM v2.0" +msgstr "TPM versió 2.0" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Tainted" +msgstr "Contaminada" + msgid "Target" msgstr "Objectiu" @@ -1256,11 +1760,36 @@ msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "El LVFS és un servei gratuït que funciona com una entitat legal independent i no té cap vincle amb la $OS_RELEASE:NAME$. És possible que el vostre distribuïdor no hagi verificat cap de les actualitzacions del microprogramari per a la compatibilitat amb el vostre sistema o els dispositius connectats. Tot el microprogramari només és proporcionat pel fabricant original dels equips." +#. TRANSLATORS: this is more background on a security measurement problem +msgid "The TPM PCR0 differs from reconstruction." +msgstr "El PCR0 del TPM difereix de la reconstrucció." + +#. TRANSLATORS: the user is SOL for support... +msgid "The daemon has loaded 3rd party code and is no longer supported by the upstream developers!" +msgstr "El dimoni ha carregat codi de tercers i ja no és admès pels desenvolupadors originals!" + +#. TRANSLATORS: %1 is the firmware vendor, %2 is the device vendor name +#, c-format +msgid "The firmware from %s is not supplied by %s, the hardware vendor." +msgstr "El microprogramari des de %s no és proporcionat per %s, el proveïdor de maquinari." + +#. TRANSLATORS: try to help +msgid "The system clock has not been set correctly and downloading files may fail." +msgstr "El rellotge del sistema no s'ha configurat correctament i pot fallar la descàrrega de fitxers." + +#. TRANSLATORS: nothing to show +msgid "There are no blocked firmware files" +msgstr "No hi ha cap fitxer de microprogramari bloquejat." + #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator msgid "There is no approved firmware." msgstr "No hi ha cap microprogramari aprovat." +#. TRANSLATORS: unsupported build of the package +msgid "This package has not been validated, it may not work properly." +msgstr "Aquest paquet no ha estat validat, pel que podria no funcionar adecuadament." + #. TRANSLATORS: we're poking around as a power user msgid "This program may only work correctly as root" msgstr "Aquest programa només pot funcionar correctament com a «root»" @@ -1268,18 +1797,98 @@ msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "Aquest remot conté microprogramari que no està embargat, però encara l'ha de provar el proveïdor del maquinari. Haureu d'assegurar-vos que teniu una manera de desactualitzar manualment el microprogramari si l'actualització del microprogramari no funciona." +#. TRANSLATORS: this is instructions on how to improve the HSI suffix +msgid "This system has HSI runtime issues." +msgstr "Aquest sistema té problemes d'execució HSI." + +#. TRANSLATORS: this is instructions on how to improve the HSI security level +msgid "This system has a low HSI security level." +msgstr "Aquest sistema té un nivell de seguretat HSI baix." + +#. TRANSLATORS: description of dbxtool +msgid "This tool allows an administrator to apply UEFI dbx updates." +msgstr "Aquesta eina permet a un administrador aplicar les actualitzacions des de la dbx UEFI." + +#. TRANSLATORS: CLI description +msgid "This tool allows an administrator to debug UpdateCapsule operation." +msgstr "Aquesta eina permet a un administrador depurar el funcionament d'«UpdateCapsule»." + +#. TRANSLATORS: CLI description +msgid "This tool allows an administrator to query and control the fwupd daemon, allowing them to perform actions such as installing or downgrading firmware." +msgstr "Aquesta eina permet que un administrador consulti i controli el dimoni «fwupd», el qual li permetrà realitzar accions com instal·lar o degradar la versió de microprogramari." + +#. TRANSLATORS: CLI description +msgid "This tool allows an administrator to use the fwupd plugins without being installed on the host system." +msgstr "Aquesta eina permet a un administrador usar els connectors de «fwupd» sense estar instal·lats en el sistema amfitrió." + +#. TRANSLATORS: CLI description +msgid "This tool can be used from other tools and from shell scripts." +msgstr "Aquesta eina es pot usar des d'altres eines i des de scripts de l'intèrpret d'ordres." + #. TRANSLATORS: the user needs to stop playing with stuff msgid "This tool can only be used by the root user" msgstr "Aquesta eina només pot ser usada per l'usuari «root»." +#. TRANSLATORS: CLI description +msgid "This tool will read and parse the TPM event log from the system firmware." +msgstr "Aquesta eina llegirà i analitzarà el registre d'esdeveniments TPM des del microprogramari del sistema." + +#. TRANSLATORS: command line option +msgid "Timeout in milliseconds for each parse" +msgstr "Temps d'espera en mil·lisegons per a cada anàlisi" + +#. TRANSLATORS: The update state of the specific device +msgid "Transient failure" +msgstr "Fallada transitòria" + #. TRANSLATORS: remote type, e.g. remote or local msgid "Type" msgstr "Tipus" +#. TRANSLATORS: partition refers to something on disk, again, hey Arch users +msgid "UEFI ESP partition not detected or configured" +msgstr "No s'ha detectat o configurat la partició ESP de la UEFI" + #. TRANSLATORS: program name msgid "UEFI Firmware Utility" msgstr "Utilitat per al microprogramari UEFI" +#. TRANSLATORS: capsule updates are an optional BIOS feature +msgid "UEFI capsule updates not available or enabled in firmware setup" +msgstr "Les actualitzacions de la càpsula UEFI no estan disponibles o habilitades a la configuració del microprogramari" + +#. TRANSLATORS: program name +msgid "UEFI dbx Utility" +msgstr "Utilitat dbx UEFI" + +#. TRANSLATORS: Title: PK is the 'platform key' for the machine +msgid "UEFI platform key" +msgstr "Clau de la plataforma UEFI" + +#. TRANSLATORS: Title: SB is a way of locking down UEFI +msgid "UEFI secure boot" +msgstr "Arrancada segura de la UEFI" + +#. TRANSLATORS: error message +msgid "Unable to connect to service" +msgstr "No s'ha pogut connectar amb el servei" + +#. TRANSLATORS: command description +msgid "Unbind current driver" +msgstr "Desvincula el controlador actual." + +#. TRANSLATORS: we will now offer this firmware to the user +msgid "Unblocking firmware:" +msgstr "Microprogramari desbloquejat:" + +#. TRANSLATORS: command description +msgid "Unblocks a specific firmware from being installed" +msgstr "Desbloqueja la instal·lació d'un microprogramari específic." + +#. TRANSLATORS: Suffix: the HSI result +msgid "Unencrypted" +msgstr "Desencriptada" + #. TRANSLATORS: current daemon status is unknown #. TRANSLATORS: we don't know the license of the update #. TRANSLATORS: unknown release urgency @@ -1293,9 +1902,17 @@ msgid "Unlock the device to allow access" msgstr "Desbloqueja el dispositiu per a permetre l'accés" +#. TRANSLATORS: Suffix: the HSI result +msgid "Unlocked" +msgstr "Desblocada" + #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" -msgstr "Desbloqueja el dispositiu per accedir al microprogramari" +msgstr "Desbloqueja el dispositiu per a accedir al microprogramari." + +#. TRANSLATORS: command description +msgid "Unmounts the ESP" +msgstr "Desmunta l'ESP." #. TRANSLATORS: command line option msgid "Unset the debugging flag during update" @@ -1306,6 +1923,10 @@ msgid "Unsupported daemon version %s, client version is %s" msgstr "Versió %s no admesa del dimoni, la versió del client és %s" +#. TRANSLATORS: Suffix: the HSI result +msgid "Untainted" +msgstr "Sense contaminar" + #. TRANSLATORS: Device is updatable in this or any other mode msgid "Updatable" msgstr "Actualitzable" @@ -1325,11 +1946,11 @@ #. TRANSLATORS: command description msgid "Update all devices that match local metadata" -msgstr "Actualitza tots els dispositius que coincideixin amb les metadades locals" +msgstr "Actualitza tots els dispositius que coincideixin amb les metadades locals." #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" -msgstr "Que falli en actualitzar és un problema conegut, visiteu aquest URL per obtenir més informació:" +msgstr "Que falli en actualitzar és un problema conegut, visiteu aquest URL per a obtenir més informació:" #. TRANSLATORS: ask the user if we can update the metadata msgid "Update now?" @@ -1341,18 +1962,21 @@ #. TRANSLATORS: command description msgid "Update the stored cryptographic hash with current ROM contents" -msgstr "Actualitza la suma criptogràfica emmagatzemada amb el contingut actual de la ROM" +msgstr "Actualitza la suma criptogràfica emmagatzemada amb el contingut actual de la ROM." msgid "Update the stored device verification information" msgstr "Actualitza la informació de verificació dels dispositius emmagatzemats" #. TRANSLATORS: command description msgid "Update the stored metadata with current contents" -msgstr "Actualitza les metadades emmagatzemades amb el contingut actual" +msgstr "Actualitza les metadades emmagatzemades amb el contingut actual." #. TRANSLATORS: command description msgid "Updates all firmware to latest versions available" -msgstr "Actualitza tot el microprogramari a les versions més recents" +msgstr "Actualitza tot el microprogramari a les versions més recents." + +msgid "Updating" +msgstr "S'està actualitzant" #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second and third are @@ -1372,10 +1996,6 @@ msgid "Upgrade available for %s from %s to %s" msgstr "Actualització disponible per a %s des de %s a %s" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Missatge de l'enviament:" - msgid "Upload report just this one time, but prompt again for future updates" msgid_plural "Upload reports just this one time, but prompt again for future updates" msgstr[0] "Envia l'informe només aquesta vegada, però sol·licita-ho de nou en les futures actualitzacions" @@ -1398,6 +2018,14 @@ msgid "Urgency" msgstr "Urgència" +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdmgr --help for help" +msgstr "Empreu «fwupdmgr --help» per a l'ajuda" + +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdtool --help for help" +msgstr "Empreu «fwupdtool --help» per a l'ajuda" + #. TRANSLATORS: command line option msgid "Use quirk flags when installing firmware" msgstr "Usa les etiquetes peculiars en instal·lar el microprogramari" @@ -1410,6 +2038,17 @@ msgid "Username" msgstr "Nom d'usuari" +msgid "VID:PID" +msgstr "VID:PID" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Valid" +msgstr "Vàlid" + +#. TRANSLATORS: ESP refers to the EFI System Partition +msgid "Validating ESP contents…" +msgstr "S'està validant el contingut ESP..." + #. TRANSLATORS: one line variant of release (e.g. 'Prerelease' or 'China') msgid "Variant" msgstr "Variant" @@ -1422,29 +2061,33 @@ msgid "Verifying…" msgstr "S'està verificant..." -#. TRANSLATORS: try to help -msgid "WARNING: Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" -msgstr "AVÍS: S'ignoren les comprovacions estrictes de SSL. Per a fer-ho automàticament en el futur, exporteu DISABLE_SSL_STRICT en el vostre entorn" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Versió:" + +#. TRANSLATORS: this is a prefix on the console +msgid "WARNING:" +msgstr "AVÍS:" #. TRANSLATORS: waiting for device to do something msgid "Waiting…" msgstr "S'està esperant…" #. TRANSLATORS: command description -msgid "Watch DFU devices being hotplugged" -msgstr "Vigila els dispositius DFU que han estat connectats en calent" - -#. TRANSLATORS: command description msgid "Watch for hardware changes" -msgstr "Mira per a canvis al maquinari" +msgstr "Mira per a canvis al maquinari." #. TRANSLATORS: command description msgid "Write firmware from file into device" -msgstr "Escriu el microprogramari des d'un fitxer a dins del dispositiu" +msgstr "Escriu el microprogramari des d'un fitxer a dins del dispositiu." #. TRANSLATORS: command description msgid "Write firmware from file into one partition" -msgstr "Escriu el microprogramari des d'un fitxer a dins d'una partició" +msgstr "Escriu el microprogramari des d'un fitxer a dins d'una partició." + +#. TRANSLATORS: decompressing images from a container firmware +msgid "Writing file:" +msgstr "Fitxer d'escriptura:" #. TRANSLATORS: writing to the flash chips msgid "Writing…" @@ -1454,19 +2097,39 @@ msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "És possible que el vostre distribuïdor no hagi verificat cap de les actualitzacions del microprogramari per a la compatibilitat amb el vostre sistema o els dispositius connectats." +#. TRANSLATORS: %1 is the device vendor name +#, c-format +msgid "Your hardware may be damaged using this firmware, and installing this release may void any warranty with %s." +msgstr "El vostre maquinari pot danyar-se amb aquest microprogramari, i la instal·lació d'aquesta versió pot anul·lar qualsevol garantia amb %s." + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "[CHECKSUM]" +msgstr "[SUMA_DE_VERIFICACIÓ]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "[DEVICE-ID|GUID]" +msgstr "[ID_DISPOSITIU|GUID]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "[DEVICE-ID|GUID] [BRANCH]" +msgstr "[ID_DISPOSITIU|GUID] [BRANCA]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "[FILE FILE_SIG REMOTE-ID]" +msgstr "[FITXER SIGNATURA_FITXER ID_REMOT]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "[SMBIOS-FILE|HWIDS-FILE]" +msgstr "[FITXER-HWIDS-SMBIOS]" + +#. TRANSLATORS: this is the default branch name when unset +msgid "default" +msgstr "predeterminat" + #. TRANSLATORS: program name msgid "fwupd TPM event log utility" -msgstr "Utilitat per al registre d’esdeveniments TPM del fwupd" +msgstr "Utilitat per al registre d'esdeveniments TPM del fwupd" -#. TRANSLATORS: message letting the user know no device upgrade available due -#. to missing on LVFS -#. * %1 is the device name -#, c-format -msgid "• %s has no available firmware updates" -msgstr "• %s no té disponible cap actualització de microprogramari" - -#. TRANSLATORS: message letting the user know no device upgrade available -#. * %1 is the device name -#, c-format -msgid "• %s has the latest available firmware version" -msgstr "• %s té disponible la darrera versió del microprogramari" +#. TRANSLATORS: Title: if the fwupd plugins are all present and correct +msgid "fwupd plugins" +msgstr "Connectors del «fwupd»" diff -Nru fwupd-1.4.5/po/cs.po fwupd-1.5.8/po/cs.po --- fwupd-1.4.5/po/cs.po 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/po/cs.po 2021-03-31 20:08:32.000000000 +0000 @@ -6,6 +6,7 @@ # Ascii Wolf , 2017,2019-2020 # Ascii Wolf , 2017 # Marek Černocký , 2016,2018 +# Pavel Borecki , 2020-2021 msgid "" msgstr "" "Project-Id-Version: fwupd\n" @@ -24,11 +25,188 @@ msgstr[0] "Zbývá %.0f minuta" msgstr[1] "Zbývají %.0f minuty" msgstr[2] "Zbývá %.0f minut" -msgstr[3] "Zbývá %.0f minuty" +msgstr[3] "Zbývají %.0f minuty" -#. TRANSLATORS: this is when a device is hotplugged -msgid "Added" -msgstr "Přidáno" +#. TRANSLATORS: the CPU microcode is firmware loaded onto the CPU +#. * at system bootup +#, c-format +msgid "%s CPU Microcode Update" +msgstr "Aktualizace mikrokódu procesoru %s" + +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Secure Boot` +#, c-format +msgid "%s Configuration Update" +msgstr "Aktualizace nastavení %s" + +#. TRANSLATORS: ME stands for Management Engine, where +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Consumer ME Update" +msgstr "Aktualizace spotřebitelského ME v %s" + +#. TRANSLATORS: the controller is a device that has other devices +#. * plugged into it, for example ThunderBolt, FireWire or USB, +#. * the first %s is the device name, e.g. 'Intel ThunderBolt` +#, c-format +msgid "%s Controller Update" +msgstr "Aktualizace řadiče %s" + +#. TRANSLATORS: ME stands for Management Engine (with Intel AMT), +#. * where the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Corporate ME Update" +msgstr "Aktualizace korporátního ME v %s" + +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Unifying Receiver` +#, c-format +msgid "%s Device Update" +msgstr "Aktualizace zařízení %s" + +#. TRANSLATORS: the EC is typically the keyboard controller chip, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Embedded Controller Update" +msgstr "Aktualizace vestavěného řadiče v %s" + +#. TRANSLATORS: ME stands for Management Engine, the Intel AMT thing, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s ME Update" +msgstr "Aktualizace ME v %s" + +#. TRANSLATORS: the entire system, e.g. all internal devices, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s System Update" +msgstr "Celková aktualizace %s" + +#. TRANSLATORS: the Thunderbolt controller is a device that +#. * has other high speed Thunderbolt devices plugged into it; +#. * the first %s is the system name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Thunderbolt Controller Update" +msgstr "Aktualizace řadiče Thunderbolt %s" + +#. TRANSLATORS: this is the fallback where we don't know if the release +#. * is updating the system, the device, or a device class, or something else +#. -- +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Update" +msgstr "Aktualizace %s" + +#. TRANSLATORS: warn the user before updating, %1 is a device name +#, c-format +msgid "%s and all connected devices may not be usable while updating." +msgstr "%s a k němu připojená zařízení nemusí být v průběhu aktualizace použitelná." + +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s manufacturing mode" +msgstr "režim pro výrobce v %s" + +#. TRANSLATORS: warn the user before updating, %1 is a device name +#, c-format +msgid "%s must remain connected for the duration of the update to avoid damage." +msgstr "Je třeba, aby %s zůstalo v průběhu aktualizace připojené, jinak hrozí poškození." + +#. TRANSLATORS: warn the user before updating, %1 is a machine name +#, c-format +msgid "%s must remain plugged into a power source for the duration of the update to avoid damage." +msgstr "Je třeba, aby %s bylo po dobu aktualizace připojené ke zdroji napájení z elektrické sítě, jinak hrozí poškození." + +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s override" +msgstr "přebití %s" + +#. TRANSLATORS: Title: %1 is ME kind, e.g. CSME/TXT, %2 is a version number +#, c-format +msgid "%s v%s" +msgstr "%s verze %s" + +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s version" +msgstr "Verze %s" + +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u den" +msgstr[1] "%u dny" +msgstr[2] "%u dnů" +msgstr[3] "%u dny" + +#, c-format +msgid "%u device has a firmware upgrade available." +msgid_plural "%u devices have a firmware upgrade available." +msgstr[0] "Je k dispozici novější firmware pro %u zařízení." +msgstr[1] "Jsou k dispozici novější firmware pro %u zařízení." +msgstr[2] "Jsou k dispozici novější firmware pro %u zařízení." +msgstr[3] "Jsou k dispozici novější firmware pro %u zařízení." + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u hodina" +msgstr[1] "%u hodiny" +msgstr[2] "%u hodin" +msgstr[3] "%u hodiny" + +#. TRANSLATORS: how many local devices can expect updates now +#, c-format +msgid "%u local device supported" +msgid_plural "%u local devices supported" +msgstr[0] "%u zařízení v počítači podporováno" +msgstr[1] "%u zařízení v počítači podporováno" +msgstr[2] "%u zařízení v počítači podporováno" +msgstr[3] "%u zařízení v počítači podporováno" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u minuta" +msgstr[1] "%u minuty" +msgstr[2] "%u minut" +msgstr[3] "%u minuty" + +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u sekunda" +msgstr[1] "%u sekundy" +msgstr[2] "%u sekund" +msgstr[3] "%u sekundy" + +#. TRANSLATORS: this is shown as a suffix for obsoleted tests +msgid "(obsoleted)" +msgstr "(zastaralé)" + +#. TRANSLATORS: command description +msgid "Activate devices" +msgstr "Aktivovat zařízení" + +#. TRANSLATORS: command description +msgid "Activate pending devices" +msgstr "Aktivovat čekající zařízení" + +msgid "Activate the new firmware on the device" +msgstr "Aktivovat nový firmware na zařízení" + +#. TRANSLATORS: shown when shutting down to switch to the new version +msgid "Activating firmware update" +msgstr "Aktivování aktualizace firmware" + +#. TRANSLATORS: shown when shutting down to switch to the new version +msgid "Activating firmware update for" +msgstr "Aktivace aktualizovaného firmware pro" #. TRANSLATORS: the age of the metadata msgid "Age" @@ -49,12 +227,20 @@ #. TRANSLATORS: command line option msgid "Allow reinstalling existing firmware versions" -msgstr "Povolit reinstalaci stávající verze firmwaru" +msgstr "Povolit přeinstalaci stávající verze firmwaru" + +#. TRANSLATORS: command line option +msgid "Allow switching firmware branch" +msgstr "Umožnit přepnutí varianty firmware" #. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Některá z aktualizací vyžaduje pro dokončení restart." +#. TRANSLATORS: explain why we want to shutdown +msgid "An update requires the system to shutdown to complete." +msgstr "Pro dokončení aktualizace je zapotřebí vypnutí počítače." + #. TRANSLATORS: command line option msgid "Answer yes to all questions" msgstr "Na všechny dotazy odpovědět ano" @@ -63,6 +249,31 @@ msgid "Apply firmware updates" msgstr "Použít aktualizace firmwaru" +#. TRANSLATORS: command line option +msgid "Apply update even when not advised" +msgstr "Použít aktualizaci i když to není doporučeno" + +#. TRANSLATORS: command line option +msgid "Apply update files" +msgstr "Použít soubory s aktualizací" + +#. TRANSLATORS: actually sending the update to the hardware +msgid "Applying update…" +msgstr "Provádění aktualizace…" + +#. TRANSLATORS: approved firmware has been checked by +#. * the domain administrator +msgid "Approved firmware:" +msgid_plural "Approved firmware:" +msgstr[0] "Schválený firmware:" +msgstr[1] "Schválené firmwary:" +msgstr[2] "Schválených firmwarů:" +msgstr[3] "Schválené firmwary:" + +#. TRANSLATORS: stop nagging the user +msgid "Ask again next time?" +msgstr "Ptát se i příště?" + #. TRANSLATORS: command description msgid "Attach to firmware mode" msgstr "Napojit do režimu firmwaru" @@ -73,36 +284,95 @@ #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on a removable device" -msgstr "K přechodu na nižší verzi firmwaru na výměnném zařízení je vyžadováno ověření" +msgstr "K přechodu na nižší verzi firmwaru na výměnném zařízení je vyžadováno ověření se" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "K přechodu na nižší verzi firmwaru na tomto počítači je vyžadováno ověření" +msgstr "K přechodu na nižší verzi firmwaru na tomto počítači je vyžadováno ověření so" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to modify a configured remote used for firmware updates" msgstr "Ke změně nastaveného vzdáleného zdroje, který se používá pro aktualizace firmwaru, je vyžadováno ověření" #. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify daemon configuration" +msgstr "Ke změně nastavení procesu služby je vyžadováno ověření se" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to set the list of approved firmware" +msgstr "Pro nastavení seznamu schválených firmwarů je vyžadováno ověření se" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to sign data using the client certificate" +msgstr "Pro podepsání dat klientským certifikátem je třeba ověření se" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to switch to the new firmware version" +msgstr "Pro přepnutí na novou verzi firmware je vyžadováno ověření se" + +#. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to unlock a device" msgstr "Pro odemknutí zařízení je požadováno ověření" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to update the firmware on a removable device" -msgstr "K aktualizaci firmwaru na výměnném zařízení je vyžadováno ověření" +msgstr "K aktualizaci firmwaru na výměnném zařízení je vyžadováno ověření se" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to update the firmware on this machine" -msgstr "K aktualizaci firmwaru na tomto počítači je vyžadováno ověření" +msgstr "K aktualizaci firmwaru na tomto počítači je vyžadováno ověření se" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to update the stored checksums for the device" -msgstr "K aktualizaci uložených kontrolních součtů zařízení je vyžadováno ověření" +msgstr "K aktualizaci uložených kontrolních součtů zařízení je vyžadováno ověření se" + +#. TRANSLATORS: Boolean value to automatically send reports +msgid "Automatic Reporting" +msgstr "Automatické odesílání hlášení" + +#. TRANSLATORS: can we JFDI? +msgid "Automatically upload every time?" +msgstr "Pokaždé automaticky nahrát?" + +msgid "BYTES" +msgstr "BAJTŮ" + +#. TRANSLATORS: command description +msgid "Bind new kernel driver" +msgstr "Napojit nový ovladač jádra" + +#. TRANSLATORS: there follows a list of hashes +msgid "Blocked firmware files:" +msgstr "Blokované soubory s firmware:" + +#. TRANSLATORS: we will not offer this firmware to the user +msgid "Blocking firmware:" +msgstr "Blokuje se firmware:" + +#. TRANSLATORS: command description +msgid "Blocks a specific firmware from being installed" +msgstr "Blokuje instalaci konkrétního firmware" + +#. TRANSLATORS: firmware version of bootloader +msgid "Bootloader Version" +msgstr "Verze zavaděče firmware" + +#. TRANSLATORS: the stream of firmware, e.g. nonfree or open-source +msgid "Branch" +msgstr "Větev" + +#. TRANSLATORS: command description +msgid "Build a firmware file" +msgstr "Sestavit soubor s firmware" #. TRANSLATORS: command description msgid "Build firmware using a sandbox" msgstr "Sestavit firmware za použití izolovaného prostředí" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "CHECKSUM1[,CHECKSUM2][,CHECKSUM3]" +msgstr "KONTROLNÍ-SOUČET1[,KONTROLNÍ-SOUČET2][,KONTROLNÍ-SOUČET3]" + #. TRANSLATORS: this is to abort the interactive prompt msgid "Cancel" msgstr "Zrušit" @@ -111,23 +381,47 @@ msgid "Cancelled" msgstr "Zrušeno" -#. TRANSLATORS: this is when a device is hotplugged +#. TRANSLATORS: same or newer update already applied +msgid "Cannot apply as dbx update has already been applied." +msgstr "Tuto aktualizaci dbx už není možné použít, protože už je používána." + +#. TRANSLATORS: the user is using a LiveCD or LiveUSB install disk +msgid "Cannot apply updates on live media" +msgstr "Aktualizace není možné použít při provozování systému z instalačního média (live)" + #. TRANSLATORS: this is when the daemon state changes msgid "Changed" msgstr "Změněno" +#. TRANSLATORS: command description +msgid "Checks cryptographic hash matches firmware" +msgstr "Zkontroluje zda se kryptografický otisk shoduje s firmware" + #. TRANSLATORS: remote checksum msgid "Checksum" msgstr "Kontrolní součet" +#. TRANSLATORS: get interactive prompt, where branch is the +#. * supplier of the firmware, e.g. "non-free" or "free" +msgid "Choose a branch:" +msgstr "Zvolte variantu firmware:" + #. TRANSLATORS: get interactive prompt msgid "Choose a device:" msgstr "Vyberte zařízení:" #. TRANSLATORS: get interactive prompt +msgid "Choose a firmware type:" +msgstr "Zvolte typ firmware:" + +#. TRANSLATORS: get interactive prompt msgid "Choose a release:" msgstr "Vyberte verzi:" +#. TRANSLATORS: get interactive prompt +msgid "Choose a volume:" +msgstr "Zvolte svazek:" + #. TRANSLATORS: command description msgid "Clears any updates scheduled to be updated offline" msgstr "Smazat vše naplánované pro aktualizaci při odpojení" @@ -140,6 +434,34 @@ msgid "Command not found" msgstr "Příkaz nebyl nalezen" +#. TRANSLATORS: prompt to apply the update +msgid "Continue with update?" +msgstr "Pokračovat v aktualizaci?" + +#. TRANSLATORS: command description +msgid "Convert a firmware file" +msgstr "Převést soubor s firmware" + +#. TRANSLATORS: when the update was built +msgid "Created" +msgstr "Vytvořeno" + +#. TRANSLATORS: the release urgency +msgid "Critical" +msgstr "Kritická" + +#. TRANSLATORS: Device supports some form of checksum verification +msgid "Cryptographic hash verification is available" +msgstr "Je k dispozici kryptografické ověření otisku" + +#. TRANSLATORS: version number of current firmware +msgid "Current version" +msgstr "Stávající verze" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "DEVICE-ID|GUID" +msgstr "IDENTIF-ZAŘÍZENÍ|GUID" + #. TRANSLATORS: DFU stands for device firmware update msgid "DFU Utility" msgstr "Nástroj pro práci s DFU" @@ -160,18 +482,70 @@ msgid "Detach to bootloader mode" msgstr "Odpojit do režimu zavaděče" +#. TRANSLATORS: more details about the update link +msgid "Details" +msgstr "Podrobnosti" + +#. TRANSLATORS: description of device ability +msgid "Device Flags" +msgstr "Příznaky zařízení" + +#. TRANSLATORS: ID for hardware, typically a SHA1 sum +msgid "Device ID" +msgstr "Identifikátor zařízení" + #. TRANSLATORS: this is when a device is hotplugged msgid "Device added:" msgstr "Přidáno zařízení:" +#. TRANSLATORS: Device supports a safety mechanism for flashing +msgid "Device can recover flash failures" +msgstr "Zařízení se dovede vzpamatovat z nezdaru při zápisu firmware" + #. TRANSLATORS: this is when a device has been updated msgid "Device changed:" msgstr "Změněno zařízení:" +#. TRANSLATORS: a version check is required for all firmware +msgid "Device firmware is required to have a version check" +msgstr "Je třeba, aby firmware zařízení měl kontrolu verze" + +#. TRANSLATORS: Is locked and can be unlocked +msgid "Device is locked" +msgstr "Zařízení je uzamčeno" + +#. TRANSLATORS: a version check is required for all firmware +msgid "Device is required to install all provided releases" +msgstr "Zařízení vyžaduje instalaci všech poskytnutých vydání" + +#. TRANSLATORS: Device remains usable during update +msgid "Device is usable for the duration of the update" +msgstr "Zařízení je možné používat i v průběhu aktualizace" + #. TRANSLATORS: this is when a device is hotplugged msgid "Device removed:" msgstr "Odebráno zařízení:" +#. TRANSLATORS: Device supports a safety mechanism for flashing +msgid "Device stages updates" +msgstr "Zařízení podporuje rozfázované aktualizace" + +#. TRANSLATORS: there is more than one supplier of the firmware +msgid "Device supports switching to a different branch of firmware" +msgstr "Zařízení podporuje přepínání mezi různými větvemi firmware" + +#. TRANSLATORS: Device update needs to be separately activated +msgid "Device update needs activation" +msgstr "Zařízení je pro aktualizaci třeba aktivovat" + +#. TRANSLATORS: save the old firmware to disk before installing the new one +msgid "Device will backup firmware before installing" +msgstr "Zařízení provede zálohu stávajícího firmware před instalací nového" + +#. TRANSLATORS: Device will not return after update completes +msgid "Device will not re-appear after update completes" +msgstr "Po dokončení aktualizace se zařízení hned znovu neobjeví" + #. TRANSLATORS: a list of successful updates msgid "Devices that have been updated successfully:" msgstr "Zařízení, která byla úspěšně aktualizována:" @@ -180,6 +554,20 @@ msgid "Devices that were not updated correctly:" msgstr "Zařízení, která nebyla úspěšně aktualizována:" +#. TRANSLATORS: message letting the user know no device upgrade available due +#. to missing on LVFS +msgid "Devices with no available firmware updates: " +msgstr "Zařízení, ke kterém nejsou k dispozici aktualizace firmware:" + +#. TRANSLATORS: message letting the user know no device upgrade available +msgid "Devices with the latest available firmware version:" +msgstr "Zařízení s nejnovějšími dostupnými verzemi firmware:" + +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is inactive and not used +msgid "Disabled" +msgstr "Vypnuto" + msgid "Disabled fwupdate debugging" msgstr "Vypnout ladění fwupdate" @@ -204,9 +592,44 @@ msgstr "Nekontrolovat nenahlášení historie" #. TRANSLATORS: command line option +msgid "Do not check if download remotes should be enabled" +msgstr "Nekontrolovat zda by mělo být zapnuté stahování ze vzdálených" + +#. TRANSLATORS: turn on all debugging +msgid "Do not include log domain prefix" +msgstr "Nepřidávat dlouhou příponu oblasti" + +#. TRANSLATORS: turn on all debugging +msgid "Do not include timestamp prefix" +msgstr "Nepřidávat příponu s datem a časem" + +#. TRANSLATORS: command line option +msgid "Do not perform device safety checks" +msgstr "Neprovádět kontroly bezpečnosti zařízení" + +msgid "Do not upload report at this time, but prompt again for future updates" +msgid_plural "Do not upload reports at this time, but prompt again for future updates" +msgstr[0] "Nyní hlášení neodesílat, ale při budoucích aktualizacích se znovu zeptat" +msgstr[1] "Nyní hlášení neodesílat, ale při budoucích aktualizacích se znovu zeptat" +msgstr[2] "Nyní hlášení neodesílat, ale při budoucích aktualizacích se znovu zeptat" +msgstr[3] "Nyní hlášení neodesílat, ale při budoucích aktualizacích se znovu zeptat" + +msgid "Do not upload report, and never ask to upload reports for future updates" +msgid_plural "Do not upload reports, and never ask to upload reports for future updates" +msgstr[0] "Neodesílat hlášení, a nikdy se neptat na odesílání hlášení u budoucích aktualizací" +msgstr[1] "Neodesílat hlášení, a nikdy se neptat na odesílání hlášení u budoucích aktualizací" +msgstr[2] "Neodesílat hlášení, a nikdy se neptat na odesílání hlášení u budoucích aktualizací" +msgstr[3] "Neodesílat hlášení, a nikdy se neptat na odesílání hlášení u budoucích aktualizací" + +#. TRANSLATORS: command line option msgid "Do not write to the history database" msgstr "Nezapisovat do databáze historie" +#. TRANSLATORS: should the branch be changed +msgid "Do you understand the consequences of changing the firmware branch?" +msgstr "Rozumíte důsledkům změny větve firmware?" + +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Hotovo!" @@ -220,7 +643,12 @@ #. * version numbers e.g. "1.2.3" #, c-format msgid "Downgrading %s from %s to %s... " -msgstr "Převádí se %s z verze %s na %s…" +msgstr "Přechází se na starší verzi %s z verze %s na %s…" + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "Vracení %s na starší verzi…" #. TRANSLATORS: downloading from a remote server msgid "Downloading…" @@ -230,6 +658,10 @@ msgid "Dump SMBIOS data from a file" msgstr "Vypsat data SMBIOS ze souboru" +#. TRANSLATORS: length of time the update takes to apply +msgid "Duration" +msgstr "Délka instalace" + #. TRANSLATORS: ESP is EFI System Partition msgid "ESP specified was not valid" msgstr "Určený ESP není platný" @@ -242,6 +674,8 @@ msgid "Enable this remote?" msgstr "Povolit tento vzdálený zdroj?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Povoleno" @@ -254,12 +688,20 @@ msgstr "Povolit zadaný vzdálený zdroj" msgid "Enabling this functionality is done at your own risk, which means you have to contact your original equipment manufacturer regarding any problems caused by these updates. Only problems with the update process itself should be filed at $OS_RELEASE:BUG_REPORT_URL$." -msgstr "Zapnutí této funkcionality je na vaše vlastní riziko, což znamená, že v případě problémů způsobených aktualizací musíte kontaktovat přímo výrobce zařízení. Pouze problémy s aktualizačním procesem jako takovým by měly být hlášeny na $OS_RELEASE:BUG_REPORT_URL$." +msgstr "Zapnutí této funkce je na vaše vlastní riziko. To znamená, že v případě problémů způsobených aktualizací je třeba, abyste se obrátili přímo na výrobce zařízení. Na adresu $OS_RELEASE:BUG_REPORT_URL$ by měly být hlášeny pouze problémy s aktualizačním procesem jako takovým." #. TRANSLATORS: show the user a warning msgid "Enabling this remote is done at your own risk." msgstr "Povolení tohoto zdroje je na vaše vlastní riziko." +#. TRANSLATORS: Suffix: the HSI result +msgid "Encrypted" +msgstr "Šifrované" + +#. TRANSLATORS: Title: Memory contents are encrypted, e.g. Intel TME +msgid "Encrypted RAM" +msgstr "Šifrovaná RAM" + #. TRANSLATORS: command description msgid "Erase all firmware update history" msgstr "Smazat veškerou historii aktualizací" @@ -276,33 +718,100 @@ msgid "Exit after the engine has loaded" msgstr "Skončit po načtení výkonné části" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "Nezdařilo se stáhnout kvůli omezením serveru" +#. TRANSLATORS: command description +msgid "Extract a firmware blob to images" +msgstr "Rozbalit firmware z blobu do obrazů" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILE" +msgstr "SOUBOR" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILE [DEVICE-ID|GUID]" +msgstr "SOUBOR [IDENTIF-ZAŘÍZENÍ|GUID]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME" +msgstr "SOUBOR" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME DEVICE-ALT-NAME|DEVICE-ALT-ID" +msgstr "SOUBOR ALTERN-NÁZEV-ZAŘÍZENÍ|ALTERN-IDENTIF-ZAŘÍZENÍ" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME DEVICE-ALT-NAME|DEVICE-ALT-ID [IMAGE-ALT-NAME|IMAGE-ALT-ID]" +msgstr "SOUBOR ALTERN-NÁZEV-ZAŘÍZENÍ|ALTENRN-IDENTIF-ZAŘÍZENÍ [ALTERN-NÁZEV-OBRAZU|ALTERN-IDENTIF-OBRAZU]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME DEVICE-ID" +msgstr "NÁZEV-SOUBORU IDENTIFIKÁTOR-ZAŘÍZENÍ" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME [FIRMWARE-TYPE]" +msgstr "NÁZEV-SOUBORU [TYP-FIRMWARE]" + +#. TRANSLATORS: Suffix: the fallback HSI result +#. TRANSLATORS: The update state of the specific device +msgid "Failed" +msgstr "Nezdařilo se" + +#. TRANSLATORS: dbx file failed to be applied as an update +msgid "Failed to apply update" +msgstr "Aktualizaci se nepodařilo provést" + +#. TRANSLATORS: we could not talk to the fwupd daemon +msgid "Failed to connect to daemon" +msgstr "Nepodařilo se spojit s procesem služby" + +#. TRANSLATORS: we could not get the devices to update offline +msgid "Failed to get pending devices" +msgstr "Nepodařilo se získat čekající zařízení" + +#. TRANSLATORS: we could not install for some reason +msgid "Failed to install firmware update" +msgstr "Aktualizaci firmware se nepodařilo nainstalovat" + +#. TRANSLATORS: could not read existing system data +#. TRANSLATORS: could not read file +msgid "Failed to load local dbx" +msgstr "Nepodařilo se načíst místní dbx" #. TRANSLATORS: quirks are device-specific workarounds msgid "Failed to load quirks" -msgstr "Selhalo načtení zvláštních požadavků" +msgstr "Načtení zvláštních požadavků (quirks) se nezdařilo" + +#. TRANSLATORS: could not read existing system data +msgid "Failed to load system dbx" +msgstr "Nepodařilo se načíst systémové dbx" #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" -msgstr "Selhalo zpracování argumentů" +msgstr "Zpracování argumentů se nezdařilo" + +#. TRANSLATORS: failed to read measurements file +msgid "Failed to parse file" +msgstr "Soubor se nepodařilo zpracovat" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "Stahuje se soubor" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "Stahuje se firmware" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "Stahují se metadata" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "Stahuje se podpis" +#. TRANSLATORS: the user didn't read the man page +msgid "Failed to parse flags for --filter" +msgstr "Nepodařilo se zpracovat příznaky pro --filter" + +#. TRANSLATORS: could not parse file +msgid "Failed to parse local dbx" +msgstr "Nepodařilo se zpracovat místní dbx" + +#. TRANSLATORS: we could not reboot for some reason +msgid "Failed to reboot" +msgstr "Nepodařilo se restartovat" + +#. TRANSLATORS: we could not talk to plymouth +msgid "Failed to set splash mode" +msgstr "Nepodařilo se nastavit režim startovací obrazovky" + +#. TRANSLATORS: something with a blocked hash exists +#. * in the users ESP -- which would be bad! +msgid "Failed to validate ESP contents" +msgstr "Nepodařilo se ověřit obsah ESP oddílu" #. TRANSLATORS: filename of the local file msgid "Filename" @@ -312,6 +821,18 @@ msgid "Filename Signature" msgstr "Podpis názvu souboru" +#. TRANSLATORS: user did not include a filename parameter +msgid "Filename required" +msgstr "Je zapotřebí zadat název souboru" + +#. TRANSLATORS: command line option +msgid "Filter with a set of device flags using a ~ prefix to exclude, e.g. 'internal,~needs-reboot'" +msgstr "Filtrovat podle sady příznaků zařízení pomocí předpony (~ pro vynechání), např. „internal,~needs-reboot“" + +#. TRANSLATORS: program name +msgid "Firmware Agent" +msgstr "Firmware Agent" + #. TRANSLATORS: remote URI msgid "Firmware Base URI" msgstr "Základní URI firmwaru" @@ -322,12 +843,28 @@ #. TRANSLATORS: program name msgid "Firmware Update Daemon" -msgstr "Démon pro aktualizaci firmwaru" +msgstr "Proces služby pro aktualizaci firmwaru" #. TRANSLATORS: program name msgid "Firmware Utility" msgstr "Nástroj pro práci s firmwarem" +#. TRANSLATORS: Title: if we can verify the firmware checksums +msgid "Firmware attestation" +msgstr "Atestace firmware" + +#. TRANSLATORS: system is not booted in UEFI mode +msgid "Firmware can not be updated in legacy BIOS mode" +msgstr "Firmware není možné aktualizovat v původním BIOS režimu" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is already blocked" +msgstr "Firmware už je blokován" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is not already blocked" +msgstr "Firmware ještě není blokován" + #. TRANSLATORS: the metadata is very out of date; %u is a number > 1 #, c-format msgid "Firmware metadata has not been updated for %u day and may not be up to date." @@ -337,12 +874,57 @@ msgstr[2] "Metadata firmwaru nebyla akualizována již %u dní a nelze je aktualizovat." msgstr[3] "Metadata firmwaru nebyla akualizována již %u dne a nelze je aktualizovat." +#. TRANSLATORS: Title: if firmware updates are available +msgid "Firmware updates" +msgstr "Aktualizace firmware" + msgid "Firmware updates are not supported on this machine." msgstr "Aktualizace firmwaru nejsou na tomto počítači podporované." msgid "Firmware updates are supported on this machine." msgstr "Aktualizace firmwaru jsou na tomto počítači podporované." +#. TRANSLATORS: user needs to run a command +msgid "Firmware updates disabled; run 'fwupdmgr unlock' to enable" +msgstr "Aktualizace firmware jsou zakázané; pro jejich povolení spusťte „fwupdmgr unlock“" + +#. TRANSLATORS: description of plugin state, e.g. disabled +#. TRANSLATORS: release properties +msgid "Flags" +msgstr "Příznaky" + +#. TRANSLATORS: command line option +msgid "Force the action by relaxing some runtime checks" +msgstr "Vynutit akci uvolněním některých kontrol při vykonávání" + +msgid "Force the action ignoring all warnings" +msgstr "Vynutit, aby při akci byla ignorována všechna varování" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Nalezeno" + +#. TRANSLATORS: global ID common to all similar hardware +msgid "GUID" +msgid_plural "GUIDs" +msgstr[0] "Globálně neopakující se identifikátor" +msgstr[1] "Globálně neopakující se identifikátory" +msgstr[2] "Globálně neopakujících se identifikátorů" +msgstr[3] "Globálně neopakující se identifikátory" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgctxt "A single GUID" +msgid "GUID" +msgstr "GUID" + +#. TRANSLATORS: command description +msgid "Get all device flags supported by fwupd" +msgstr "Získat všechny příznaky zařízení podporované fwupd" + +#. TRANSLATORS: command description +msgid "Get all devices and possible releases" +msgstr "Zjistit všechna zařízení a vydání, která jsou možná" + #. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "Zjistit všechna zařízení podporující aktualizaci firmwaru" @@ -360,6 +942,18 @@ msgstr "Vypsat nastavené vzdálené zdroje" #. TRANSLATORS: command description +msgid "Gets the host security attributes" +msgstr "Zjistit atributy zabezpečení hostitele" + +#. TRANSLATORS: firmware approved by the admin +msgid "Gets the list of approved firmware" +msgstr "Získá seznam schválených firmware" + +#. TRANSLATORS: command description +msgid "Gets the list of blocked firmware" +msgstr "Získá seznam blokovaných firmware" + +#. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "Vypsat seznam aktualizací pro připojený hardware" @@ -371,10 +965,55 @@ msgid "Gets the results from the last update" msgstr "Vypsat výsledky z poslední aktualizace" +#. TRANSLATORS: The hardware is waiting to be replugged +msgid "Hardware is waiting to be replugged" +msgstr "Hardware čeká na opětovné připojení" + +#. TRANSLATORS: the release urgency +msgid "High" +msgstr "Vysoká" + +#. TRANSLATORS: this is a string like 'HSI:2-U' +msgid "Host Security ID:" +msgstr "Identifikátor zabezpečení hostitele:" + +#. TRANSLATORS: Title: +#. https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit +msgid "IOMMU" +msgstr "IOMMU" + #. TRANSLATORS: daemon is inactive msgid "Idle…" msgstr "Nečinný…" +#. TRANSLATORS: command line option +msgid "Ignore SSL strict checks when downloading files" +msgstr "Při stahování souborů ignorovat některé nedostatky SSL certifikátů" + +#. TRANSLATORS: command line option +msgid "Ignore firmware checksum failures" +msgstr "Ignorovat nesprávný kontrolní součet firmware" + +#. TRANSLATORS: command line option +msgid "Ignore firmware hardware mismatch failures" +msgstr "Ignorovat neshody firmware s hardware" + +#. TRANSLATORS: command line option +msgid "Ignore requirement of external power source" +msgstr "Ignorovat požadavek na přítomnost externího napájení" + +#. TRANSLATORS: Ignore validation safety checks when flashing this device +msgid "Ignore validation safety checks" +msgstr "Ignorovat výsledky kontrol ověření" + +#. TRANSLATORS: try to help +msgid "Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" +msgstr "Ignorovat striktní SSL kontroly. Pokud chcete, aby se tak příště stalo automaticky, nastavte (a exportujte) proměnnou prosstředí DISABLE_SSL_STRICT" + +#. TRANSLATORS: length of time the update takes to apply +msgid "Install Duration" +msgstr "Délka instalace" + #. TRANSLATORS: command description msgid "Install a firmware blob on a device" msgstr "Nainstalovat na zařízení binární soubor s firmwarem" @@ -392,12 +1031,20 @@ msgid "Install signed system firmware" msgstr "Instalace podepsaného systémového firmwaru" +#. TRANSLATORS: Install composite firmware on the parent before the child +msgid "Install to parent device first" +msgstr "Nejprve nainstalovat do nadřazeného zařízení" + msgid "Install unsigned device firmware" msgstr "Instalace nepodepsaného firmwaru zařízení" msgid "Install unsigned system firmware" msgstr "Instalace nepodepsaného systémového firmwaru" +#. TRANSLATORS: console message when no Plymouth is installed +msgid "Installing Firmware…" +msgstr "Instalace firmware…" + #. TRANSLATORS: this is shown when updating the firmware after the reboot msgid "Installing firmware update…" msgstr "Instaluje se aktualizace firmwaru…" @@ -407,30 +1054,159 @@ msgid "Installing on %s…" msgstr "Instaluje se na zařízení %s…" +#. TRANSLATORS: Title: BootGuard is a trademark from Intel +msgid "Intel BootGuard" +msgstr "Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * ACM means to verify the integrity of Initial Boot Block +msgid "Intel BootGuard ACM protected" +msgstr "Chráněno Intel BootGuard ACM" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * OTP = one time programmable +msgid "Intel BootGuard OTP fuse" +msgstr "Intel BootGuard OTP pojistka" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * error policy is what to do on failure +msgid "Intel BootGuard error policy" +msgstr "Co Intel BootGuard udělá v případě chyb" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * verified boot refers to the way the boot process is verified +msgid "Intel BootGuard verified boot" +msgstr "Ověřené zavádění s Intel BootGuard" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * active means being used by the OS +msgid "Intel CET Active" +msgstr "Intel CET aktivní" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * enabled means supported by the processor +msgid "Intel CET Enabled" +msgstr "Intel CET podporováno" + +#. TRANSLATORS: Title: Direct Connect Interface (DCI) allows +#. * debugging of Intel processors using the USB3 port +msgid "Intel DCI debugger" +msgstr "Ladící nástroj Intel DCI" + +#. TRANSLATORS: Title: SMAP = Supervisor Mode Access Prevention +msgid "Intel SMAP" +msgstr "Intel SMAP" + +#. TRANSLATORS: Device cannot be removed easily +msgid "Internal device" +msgstr "Vestavěné zařízení" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Invalid" +msgstr "Neplatné" + +#. TRANSLATORS: Is currently in bootloader mode +msgid "Is in bootloader mode" +msgstr "Je v režimu zavaděče" + +#. TRANSLATORS: issue fixed with the release, e.g. CVE +msgid "Issue" +msgid_plural "Issues" +msgstr[0] "Problém" +msgstr[1] "Problémy" +msgstr[2] "Problémů" +msgstr[3] "Problémy" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "KEY,VALUE" +msgstr "KLÍČ,HODNOTA" + msgid "Keyring" msgstr "Klíčenka" +#. TRANSLATORS: the original time/date the device was modified +msgid "Last modified" +msgstr "Naposledy změněno" + #. TRANSLATORS: time remaining for completing firmware flash msgid "Less than one minute remaining" msgstr "Zbývá méně než jedna minuta" +#. TRANSLATORS: e.g. GPLv2+, Proprietary etc +msgid "License" +msgstr "Licence" + msgid "Linux Vendor Firmware Service (stable firmware)" msgstr "Linux Vendor Firmware Service (stabilní firmware)" msgid "Linux Vendor Firmware Service (testing firmware)" msgstr "Linux Vendor Firmware Service (testovací firmware)" +#. TRANSLATORS: Title: if it's tainted or not +msgid "Linux kernel" +msgstr "Linuxové jádro" + +#. TRANSLATORS: Title: lockdown is a security mode of the kernel +msgid "Linux kernel lockdown" +msgstr "Uzamčení linuxového jádra" + +#. TRANSLATORS: Title: swap space or swap partition +msgid "Linux swap" +msgstr "Linuxový odkládací prostor" + +#. TRANSLATORS: command line option +msgid "List entries in dbx" +msgstr "Vypsat položky v dbx" + #. TRANSLATORS: command line option msgid "List supported firmware updates" msgstr "Vypsat podporované aktualizace firmwarů" +#. TRANSLATORS: command description +msgid "List the available firmware types" +msgstr "Vypsat typy firmware, které jsou k dispozici" + +#. TRANSLATORS: command description +msgid "Lists files on the ESP" +msgstr "Vypíše soubory na ESP oddílu" + #. TRANSLATORS: parsing the firmware information msgid "Loading…" msgstr "Načítá se…" -#. TRANSLATORS: command line option -msgid "Manually whitelist specific plugins" -msgstr "Ručně povolit konkrétní zásuvné moduly" +#. TRANSLATORS: Suffix: the HSI result +msgid "Locked" +msgstr "Zamčeno" + +#. TRANSLATORS: the release urgency +msgid "Low" +msgstr "Nízká" + +#. TRANSLATORS: Title: MEI = Intel Management Engine +msgid "MEI manufacturing mode" +msgstr "MEI režim pro výrobu" + +#. TRANSLATORS: Title: MEI = Intel Management Engine, and the +#. * "override" is the physical PIN that can be driven to +#. * logic high -- luckily it is probably not accessible to +#. * end users on consumer boards +msgid "MEI override" +msgstr "MEI přebití" + +msgid "MEI version" +msgstr "Verze MEI" + +#. TRANSLATORS: command line option +msgid "Manually enable specific plugins" +msgstr "Ručně zapnout konkrétní zásuvné moduly" + +#. TRANSLATORS: the release urgency +msgid "Medium" +msgstr "Střední" + +#. TRANSLATORS: remote URI +msgid "Metadata Signature" +msgstr "Podpis metadat" #. TRANSLATORS: remote URI msgid "Metadata URI" @@ -440,6 +1216,19 @@ msgid "Metadata can be obtained from the Linux Vendor Firmware Service." msgstr "Metadata lze získat ze služby Linux Vendor Firmware." +#. TRANSLATORS: smallest version number installable on device +msgid "Minimum Version" +msgstr "Nejstarší použitelná verze" + +#. TRANSLATORS: error message +#, c-format +msgid "Mismatched daemon and client, use %s instead" +msgstr "Nesoulad verzí procesu služby a klienta, namísto toho použijte %s" + +#. TRANSLATORS: sets something in daemon.conf +msgid "Modifies a daemon configuration value" +msgstr "Změní hodnotu v nastavení procesu služby" + #. TRANSLATORS: command description msgid "Modifies a given remote" msgstr "Změnit zadaný vzdálený zdroj" @@ -447,13 +1236,47 @@ msgid "Modify a configured remote" msgstr "Upravit nastavený vzdálený zdroj" +msgid "Modify daemon configuration" +msgstr "Upravit nastavení procesu služby" + #. TRANSLATORS: command description msgid "Monitor the daemon for events" -msgstr "Sledovat události démona" +msgstr "Sledovat události v procesu služby" + +#. TRANSLATORS: command description +msgid "Mounts the ESP" +msgstr "Připojí ESP oddíl" + +#. TRANSLATORS: Requires a reboot to apply firmware or to reload hardware +msgid "Needs a reboot after installation" +msgstr "Po instalaci vyžaduje restart" + +#. TRANSLATORS: The update state of the specific device +msgid "Needs reboot" +msgstr "Vyžaduje restart" +#. TRANSLATORS: Requires system shutdown to apply firmware +msgid "Needs shutdown after installation" +msgstr "Po instalaci vyžaduje vypnutí" + +#. TRANSLATORS: version number of new firmware +msgid "New version" +msgstr "Nová verze" + +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "Není určena žádné akce!" +#. TRANSLATORS: message letting the user know no device downgrade available +#. * %1 is the device name +#, c-format +msgid "No downgrades for %s" +msgstr "Pro %s nejsou k dispozici žádné starší verze" + +#. TRANSLATORS: nothing found +msgid "No firmware IDs found" +msgstr "Nenalezeny žádné identifikátory firmware" + #. TRANSLATORS: nothing attached that can be upgraded msgid "No hardware detected with firmware update capability" msgstr "Nebylo nalezeno žádné zařízení schopné aktualizace firmwaru" @@ -462,18 +1285,66 @@ msgid "No plugins found" msgstr "Nebyl nalezen žádný zásuvný modul" +#. TRANSLATORS: no repositories to download from +msgid "No releases available" +msgstr "Nejsou k dispozici žádná vydání" + #. TRANSLATORS: explain why no metadata available msgid "No remotes are currently enabled so no metadata is available." msgstr "Zrovna nejsou povolené žádné vzdálené zdroje, takže nejsou k dispozici žádná metadata." +#. TRANSLATORS: no repositories to download from +msgid "No remotes available" +msgstr "Nejsou k dispozici žádné protějšky" + +#. TRANSLATORS: nothing was updated offline +msgid "No updates were applied" +msgstr "Nebyly nainstalovány žádné aktualizace" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Not found" +msgstr "Nenalezeno" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Not supported" +msgstr "Nepodporováno" + +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "V pořádku" + #. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Potlačit varování zásuvného modulu" +msgid "Only show single PCR value" +msgstr "Zobrazit pouze jedinou PCR hodnotu" + +#. TRANSLATORS: command line option +msgid "Only use IPFS when downloading files" +msgstr "IFPS použít pouze při stahování souborů" #. TRANSLATORS: command line option msgid "Override the default ESP path" msgstr "Přepsat výchozí cestu ESP" +#. TRANSLATORS: command line option +msgid "Override warnings and force the action" +msgstr "Přebít varování a vynutit akci" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "PATH" +msgstr "POPIS-UMÍSTĚNÍ" + +#. TRANSLATORS: command description +msgid "Parse and show details about a firmware file" +msgstr "Zpracovat a zobrazit podrobnosti o souboru s firmware" + +#. TRANSLATORS: reading new dbx from the update +msgid "Parsing dbx update…" +msgstr "Zpracovávání aktualizace dbx…" + +#. TRANSLATORS: reading existing dbx from the system +msgid "Parsing system dbx…" +msgstr "Zpracovávání systémového dbx…" + #. TRANSLATORS: remote filename base msgid "Password" msgstr "Heslo" @@ -481,11 +1352,37 @@ msgid "Payload" msgstr "Obsah" +#. TRANSLATORS: The update state of the specific device +msgid "Pending" +msgstr "Čeká" + +#. TRANSLATORS: console message when not using plymouth +msgid "Percentage complete" +msgstr "Dokončeno procent" + #. TRANSLATORS: the user isn't reading the question #, c-format msgid "Please enter a number from 0 to %u: " msgstr "Zadejte prosím číslo od 0 do %u:" +#. TRANSLATORS: Failed to open plugin, hey Arch users +msgid "Plugin dependencies missing" +msgstr "Chybí komponenty, na kterých zásuvný modul závisí" + +#. TRANSLATORS: Title: DMA as in https://en.wikipedia.org/wiki/DMA_attack +msgid "Pre-boot DMA protection" +msgstr "Ochrana přímého přístupu do paměti před startem operačního systému" + +#. TRANSLATORS: version number of previous firmware +msgid "Previous version" +msgstr "Předchozí verze" + +msgid "Print the version number" +msgstr "Vypsat číslo verze" + +msgid "Print verbose debug statements" +msgstr "Vypsat podrobná ladící hlášení" + #. TRANSLATORS: the numeric priority msgid "Priority" msgstr "Priorita" @@ -493,10 +1390,26 @@ msgid "Proceed with upload?" msgstr "Pokračovat v nahrávání?" +#. TRANSLATORS: a non-free software license +msgid "Proprietary" +msgstr "Proprietární" + #. TRANSLATORS: command line option msgid "Query for firmware update support" msgstr "Dotázat se na podporu aktualizace firmwaru" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "REMOTE-ID" +msgstr "IDENTIF-NA-PROTĚJŠKU" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "REMOTE-ID KEY VALUE" +msgstr "HODNOTA KLÍČE IDENTIF-NA-PROTĚJŠKU" + +#. TRANSLATORS: command description +msgid "Read a firmware blob from a device" +msgstr "Načíst blob firmware ze zařízení" + #. TRANSLATORS: command description msgid "Read firmware from device into a file" msgstr "Přečíst firmware ze zařízení do souboru" @@ -505,15 +1418,28 @@ msgid "Read firmware from one partition into a file" msgstr "Přečíst firmware z jednoho oddílu do souboru" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Reading from %s…" +msgstr "Načítání z %s…" + #. TRANSLATORS: reading from the flash chips msgid "Reading…" msgstr "Čte se…" +#. TRANSLATORS: console message when not using plymouth +msgid "Rebooting…" +msgstr "Restartování…" + #. TRANSLATORS: command description msgid "Refresh metadata from remote server" msgstr "Aktualizovat metadata ze vzdáleného serveru" #. TRANSLATORS: command description +msgid "Reinstall current firmware on the device" +msgstr "Přeinstaluje stávající firmware na zařízení" + +#. TRANSLATORS: command description msgid "Reinstall firmware on a device" msgstr "Přeinstalovat firmware na zařízení" @@ -524,15 +1450,15 @@ msgid "Reinstalling %s with %s... " msgstr "Přeinstalovává se %s na %s…" +#. TRANSLATORS: the stream of firmware, e.g. nonfree or open-source +msgid "Release Branch" +msgstr "Větev vydání" + #. TRANSLATORS: the server the file is coming from #. TRANSLATORS: remote identifier, e.g. lvfs-testing msgid "Remote ID" msgstr "ID vzdáleného zdroje" -#. TRANSLATORS: this is when a device is hotplugged -msgid "Removed" -msgstr "Odebráno" - #. TRANSLATORS: command description msgid "Replace data in an existing firmware file" msgstr "Nahradit data ve stávajícím souboru s firmwarem" @@ -541,6 +1467,22 @@ msgid "Report URI" msgstr "URI hlášení" +#. TRANSLATORS: Has been reported to a metadata server +msgid "Reported to remote server" +msgstr "Nahlášeno na vzdálený server" + +#. TRANSLATORS: the user is using Gentoo/Arch and has screwed something up +msgid "Required efivarfs filesystem was not found" +msgstr "Nebyl nalezen potřebný souborový systém efivarfs" + +#. TRANSLATORS: not required for this system +msgid "Required hardware was not found" +msgstr "Požadovaný hardware nenalezen" + +#. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user +msgid "Requires a bootloader" +msgstr "Vyžaduje zavaděč systému" + #. TRANSLATORS: metadata is downloaded from the Internet msgid "Requires internet connection" msgstr "Vyžaduje připojení k Internetu" @@ -549,13 +1491,56 @@ msgid "Restart now?" msgstr "Restartovat nyní?" +#. TRANSLATORS: configuration changes only take effect on restart +msgid "Restart the daemon to make the change effective?" +msgstr "Restartovat proces služby, aby se změny uplatnily?" + #. TRANSLATORS: restarting the device to pick up new F/W msgid "Restarting device…" msgstr "Zařízení se restartuje…" #. TRANSLATORS: command description msgid "Return all the hardware IDs for the machine" -msgstr "Vrátit všechna ID hardwaru počítače" +msgstr "Vrátit všechny identifikátory hardwaru počítače" + +msgid "Run `fwupdmgr get-upgrades` for more information." +msgstr "Podrobnosti získáte spuštěním `fwupdmgr get-upgrades`." + +#. TRANSLATORS: command line option +msgid "Run the plugin composite cleanup routine when using install-blob" +msgstr "Při použití install-blob spustit rutinu složeného vyčištění zásuvného modulu" + +#. TRANSLATORS: command line option +msgid "Run the plugin composite prepare routine when using install-blob" +msgstr "Při použití install-blob spustit rutinu složené přípravy zásuvného modulu" + +#. TRANSLATORS: this is the HSI suffix +msgid "Runtime Suffix" +msgstr "Přípona běhového prostředí" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI BIOS region" +msgstr "Oblast SPI BIOS" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI lock" +msgstr "SPI uzamčení" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI write" +msgstr "SPI zápis" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "SUBSYSTEM DRIVER [DEVICE-ID|GUID]" +msgstr "OVLADAČ PODSYSTÉMU [IDENTIF-ZAŘÍZENÍ|GUID]" + +#. TRANSLATORS: command description +msgid "Save a file that allows generation of hardware IDs" +msgstr "Uložit soubor který umožňuje vytváření identifikátorů hardware" + +#. TRANSLATORS: command line option +msgid "Save device state into a JSON file between executions" +msgstr "Mezi vykonáními uložit stav zařízení do JSON souboru" #. TRANSLATORS: command line option msgid "Schedule installation for next reboot when possible" @@ -565,17 +1550,50 @@ msgid "Scheduling…" msgstr "Plánuje se…" +#. TRANSLATORS: %s is a link to a website +#, c-format +msgid "See %s for more information." +msgstr "Podrobnosti viz %s." + +#. TRANSLATORS: Device has been chosen by the daemon for the user +msgid "Selected device" +msgstr "Vybrané zařízení" + +#. TRANSLATORS: Volume has been chosen by the user +msgid "Selected volume" +msgstr "Vybraný svazek" + +#. TRANSLATORS: serial number of hardware +msgid "Serial Number" +msgstr "Sériové číslo" + #. TRANSLATORS: command line option msgid "Set the debugging flag during update" msgstr "Během aktualizace nastavit příznak ladění" +#. TRANSLATORS: firmware approved by the admin +msgid "Sets the list of approved firmware" +msgstr "Nastavuje seznam schválených firmwarů" + #. TRANSLATORS: command description msgid "Share firmware history with the developers" msgstr "Sdílet historii firmwaru s vývojáři" #. TRANSLATORS: command line option +msgid "Show all results" +msgstr "Zobrazit všechny výsledky" + +#. TRANSLATORS: command line option msgid "Show client and daemon versions" -msgstr "Zobrazit verzi klienta a démona" +msgstr "Zobrazit verzi klienta a procesu služby" + +#. TRANSLATORS: this is for daemon development +msgid "Show daemon verbose information for a particular domain" +msgstr "Zobrazit podrobnější informace z procesu služby pro konkrétní oblast" + +#. TRANSLATORS: turn on all debugging +msgid "Show debugging information for all domains" +msgstr "Zapnout vypisování ladících informací pro všechny oblasti" #. TRANSLATORS: for the --verbose arg msgid "Show debugging options" @@ -598,6 +1616,10 @@ msgstr "Zobrazit podrobné informace o zásuvném modulu" #. TRANSLATORS: command line option +msgid "Show the calculated version of the dbx" +msgstr "Zobrazit vypočtenou verzi dbx" + +#. TRANSLATORS: command line option msgid "Show the debug log from the last attempted update" msgstr "Zobrazit ladicí záznam z posledního pokusu o aktualizaci" @@ -605,10 +1627,142 @@ msgid "Show the information of firmware update status" msgstr "Zobrazit informace o stavu aktualizace firmwaru" +#. TRANSLATORS: shutdown to apply the update +msgid "Shutdown now?" +msgstr "Vypnout nyní?" + +msgid "Sign data using the client certificate" +msgstr "Podepsat data klientským certifikátem" + +msgctxt "command-description" +msgid "Sign data using the client certificate" +msgstr "Podepsat data klientským certifikátem" + +#. TRANSLATORS: command line option +msgid "Sign the uploaded data with the client certificate" +msgstr "Podepsat nahraná data klientským certifikátem" + +msgid "Signature" +msgstr "Podpis" + +#. TRANSLATORS: file size of the download +msgid "Size" +msgstr "Velikost" + +#. TRANSLATORS: source (as in code) link +msgid "Source" +msgstr "Zdroj" + +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Zadejte identifikátor(y) výrobce/produktu DFU zařízení" + +#. TRANSLATORS: command line option +msgid "Specify the dbx database file" +msgstr "Zadejte soubor dbx databáze" + +msgid "Specify the number of bytes per USB transfer" +msgstr "Zadejte počet bajtů v jednotlivých přenosech přes USB sběrnici" + +#. TRANSLATORS: The update state of the specific device +msgid "Success" +msgstr "Úspěch" + +#. TRANSLATORS: success message -- where activation is making the new +#. * firmware take effect, usually after updating offline +msgid "Successfully activated all devices" +msgstr "Všechna zařízení úspěšně aktivována" + +#. TRANSLATORS: success message +msgid "Successfully disabled remote" +msgstr "Vzdálené úspěšně vypnuto" + +#. TRANSLATORS: success message -- where 'metadata' is information +#. * about available firmware on the remote server +msgid "Successfully downloaded new metadata: " +msgstr "Nová metadata úspěšně stažena:" + +#. TRANSLATORS: success message +msgid "Successfully enabled remote" +msgstr "Vzdálené úspěšně zapnuto" + +#. TRANSLATORS: success message +msgid "Successfully installed firmware" +msgstr "Firmware úspěšně nainstalován" + +#. TRANSLATORS: success message -- a per-system setting value +msgid "Successfully modified configuration value" +msgstr "Hodnota v nastavení úspěšně změněna" + +#. TRANSLATORS: success message for a per-remote setting change +msgid "Successfully modified remote" +msgstr "Vzdálené úspěšně změněno" + +#. TRANSLATORS: success message -- the user can do this by-hand too +msgid "Successfully refreshed metadata manually" +msgstr "Metadata úspěšně ručně aktualizována" + +#. TRANSLATORS: success message when user refreshes device checksums +msgid "Successfully updated device checksums" +msgstr "Kontrolní součty zařízení úspěšně zaktualizovány" + +#. TRANSLATORS: success message -- where the user has uploaded +#. * success and/or failure reports to the remote server +#, c-format +msgid "Successfully uploaded %u report" +msgid_plural "Successfully uploaded %u reports" +msgstr[0] "Úspěšně nahráno %u hlášení" +msgstr[1] "Úspěšně nahrána %u hlášení" +msgstr[2] "Úspěšně nahráno %u hlášení" +msgstr[3] "Úspěšně nahrána %u hlášení" + +#. TRANSLATORS: success message when user verified device checksums +msgid "Successfully verified device checksums" +msgstr "Kontrolní součty zařízení úspěšně ověřeny" + #. TRANSLATORS: one line summary of device msgid "Summary" msgstr "Souhrn" +#. TRANSLATORS: Suffix: the HSI result +msgid "Supported" +msgstr "Podporováno" + +#. TRANSLATORS: Is found in current metadata +msgid "Supported on remote server" +msgstr "Podporováno na vzdáleném serveru" + +#. TRANSLATORS: Title: a better sleep state +msgid "Suspend-to-idle" +msgstr "Uspat do nečinnosti" + +#. TRANSLATORS: Title: sleep state +msgid "Suspend-to-ram" +msgstr "Uspat do paměti" + +#. TRANSLATORS: command description +msgid "Switch the firmware branch on the device" +msgstr "Přepnout větev firmware na zařízení" + +#. TRANSLATORS: Must be plugged in to an outlet +msgid "System requires external power source" +msgstr "Počítač vyžaduje externí napájení" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "TEXT" +msgstr "TEXT" + +#. TRANSLATORS: Title: the PCR is rebuilt from the TPM event log +msgid "TPM PCR0 reconstruction" +msgstr "Rekonstrukce TPM PCR0" + +#. TRANSLATORS: Title: TPM = Trusted Platform Module +msgid "TPM v2.0" +msgstr "TPM v2.0" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Tainted" +msgstr "Otráveno" + msgid "Target" msgstr "Cíl" @@ -616,6 +1770,36 @@ msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "LVFS je svobodná služba, které funguje jako nezávislý právní subjekt a nemá žádné vazby na systém $OS_RELEASE:NAME$. Váš distributor nemusí některé z aktualizací firmwaru schválit kvůli kompatibilitě s vaším systémem nebo připojenými zařízeními. Veškerý firmware je poskytován pouze přímo výrobci daných zařízení." +#. TRANSLATORS: this is more background on a security measurement problem +msgid "The TPM PCR0 differs from reconstruction." +msgstr "PCR0 v TPM se liší od rekonstrukce." + +#. TRANSLATORS: the user is SOL for support... +msgid "The daemon has loaded 3rd party code and is no longer supported by the upstream developers!" +msgstr "Proces služby načetl kód třetí strany a není už podporován původními vývojáři!" + +#. TRANSLATORS: %1 is the firmware vendor, %2 is the device vendor name +#, c-format +msgid "The firmware from %s is not supplied by %s, the hardware vendor." +msgstr "Firmware od %s není dodáváno %s, výrobce hardware." + +#. TRANSLATORS: try to help +msgid "The system clock has not been set correctly and downloading files may fail." +msgstr "Systémové hodiny nemají správný čas – stahování souborů se kvůli tomu nemusí zdařit." + +#. TRANSLATORS: nothing to show +msgid "There are no blocked firmware files" +msgstr "Nejsou zde žádné blokované soubory s firmware" + +#. TRANSLATORS: approved firmware has been checked by +#. * the domain administrator +msgid "There is no approved firmware." +msgstr "Není k dispozici žádný schválený firmware" + +#. TRANSLATORS: unsupported build of the package +msgid "This package has not been validated, it may not work properly." +msgstr "Tento balíček nebyl ověřen – může se stát, že nebude fungovat správně." + #. TRANSLATORS: we're poking around as a power user msgid "This program may only work correctly as root" msgstr "Tento program může správně fungovat jen pod uživatelem root" @@ -623,31 +1807,157 @@ msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "Tento zdroj obsahuje firmware, který není zakázaný, ale zatím je u výrobce stále ve stádiu testování. Měli byste se ujistit, že znáte způsob, jak se vrátit k předchozí verzi firmwaru, kdyby došlo k selhání." +#. TRANSLATORS: this is instructions on how to improve the HSI suffix +msgid "This system has HSI runtime issues." +msgstr "Tento systém má problémy s běhovým prostředím HSI." + +#. TRANSLATORS: this is instructions on how to improve the HSI security level +msgid "This system has a low HSI security level." +msgstr "Tento systém má nízkou úroveň zabezpečení HSI." + +#. TRANSLATORS: description of dbxtool +msgid "This tool allows an administrator to apply UEFI dbx updates." +msgstr "Tento nástroj správci umožňuje použít UEFI dbx aktualizace." + +#. TRANSLATORS: CLI description +msgid "This tool allows an administrator to debug UpdateCapsule operation." +msgstr "Tento nástroj správci umožňuje ladit operaci UpdateCapsule." + +#. TRANSLATORS: CLI description +msgid "This tool allows an administrator to query and control the fwupd daemon, allowing them to perform actions such as installing or downgrading firmware." +msgstr "Tento nástroj správci umožňuje dotazovat a ovládat proces služby fwupd a tím provádět akce jako např. instalaci nebo návrat ke starší verzi firmware." + +#. TRANSLATORS: CLI description +msgid "This tool allows an administrator to use the fwupd plugins without being installed on the host system." +msgstr "Tento nástroj správci umožňuje použít zásuvné moduly pro fwupd bez toho, aby se instalovalo na hostitelský systém." + +#. TRANSLATORS: CLI description +msgid "This tool can be used from other tools and from shell scripts." +msgstr "Tento nástroj je možné použít z ostatním nástrojů a shellových skriptů." + +#. TRANSLATORS: the user needs to stop playing with stuff +msgid "This tool can only be used by the root user" +msgstr "Tento nástroj může používat pouze uživatel s oprávněními na úrovni správce systému (root)" + +#. TRANSLATORS: CLI description +msgid "This tool will read and parse the TPM event log from the system firmware." +msgstr "Tento nástroj načte a zpracuje záznam událostí ve správě TPM z firmware systému." + +#. TRANSLATORS: command line option +msgid "Timeout in milliseconds for each parse" +msgstr "Časový limit (v milisekundách) pro každé ze zpracovávání" + +#. TRANSLATORS: The update state of the specific device +msgid "Transient failure" +msgstr "Přechodný nezdar" + #. TRANSLATORS: remote type, e.g. remote or local msgid "Type" msgstr "Typ" +#. TRANSLATORS: partition refers to something on disk, again, hey Arch users +msgid "UEFI ESP partition not detected or configured" +msgstr "Nezjištěn (či nastaven) UEFI ESP oddíl" + #. TRANSLATORS: program name msgid "UEFI Firmware Utility" msgstr "Nástroj pro práci s firmwarem UEFI" +#. TRANSLATORS: capsule updates are an optional BIOS feature +msgid "UEFI capsule updates not available or enabled in firmware setup" +msgstr "Nejsou k dispozici (nebo zapnuté v nastavení firmware) aktualizace typu UEFI capsule" + +#. TRANSLATORS: program name +msgid "UEFI dbx Utility" +msgstr "Nástroj pro UEFI dbx" + +#. TRANSLATORS: Title: PK is the 'platform key' for the machine +msgid "UEFI platform key" +msgstr "Klíč UEFI platformy" + +#. TRANSLATORS: Title: SB is a way of locking down UEFI +msgid "UEFI secure boot" +msgstr "UEFI secure boot" + +#. TRANSLATORS: error message +msgid "Unable to connect to service" +msgstr "Nedaří se připojit se ke službě" + +#. TRANSLATORS: command description +msgid "Unbind current driver" +msgstr "Odpojit stávající ovladač" + +#. TRANSLATORS: we will now offer this firmware to the user +msgid "Unblocking firmware:" +msgstr "Odblokovává se firmware:" + +#. TRANSLATORS: command description +msgid "Unblocks a specific firmware from being installed" +msgstr "Odblokuje instalaci konkrétní firmware" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Unencrypted" +msgstr "Nešifrované" + #. TRANSLATORS: current daemon status is unknown #. TRANSLATORS: we don't know the license of the update #. TRANSLATORS: unknown release urgency msgid "Unknown" -msgstr "Neznámý" +msgstr "Neznámo" + +#. TRANSLATORS: Name of hardware +msgid "Unknown Device" +msgstr "Neznámé zařízení" msgid "Unlock the device to allow access" msgstr "Odemknutí zařízení pro umožnění přístupu" +#. TRANSLATORS: Suffix: the HSI result +msgid "Unlocked" +msgstr "Odemčené" + #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "Odemknout zařízení pro přístup k firmwaru" +#. TRANSLATORS: command description +msgid "Unmounts the ESP" +msgstr "Odpojí ESP oddíl" + #. TRANSLATORS: command line option msgid "Unset the debugging flag during update" msgstr "Během aktualizace zrušit příznak ladění" +#. TRANSLATORS: error message +#, c-format +msgid "Unsupported daemon version %s, client version is %s" +msgstr "Nepodporovaná verze procesu služby %s, verze klienta je %s" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Untainted" +msgstr "Neotráveno" + +#. TRANSLATORS: Device is updatable in this or any other mode +msgid "Updatable" +msgstr "Možné aktualizovat" + +#. TRANSLATORS: error message from last update attempt +msgid "Update Error" +msgstr "Chyba při aktualizaci" + +#. TRANSLATORS: helpful messages from last update +#. TRANSLATORS: helpful messages for the update +msgid "Update Message" +msgstr "Zpráva z aktualizace" + +#. TRANSLATORS: hardware state, e.g. "pending" +msgid "Update State" +msgstr "Stav aktualizace" + +#. TRANSLATORS: command description +msgid "Update all devices that match local metadata" +msgstr "Aktualizovat veškerá zařízení, která se shodují s místními metadaty" + #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" msgstr "O selhání aktualizace se ví, více informací najdete na této adrese:" @@ -656,13 +1966,28 @@ msgid "Update now?" msgstr "Aktualizovat nyní?" +#. TRANSLATORS: Update can only be done from offline mode +msgid "Update requires a reboot" +msgstr "Aktualizace vyžaduje restart" + +#. TRANSLATORS: command description +msgid "Update the stored cryptographic hash with current ROM contents" +msgstr "Aktualizovat uložený kryptografický otisk stávajícím obsahem ROM paměti" + msgid "Update the stored device verification information" msgstr "Aktualizace uložené informace o ověření zařízení" #. TRANSLATORS: command description +msgid "Update the stored metadata with current contents" +msgstr "Aktualizovat uložená metadata stávajícím obsahem" + +#. TRANSLATORS: command description msgid "Updates all firmware to latest versions available" msgstr "Aktualizovat všechen firmware na nejnovější dostupné verze" +msgid "Updating" +msgstr "Aktualizuje se" + #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second and third are #. * version numbers e.g. "1.2.3" @@ -670,35 +1995,99 @@ msgid "Updating %s from %s to %s... " msgstr "Aktualizuje se %s z verze %s na %s…" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Nahraná zpráva:" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "Aktualizace %s…" + +#. TRANSLATORS: message letting the user know an upgrade is available +#. * %1 is the device name and %2 and %3 are version strings +#, c-format +msgid "Upgrade available for %s from %s to %s" +msgstr "Je k dispozici aktualizace pro %s z verze %s na %s" + +msgid "Upload report just this one time, but prompt again for future updates" +msgid_plural "Upload reports just this one time, but prompt again for future updates" +msgstr[0] "Nyní hlášení odeslat, ale při budoucích aktualizacích se znovu zeptat" +msgstr[1] "Nyní hlášení odeslat, ale při budoucích aktualizacích se znovu zeptat" +msgstr[2] "Nyní hlášení odeslat, ale při budoucích aktualizacích se znovu zeptat" +msgstr[3] "Nyní hlášení odeslat, ale při budoucích aktualizacích se znovu zeptat" #. TRANSLATORS: ask the user to upload msgid "Upload report now?" msgstr "Nahrát hlášení nyní?" +msgid "Upload report this time and automatically upload reports after completing future updates" +msgid_plural "Upload reports this time and automatically upload reports after completing future updates" +msgstr[0] "Nyní hlášení odeslat a nadále po dokončení budoucích aktualizací odesílat automaticky" +msgstr[1] "Nyní hlášení odeslat a nadále po dokončení budoucích aktualizací odesílat automaticky" +msgstr[2] "Nyní hlášení odeslat a nadále po dokončení budoucích aktualizací odesílat automaticky" +msgstr[3] "Nyní hlášení odeslat a nadále po dokončení budoucích aktualizací odesílat automaticky" + #. TRANSLATORS: explain why we want to upload msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." msgstr "Když nahrajete hlášení o firmwaru, pomůžete tím výrobcům hardwaru rychle rozpoznat nezdařené a úspěšné aktualizace na reálných zařízeních." +#. TRANSLATORS: how important the release is +msgid "Urgency" +msgstr "Naléhavost" + +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdmgr --help for help" +msgstr "Pro zobrazení nápovědy použijte příkaz fwupdmgr --help" + +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdtool --help for help" +msgstr "Nápovědu obdržíte spuštěním fwupdtool --help" + +#. TRANSLATORS: command line option +msgid "Use quirk flags when installing firmware" +msgstr "Při instalaci firmware použít příznaky pro kompatibilitu" + +#. TRANSLATORS: User has been notified +msgid "User has been notified" +msgstr "Uživatel byl upozorněn" + #. TRANSLATORS: remote filename base msgid "Username" msgstr "Uživatelské jméno" +msgid "VID:PID" +msgstr "IDENTIF-VÝROBCE:IDENTIF-ZAŘÍZENÍ" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Valid" +msgstr "Platné" + +#. TRANSLATORS: ESP refers to the EFI System Partition +msgid "Validating ESP contents…" +msgstr "Ověřování obsahu ESP oddílu…" + +#. TRANSLATORS: one line variant of release (e.g. 'Prerelease' or 'China') +msgid "Variant" +msgstr "Varianta" + +#. TRANSLATORS: manufacturer of hardware +msgid "Vendor" +msgstr "Výrobce" + #. TRANSLATORS: verifying we wrote the firmware correctly msgid "Verifying…" msgstr "Ověřuje se…" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Verze" + +#. TRANSLATORS: this is a prefix on the console +msgid "WARNING:" +msgstr "VAROVÁNÍ:" + #. TRANSLATORS: waiting for device to do something msgid "Waiting…" msgstr "Čeká se…" #. TRANSLATORS: command description -msgid "Watch DFU devices being hotplugged" -msgstr "Sledovat připojení zařízení podporujících DFU" - -#. TRANSLATORS: command description msgid "Watch for hardware changes" msgstr "Sledovat změny hardwaru" @@ -710,6 +2099,10 @@ msgid "Write firmware from file into one partition" msgstr "Zapsat firmware ze souboru do jednoho oddílu" +#. TRANSLATORS: decompressing images from a container firmware +msgid "Writing file:" +msgstr "Zápis do souboru:" + #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Zapisuje se…" @@ -717,3 +2110,36 @@ #. TRANSLATORS: show the user a warning msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "Váš distributor nemusí schválit některé aktualizace firmwaru kvůli kompatibilitě s vaším systémem nebo připojenými zařízeními." + +#. TRANSLATORS: %1 is the device vendor name +#, c-format +msgid "Your hardware may be damaged using this firmware, and installing this release may void any warranty with %s." +msgstr "Použitím tohoto firmware může být hardware poškozen a instalací tohoto vydání může být ztracena záruka od %s." + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "[CHECKSUM]" +msgstr "[KONTROLNÍ-SOUČET]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "[DEVICE-ID|GUID]" +msgstr "[IDENTIF-ZAŘÍZENÍ|GUID]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "[DEVICE-ID|GUID] [BRANCH]" +msgstr "[IDENTIF-ZAŘÍZENÍ|GUID] [VĚTEV]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "[FILE FILE_SIG REMOTE-ID]" +msgstr "[SOUBOR PODPIS_SOUBORU IDENTIF-NA-PROTEJŠKU]" + +#. TRANSLATORS: this is the default branch name when unset +msgid "default" +msgstr "výchozí" + +#. TRANSLATORS: program name +msgid "fwupd TPM event log utility" +msgstr "fwupd nástroj pro záznamy událostí v TPM" + +#. TRANSLATORS: Title: if the fwupd plugins are all present and correct +msgid "fwupd plugins" +msgstr "zásuvné moduly pro fwupd" diff -Nru fwupd-1.4.5/po/da.po fwupd-1.5.8/po/da.po --- fwupd-1.4.5/po/da.po 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/po/da.po 2021-03-31 20:08:32.000000000 +0000 @@ -23,6 +23,18 @@ msgstr[0] "%.0f minut tilbage" msgstr[1] "%.0f minutter tilbage" +#. TRANSLATORS: the CPU microcode is firmware loaded onto the CPU +#. * at system bootup +#, c-format +msgid "%s CPU Microcode Update" +msgstr "%s opdatering af CPU-mikrokode" + +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Secure Boot` +#, c-format +msgid "%s Configuration Update" +msgstr "Opdatering for konfiguration %s" + #. TRANSLATORS: ME stands for Management Engine, where #. * the first %s is the device name, e.g. 'ThinkPad P50` #, c-format @@ -86,6 +98,11 @@ msgid "%s and all connected devices may not be usable while updating." msgstr "%s og alle tilsluttede enheder vil måske ikke være anvendelige under opdatering." +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s manufacturing mode" +msgstr "%s-fabrikstilstand" + #. TRANSLATORS: warn the user before updating, %1 is a device name #, c-format msgid "%s must remain connected for the duration of the update to avoid damage." @@ -96,6 +113,21 @@ msgid "%s must remain plugged into a power source for the duration of the update to avoid damage." msgstr "%s skal være tilsluttet en strømkilde under hele opdateringen, for at undgå skade." +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s override" +msgstr "%s-tilsidesættelse" + +#. TRANSLATORS: Title: %1 is ME kind, e.g. CSME/TXT, %2 is a version number +#, c-format +msgid "%s v%s" +msgstr "%s v%s" + +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s version" +msgstr "%s-version" + #. TRANSLATORS: duration in days! #, c-format msgid "%u day" @@ -137,6 +169,10 @@ msgstr[0] "%u sekund" msgstr[1] "%u sekunder" +#. TRANSLATORS: this is shown as a suffix for obsoleted tests +msgid "(obsoleted)" +msgstr "(forældet)" + #. TRANSLATORS: command description msgid "Activate devices" msgstr "Aktivér enheder" @@ -156,10 +192,6 @@ msgid "Activating firmware update for" msgstr "Aktiverer firmwareopdatering for" -#. TRANSLATORS: this is when a device is hotplugged -msgid "Added" -msgstr "Tilføjet" - #. TRANSLATORS: the age of the metadata msgid "Age" msgstr "Alder" @@ -181,6 +213,10 @@ msgid "Allow reinstalling existing firmware versions" msgstr "Tillad geninstallering af eksisterende firmwareversioner" +#. TRANSLATORS: command line option +msgid "Allow switching firmware branch" +msgstr "Tillad skift af firmwaregren" + #. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "For at fuldføre en opdatering skal systemet genstartes." @@ -197,6 +233,18 @@ msgid "Apply firmware updates" msgstr "Anvend firmwareopdateringer" +#. TRANSLATORS: command line option +msgid "Apply update even when not advised" +msgstr "Anvend opdatering, selv når det ikke tilrådes" + +#. TRANSLATORS: command line option +msgid "Apply update files" +msgstr "Anvend opdateringsfiler" + +#. TRANSLATORS: actually sending the update to the hardware +msgid "Applying update…" +msgstr "Anvender opdatering …" + #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator msgid "Approved firmware:" @@ -204,6 +252,10 @@ msgstr[0] "Godkendt firmware:" msgstr[1] "Godkendt firmware:" +#. TRANSLATORS: stop nagging the user +msgid "Ask again next time?" +msgstr "Spørg igen næste gang?" + #. TRANSLATORS: command description msgid "Attach to firmware mode" msgstr "Tilkobl til firmwaretilstand" @@ -260,10 +312,38 @@ msgid "Automatic Reporting" msgstr "Automatisk rapportering" +#. TRANSLATORS: can we JFDI? +msgid "Automatically upload every time?" +msgstr "Upload automatisk hver gang?" + +#. TRANSLATORS: command description +msgid "Bind new kernel driver" +msgstr "Bind ny kernedriver" + +#. TRANSLATORS: there follows a list of hashes +msgid "Blocked firmware files:" +msgstr "Blokerede firmwarefiler:" + +#. TRANSLATORS: we will not offer this firmware to the user +msgid "Blocking firmware:" +msgstr "Blokerer firmware:" + +#. TRANSLATORS: command description +msgid "Blocks a specific firmware from being installed" +msgstr "Blokerer en bestemt firmware fra at blive installeret" + #. TRANSLATORS: firmware version of bootloader msgid "Bootloader Version" msgstr "Opstartsindlæser version" +#. TRANSLATORS: the stream of firmware, e.g. nonfree or open-source +msgid "Branch" +msgstr "Gren" + +#. TRANSLATORS: command description +msgid "Build a firmware file" +msgstr "Byg en firmwarefil" + #. TRANSLATORS: command description msgid "Build firmware using a sandbox" msgstr "Byg firmware med en sandkasse" @@ -276,7 +356,14 @@ msgid "Cancelled" msgstr "Annulleret" -#. TRANSLATORS: this is when a device is hotplugged +#. TRANSLATORS: same or newer update already applied +msgid "Cannot apply as dbx update has already been applied." +msgstr "Kan ikke anvende eftersom dbx-opdatering allerede er blevet anvendt." + +#. TRANSLATORS: the user is using a LiveCD or LiveUSB install disk +msgid "Cannot apply updates on live media" +msgstr "Kan ikke anvende opdateringer på livemedier" + #. TRANSLATORS: this is when the daemon state changes msgid "Changed" msgstr "Ændret" @@ -289,6 +376,11 @@ msgid "Checksum" msgstr "Checksum" +#. TRANSLATORS: get interactive prompt, where branch is the +#. * supplier of the firmware, e.g. "non-free" or "free" +msgid "Choose a branch:" +msgstr "Vælg en gren:" + #. TRANSLATORS: get interactive prompt msgid "Choose a device:" msgstr "Vælg en enhed:" @@ -301,6 +393,10 @@ msgid "Choose a release:" msgstr "Vælg en udgivelse:" +#. TRANSLATORS: get interactive prompt +msgid "Choose a volume:" +msgstr "Vælg et diskområde:" + #. TRANSLATORS: command description msgid "Clears any updates scheduled to be updated offline" msgstr "Rydder opdateringer som er planlagt til at blive opdateret offline" @@ -317,6 +413,18 @@ msgid "Continue with update?" msgstr "Fortsæt opdateringen?" +#. TRANSLATORS: command description +msgid "Convert a firmware file" +msgstr "Konverter en firmwarefil" + +#. TRANSLATORS: when the update was built +msgid "Created" +msgstr "Oprettet" + +#. TRANSLATORS: the release urgency +msgid "Critical" +msgstr "Kritisk" + #. TRANSLATORS: Device supports some form of checksum verification msgid "Cryptographic hash verification is available" msgstr "Bekræftelse af kryptografisk hash er tilgængelig" @@ -393,10 +501,18 @@ msgid "Device stages updates" msgstr "Enhedstrin-opdateringer" +#. TRANSLATORS: there is more than one supplier of the firmware +msgid "Device supports switching to a different branch of firmware" +msgstr "Enheden understøtter at der kan skiftes til en anden gren med firmware" + #. TRANSLATORS: Device update needs to be separately activated msgid "Device update needs activation" msgstr "Enhedsopdatering behøver aktivering" +#. TRANSLATORS: save the old firmware to disk before installing the new one +msgid "Device will backup firmware before installing" +msgstr "Enheden sikkerhedskopierer firmwaren inden installation" + #. TRANSLATORS: Device will not return after update completes msgid "Device will not re-appear after update completes" msgstr "Enheden vises ikke igen når opdateringen er færdig" @@ -409,6 +525,20 @@ msgid "Devices that were not updated correctly:" msgstr "Enheder som ikke blev opdateret korrekt:" +#. TRANSLATORS: message letting the user know no device upgrade available due +#. to missing on LVFS +msgid "Devices with no available firmware updates: " +msgstr "Enheder uden nogen tilgængelige firmwareopdateringer: " + +#. TRANSLATORS: message letting the user know no device upgrade available +msgid "Devices with the latest available firmware version:" +msgstr "Enheder med den seneste tilgængelige firmwareversion:" + +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is inactive and not used +msgid "Disabled" +msgstr "Deaktiveret" + msgid "Disabled fwupdate debugging" msgstr "Deaktivér fejlsøgning af fwupdate" @@ -458,6 +588,11 @@ msgid "Do not write to the history database" msgstr "Skriv ikke til historikdatabasen" +#. TRANSLATORS: should the branch be changed +msgid "Do you understand the consequences of changing the firmware branch?" +msgstr "Forstår du de konsekvenser som er forbundet med ændring af firmwaregrenen?" + +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Færdig!" @@ -502,6 +637,8 @@ msgid "Enable this remote?" msgstr "Aktivér fjernen?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Aktiveret" @@ -520,6 +657,14 @@ msgid "Enabling this remote is done at your own risk." msgstr "Aktivering af fjernen sker på egen risiko." +#. TRANSLATORS: Suffix: the HSI result +msgid "Encrypted" +msgstr "Krypteret" + +#. TRANSLATORS: Title: Memory contents are encrypted, e.g. Intel TME +msgid "Encrypted RAM" +msgstr "Krypteret RAM" + #. TRANSLATORS: command description msgid "Erase all firmware update history" msgstr "Slet al historik over firmwareopdateringer" @@ -536,14 +681,23 @@ msgid "Exit after the engine has loaded" msgstr "Afslut efter motoren er indlæst" +#. TRANSLATORS: command description +msgid "Extract a firmware blob to images" +msgstr "Udpak en firmwareblob til aftryk" + +#. TRANSLATORS: Suffix: the fallback HSI result +#. TRANSLATORS: The update state of the specific device +msgid "Failed" +msgstr "Mislykkedes" + +#. TRANSLATORS: dbx file failed to be applied as an update +msgid "Failed to apply update" +msgstr "Kunne ikke anvende opdatering" + #. TRANSLATORS: we could not talk to the fwupd daemon msgid "Failed to connect to daemon" msgstr "Kunne ikke oprette forbindelse til dæmonen" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "Kunne ikke downloade pga. begrænsning på server" - #. TRANSLATORS: we could not get the devices to update offline msgid "Failed to get pending devices" msgstr "Kunne ikke hente afventende enheder" @@ -552,10 +706,19 @@ msgid "Failed to install firmware update" msgstr "Kunne ikke installere firmwareopdateringen" +#. TRANSLATORS: could not read existing system data +#. TRANSLATORS: could not read file +msgid "Failed to load local dbx" +msgstr "Kunne ikke indlæse lokal dbx" + #. TRANSLATORS: quirks are device-specific workarounds msgid "Failed to load quirks" msgstr "Kunne ikke indlæse quirks" +#. TRANSLATORS: could not read existing system data +msgid "Failed to load system dbx" +msgstr "Kunne ikke indlæse systemets dbx" + #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Kunne ikke fortolke argumenter" @@ -568,6 +731,10 @@ msgid "Failed to parse flags for --filter" msgstr "Kunne ikke fortolke flag for --filter" +#. TRANSLATORS: could not parse file +msgid "Failed to parse local dbx" +msgstr "Kunne ikke fortolke lokal dbx" + #. TRANSLATORS: we could not reboot for some reason msgid "Failed to reboot" msgstr "Kunne ikke genstarte" @@ -576,21 +743,10 @@ msgid "Failed to set splash mode" msgstr "Kunne ikke indstille splash-tilstand" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "Henter fil" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "Henter firmware" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "Henter metadata" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "Henter underskrift" +#. TRANSLATORS: something with a blocked hash exists +#. * in the users ESP -- which would be bad! +msgid "Failed to validate ESP contents" +msgstr "Kunne ikke validere ESP-indhold" #. TRANSLATORS: filename of the local file msgid "Filename" @@ -600,6 +756,10 @@ msgid "Filename Signature" msgstr "Filnavnets underskrift" +#. TRANSLATORS: user did not include a filename parameter +msgid "Filename required" +msgstr "Filnavn kræves" + #. TRANSLATORS: command line option msgid "Filter with a set of device flags using a ~ prefix to exclude, e.g. 'internal,~needs-reboot'" msgstr "Filtrer med et sæt enhedsflag med et ~-præfiks for at udelukke, f.eks. 'intern,~behøver-genstart'" @@ -624,6 +784,22 @@ msgid "Firmware Utility" msgstr "Firmwareredskab" +#. TRANSLATORS: Title: if we can verify the firmware checksums +msgid "Firmware attestation" +msgstr "Firmwareattest" + +#. TRANSLATORS: system is not booted in UEFI mode +msgid "Firmware can not be updated in legacy BIOS mode" +msgstr "Firmwaren kan ikke opdateres i udgået BIOS-tilstand" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is already blocked" +msgstr "Firmware er allerede blokeret" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is not already blocked" +msgstr "Firmware er ikke allerede blokeret" + #. TRANSLATORS: the metadata is very out of date; %u is a number > 1 #, c-format msgid "Firmware metadata has not been updated for %u day and may not be up to date." @@ -631,18 +807,35 @@ msgstr[0] "Firmwaremetadata er ikke blevet opdateret i %u dag og kan være forældet." msgstr[1] "Firmwaremetadata er ikke blevet opdateret i %u dage og kan være forældet." +#. TRANSLATORS: Title: if firmware updates are available +msgid "Firmware updates" +msgstr "Firmwareopdateringer" + msgid "Firmware updates are not supported on this machine." msgstr "Maskinen understøtter ikke firmwareopdateringer." msgid "Firmware updates are supported on this machine." msgstr "Maskinen understøtter firmwareopdateringer." +#. TRANSLATORS: user needs to run a command +msgid "Firmware updates disabled; run 'fwupdmgr unlock' to enable" +msgstr "Firmwareopdateringer deaktiveret; kør 'fwupdmgr unlock' for at aktivere" + +#. TRANSLATORS: description of plugin state, e.g. disabled #. TRANSLATORS: release properties msgid "Flags" msgstr "Flag" +#. TRANSLATORS: command line option +msgid "Force the action by relaxing some runtime checks" +msgstr "Gennemtving handlingen ved at afslappe visse runtimetjek" + msgid "Force the action ignoring all warnings" -msgstr "Tving handlingen og ignorer alle advarsler" +msgstr "Gennemtving handlingen og ignorer alle advarsler" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Fundet" #. TRANSLATORS: global ID common to all similar hardware msgid "GUID" @@ -650,6 +843,11 @@ msgstr[0] "GUID" msgstr[1] "GUID'er" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgctxt "A single GUID" +msgid "GUID" +msgstr "GUID" + #. TRANSLATORS: command description msgid "Get all device flags supported by fwupd" msgstr "Hent alle enhedsflag som understøttes af fwupd" @@ -674,9 +872,17 @@ msgid "Gets the configured remotes" msgstr "Henter de konfigurerede fjerne" +#. TRANSLATORS: command description +msgid "Gets the host security attributes" +msgstr "Henter værtens sikkerhedsattributter" + #. TRANSLATORS: firmware approved by the admin -msgid "Gets the list of approved firmware." -msgstr "Henter listen over godkendt firmware." +msgid "Gets the list of approved firmware" +msgstr "Henter listen over godkendt firmware" + +#. TRANSLATORS: command description +msgid "Gets the list of blocked firmware" +msgstr "Henter listen over blokerede firmware" #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" @@ -694,6 +900,19 @@ msgid "Hardware is waiting to be replugged" msgstr "Hardwaren venter på at bliver gentilkoblet" +#. TRANSLATORS: the release urgency +msgid "High" +msgstr "Høj" + +#. TRANSLATORS: this is a string like 'HSI:2-U' +msgid "Host Security ID:" +msgstr "Værtens sikkerheds-ID:" + +#. TRANSLATORS: Title: +#. https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit +msgid "IOMMU" +msgstr "IOMMU" + #. TRANSLATORS: daemon is inactive msgid "Idle…" msgstr "Inaktiv …" @@ -702,10 +921,26 @@ msgid "Ignore SSL strict checks when downloading files" msgstr "Ignorer strikse SSL-tjek ved download af filer" +#. TRANSLATORS: command line option +msgid "Ignore firmware checksum failures" +msgstr "Ignorer mislykkede checksum for firmware" + +#. TRANSLATORS: command line option +msgid "Ignore firmware hardware mismatch failures" +msgstr "Ignorer mislykkedes firmwarehardware som ikke passer sammen" + +#. TRANSLATORS: command line option +msgid "Ignore requirement of external power source" +msgstr "Ignorer krav om ekstern strømkilde" + #. TRANSLATORS: Ignore validation safety checks when flashing this device msgid "Ignore validation safety checks" msgstr "Ignorer sikkerhedstjek af bekræftelse" +#. TRANSLATORS: try to help +msgid "Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" +msgstr "Ignorerer strikse SSL-tjeks. Eksportér DISABLE_SSL_STRICT i dit miljø for at gøre det automatisk i fremtiden" + #. TRANSLATORS: length of time the update takes to apply msgid "Install Duration" msgstr "Varighed for installation" @@ -750,10 +985,57 @@ msgid "Installing on %s…" msgstr "Installerer på %s …" +#. TRANSLATORS: Title: BootGuard is a trademark from Intel +msgid "Intel BootGuard" +msgstr "Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * ACM means to verify the integrity of Initial Boot Block +msgid "Intel BootGuard ACM protected" +msgstr "Intel BootGuard ACM-beskyttet" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * OTP = one time programmable +msgid "Intel BootGuard OTP fuse" +msgstr "Intel BootGuard OTP-fuse" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * error policy is what to do on failure +msgid "Intel BootGuard error policy" +msgstr "Intel BootGuard regler om fejl" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * verified boot refers to the way the boot process is verified +msgid "Intel BootGuard verified boot" +msgstr "Intel BootGuard bekræftet start" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * active means being used by the OS +msgid "Intel CET Active" +msgstr "Intel CET aktiv" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * enabled means supported by the processor +msgid "Intel CET Enabled" +msgstr "Intel CET-aktiveret" + +#. TRANSLATORS: Title: Direct Connect Interface (DCI) allows +#. * debugging of Intel processors using the USB3 port +msgid "Intel DCI debugger" +msgstr "Intel DCI-fejlsøgning" + +#. TRANSLATORS: Title: SMAP = Supervisor Mode Access Prevention +msgid "Intel SMAP" +msgstr "Intel SMAP" + #. TRANSLATORS: Device cannot be removed easily msgid "Internal device" msgstr "Intern enhed" +#. TRANSLATORS: Suffix: the HSI result +msgid "Invalid" +msgstr "Ugyldig" + #. TRANSLATORS: Is currently in bootloader mode msgid "Is in bootloader mode" msgstr "Er i opstartsindlæsertilstand" @@ -785,6 +1067,22 @@ msgid "Linux Vendor Firmware Service (testing firmware)" msgstr "Linux Vendor Firmware Service (testning firmware)" +#. TRANSLATORS: Title: if it's tainted or not +msgid "Linux kernel" +msgstr "Linux-kerne" + +#. TRANSLATORS: Title: lockdown is a security mode of the kernel +msgid "Linux kernel lockdown" +msgstr "Nedlukning af Linux-kerne" + +#. TRANSLATORS: Title: swap space or swap partition +msgid "Linux swap" +msgstr "Linux-swap" + +#. TRANSLATORS: command line option +msgid "List entries in dbx" +msgstr "Vis poster i dbx" + #. TRANSLATORS: command line option msgid "List supported firmware updates" msgstr "Vis understøttede firmwareopdateringer" @@ -793,13 +1091,43 @@ msgid "List the available firmware types" msgstr "Vis de tilgængelige firmwaretyper" +#. TRANSLATORS: command description +msgid "Lists files on the ESP" +msgstr "Viser filer på ESP'en" + #. TRANSLATORS: parsing the firmware information msgid "Loading…" msgstr "Indlæser …" -#. TRANSLATORS: command line option -msgid "Manually whitelist specific plugins" -msgstr "Manuel hvidlistning af bestemte plugins" +#. TRANSLATORS: Suffix: the HSI result +msgid "Locked" +msgstr "Låst" + +#. TRANSLATORS: the release urgency +msgid "Low" +msgstr "Lav" + +#. TRANSLATORS: Title: MEI = Intel Management Engine +msgid "MEI manufacturing mode" +msgstr "MEI-fabrikstilstand" + +#. TRANSLATORS: Title: MEI = Intel Management Engine, and the +#. * "override" is the physical PIN that can be driven to +#. * logic high -- luckily it is probably not accessible to +#. * end users on consumer boards +msgid "MEI override" +msgstr "MEI-tilsidesættelse" + +msgid "MEI version" +msgstr "MEI-version" + +#. TRANSLATORS: command line option +msgid "Manually enable specific plugins" +msgstr "Aktivér bestemte plugins manuelt" + +#. TRANSLATORS: the release urgency +msgid "Medium" +msgstr "Mellem" #. TRANSLATORS: remote URI msgid "Metadata Signature" @@ -823,8 +1151,8 @@ msgstr "Dæmon og klient passer ikke sammen, brug %s i stedet" #. TRANSLATORS: sets something in daemon.conf -msgid "Modifies a daemon configuration value." -msgstr "Rediger en værdi i dæmonkonfiguration." +msgid "Modifies a daemon configuration value" +msgstr "Rediger en værdi i dæmonkonfiguration" #. TRANSLATORS: command description msgid "Modifies a given remote" @@ -840,6 +1168,10 @@ msgid "Monitor the daemon for events" msgstr "Overvåg dæmonen for hændelser" +#. TRANSLATORS: command description +msgid "Mounts the ESP" +msgstr "Monterer ESP'en" + #. TRANSLATORS: Requires a reboot to apply firmware or to reload hardware msgid "Needs a reboot after installation" msgstr "Genstart efter installation er nødvendig" @@ -852,6 +1184,7 @@ msgid "New version" msgstr "Ny version" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "Der er ikke angivet nogen handling!" @@ -889,15 +1222,23 @@ msgid "No updates were applied" msgstr "Der blev ikke anvendt nogen opdateringer" +#. TRANSLATORS: Suffix: the HSI result +msgid "Not found" +msgstr "Ikke fundet" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Not supported" +msgstr "Ikke-understøttet" + +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "OK" + #. TRANSLATORS: command line option msgid "Only show single PCR value" msgstr "Vis kun én PCR-værdi" #. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Tilsidesæt advarsel for plugin" - -#. TRANSLATORS: command line option msgid "Override the default ESP path" msgstr "Tilsidesæt standard-ESP-stien" @@ -909,6 +1250,14 @@ msgid "Parse and show details about a firmware file" msgstr "Fortolk og vis deltaljer om en firmwarefil" +#. TRANSLATORS: reading new dbx from the update +msgid "Parsing dbx update…" +msgstr "Fortolker dbx-opdatering …" + +#. TRANSLATORS: reading existing dbx from the system +msgid "Parsing system dbx…" +msgstr "Fortolker systemets dbx …" + #. TRANSLATORS: remote filename base msgid "Password" msgstr "Adgangskode" @@ -925,6 +1274,14 @@ msgid "Please enter a number from 0 to %u: " msgstr "Indtast venligst et tal nummer 0 og %u: " +#. TRANSLATORS: Failed to open plugin, hey Arch users +msgid "Plugin dependencies missing" +msgstr "Plugin-afhængigheder mangler" + +#. TRANSLATORS: Title: DMA as in https://en.wikipedia.org/wiki/DMA_attack +msgid "Pre-boot DMA protection" +msgstr "Præopstart DMA-beskyttelse" + #. TRANSLATORS: version number of previous firmware msgid "Previous version" msgstr "Forrige version" @@ -980,8 +1337,12 @@ msgstr "Genopfrisk metadata fra fjernserver" #. TRANSLATORS: command description -msgid "Reinstall current firmware on the device." -msgstr "Geninstaller den nuværende firmware på enheden." +msgid "Reinstall current firmware on the device" +msgstr "Geninstaller den nuværende firmware på enheden" + +#. TRANSLATORS: command description +msgid "Reinstall firmware on a device" +msgstr "Geninstaller firmware på en enhed" #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second is a version number @@ -995,10 +1356,6 @@ msgid "Remote ID" msgstr "Fjern-id" -#. TRANSLATORS: this is when a device is hotplugged -msgid "Removed" -msgstr "Fjernet" - #. TRANSLATORS: command description msgid "Replace data in an existing firmware file" msgstr "Erstat data i en eksisterende firmwarefil" @@ -1011,9 +1368,13 @@ msgid "Reported to remote server" msgstr "Rapporteret til fjernserver" -#. TRANSLATORS: Must be plugged in to an outlet -msgid "Requires AC power" -msgstr "Kræver strømforsygning" +#. TRANSLATORS: the user is using Gentoo/Arch and has screwed something up +msgid "Required efivarfs filesystem was not found" +msgstr "Krævede efivarfs-filsystem blev ikke fundet" + +#. TRANSLATORS: not required for this system +msgid "Required hardware was not found" +msgstr "Det krævede hardware blev ikke fundet" #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user msgid "Requires a bootloader" @@ -1050,6 +1411,22 @@ msgid "Run the plugin composite prepare routine when using install-blob" msgstr "Kør forberedelsesrutinen for pluginkomposition når install-blob bruges" +#. TRANSLATORS: this is the HSI suffix +msgid "Runtime Suffix" +msgstr "Suffiks for runtime" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI BIOS region" +msgstr "SPI BIOS-region" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI lock" +msgstr "SPI-lås" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI write" +msgstr "SPI-skriv" + #. TRANSLATORS: command line option msgid "Save device state into a JSON file between executions" msgstr "Gem enhedens tilstand i en JSON-fil mellem udførsler" @@ -1062,10 +1439,19 @@ msgid "Scheduling…" msgstr "Planlægger …" +#. TRANSLATORS: %s is a link to a website +#, c-format +msgid "See %s for more information." +msgstr "Se %s for mere information." + #. TRANSLATORS: Device has been chosen by the daemon for the user msgid "Selected device" msgstr "Valgte enhed" +#. TRANSLATORS: Volume has been chosen by the user +msgid "Selected volume" +msgstr "Valgte diskområde" + #. TRANSLATORS: serial number of hardware msgid "Serial Number" msgstr "Serienummer" @@ -1074,18 +1460,19 @@ msgid "Set the debugging flag during update" msgstr "Indstil fejlsøgningsflaget under opdatering" +#. TRANSLATORS: firmware approved by the admin msgid "Sets the list of approved firmware" msgstr "Indstiller listen over godkendt firmware" -#. TRANSLATORS: firmware approved by the admin -msgid "Sets the list of approved firmware." -msgstr "Indstiller listen over godkendt firmware." - #. TRANSLATORS: command description msgid "Share firmware history with the developers" msgstr "Del historik over firmware med udviklerne" #. TRANSLATORS: command line option +msgid "Show all results" +msgstr "Vis alle resultater" + +#. TRANSLATORS: command line option msgid "Show client and daemon versions" msgstr "Vis klient- og dæmonversioner" @@ -1118,6 +1505,10 @@ msgstr "Vis uddybende information om plugin" #. TRANSLATORS: command line option +msgid "Show the calculated version of the dbx" +msgstr "Vis den udregnede version af dbx'en" + +#. TRANSLATORS: command line option msgid "Show the debug log from the last attempted update" msgstr "Vis fejlsøgningsloggen fra den opdatering der blev forsøgt sidst" @@ -1154,6 +1545,10 @@ msgid "Specify Vendor/Product ID(s) of DFU device" msgstr "Angiv producent-/produkt-id('er) for DFU-enhed" +#. TRANSLATORS: command line option +msgid "Specify the dbx database file" +msgstr "Angiv dbx-databasefilen" + msgid "Specify the number of bytes per USB transfer" msgstr "Angiv antal bytes pr. USB-overførsel" @@ -1211,10 +1606,42 @@ msgid "Summary" msgstr "Opsummering" +#. TRANSLATORS: Suffix: the HSI result +msgid "Supported" +msgstr "Understøttet" + #. TRANSLATORS: Is found in current metadata msgid "Supported on remote server" msgstr "Understøttes på fjernserver" +#. TRANSLATORS: Title: a better sleep state +msgid "Suspend-to-idle" +msgstr "Suspender-til-inaktiv" + +#. TRANSLATORS: Title: sleep state +msgid "Suspend-to-ram" +msgstr "Suspender-til-ram" + +#. TRANSLATORS: command description +msgid "Switch the firmware branch on the device" +msgstr "Skift firmwaregrenen på enheden" + +#. TRANSLATORS: Must be plugged in to an outlet +msgid "System requires external power source" +msgstr "Systemet kræver ekstern strømkilde" + +#. TRANSLATORS: Title: the PCR is rebuilt from the TPM event log +msgid "TPM PCR0 reconstruction" +msgstr "TPM PCR0-rekonstruktion" + +#. TRANSLATORS: Title: TPM = Trusted Platform Module +msgid "TPM v2.0" +msgstr "TPM v2.0" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Tainted" +msgstr "Tainted" + msgid "Target" msgstr "Mål" @@ -1222,6 +1649,23 @@ msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "LVFS'en er en gratis tjeneste der opererer som en selvstændig juridisk enhed og har ingen forbindelse med $OS_RELEASE:NAME$. Din distributør har måske ikke bekræftet nogen af firmwareopdateringerne for kompatibilitet med dit system eller tilsluttede enheder. Al firmware leveres kun af den oprindelige udstyrsproducent." +#. TRANSLATORS: this is more background on a security measurement problem +msgid "The TPM PCR0 differs from reconstruction." +msgstr "TPM PCR0'en er ikke magen til rekonstruktionen." + +#. TRANSLATORS: the user is SOL for support... +msgid "The daemon has loaded 3rd party code and is no longer supported by the upstream developers!" +msgstr "Dæmonen har indlæst tredjepartskode og understøttes ikke længere af opstrømsudviklerne!" + +#. TRANSLATORS: %1 is the firmware vendor, %2 is the device vendor name +#, c-format +msgid "The firmware from %s is not supplied by %s, the hardware vendor." +msgstr "Firmwaren fra %s leveres ikke af hardwareleverandøren %s." + +#. TRANSLATORS: nothing to show +msgid "There are no blocked firmware files" +msgstr "Der er ikke nogen blokerede firmwarefiler" + #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator msgid "There is no approved firmware." @@ -1234,6 +1678,18 @@ msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "Fjernen indeholder firmware som der ikke er embargo på, men som stadigvæk testes af hardwareproducenten. Du skal sikre dig at du har en manuel måde til at nedgradere firmwaren på hvis firmwareopdateringen mislykkedes." +#. TRANSLATORS: this is instructions on how to improve the HSI suffix +msgid "This system has HSI runtime issues." +msgstr "Systemet har problemer med HSI-runtime." + +#. TRANSLATORS: this is instructions on how to improve the HSI security level +msgid "This system has a low HSI security level." +msgstr "Systemet har et lavt HSI-sikkerhedsniveau." + +#. TRANSLATORS: description of dbxtool +msgid "This tool allows an administrator to apply UEFI dbx updates." +msgstr "Værktøjet giver en administrator mulighed for at anvende UEFI-dbx-opdateringer." + #. TRANSLATORS: the user needs to stop playing with stuff msgid "This tool can only be used by the root user" msgstr "Værktøjet kan kun bruges af root-brugeren" @@ -1242,10 +1698,42 @@ msgid "Type" msgstr "Type" +#. TRANSLATORS: partition refers to something on disk, again, hey Arch users +msgid "UEFI ESP partition not detected or configured" +msgstr "UEFI ESP-partition ikke registreret eller konfigureret" + #. TRANSLATORS: program name msgid "UEFI Firmware Utility" msgstr "UEFI-firmwareredskab" +#. TRANSLATORS: program name +msgid "UEFI dbx Utility" +msgstr "UEFI-dbx-redskab" + +#. TRANSLATORS: Title: SB is a way of locking down UEFI +msgid "UEFI secure boot" +msgstr "UEFI sikkeropstart" + +#. TRANSLATORS: error message +msgid "Unable to connect to service" +msgstr "Kan ikke oprette forbindelse til tjeneste" + +#. TRANSLATORS: command description +msgid "Unbind current driver" +msgstr "Fjern binding af nuværende driver" + +#. TRANSLATORS: we will now offer this firmware to the user +msgid "Unblocking firmware:" +msgstr "Fjerner blokering af firmware:" + +#. TRANSLATORS: command description +msgid "Unblocks a specific firmware from being installed" +msgstr "Fjerner blokering af en bestemt firmware fra at blive installeret" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Unencrypted" +msgstr "Dekrypteret" + #. TRANSLATORS: current daemon status is unknown #. TRANSLATORS: we don't know the license of the update #. TRANSLATORS: unknown release urgency @@ -1259,10 +1747,18 @@ msgid "Unlock the device to allow access" msgstr "Lås enheden op for at tillade adgang" +#. TRANSLATORS: Suffix: the HSI result +msgid "Unlocked" +msgstr "Låst op" + #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "Låser op for enheden for at få adgang til firmwaren" +#. TRANSLATORS: command description +msgid "Unmounts the ESP" +msgstr "Afmonterer ESP'en" + #. TRANSLATORS: command line option msgid "Unset the debugging flag during update" msgstr "Fjern fejlsøgningsflaget under opdatering" @@ -1270,7 +1766,11 @@ #. TRANSLATORS: error message #, c-format msgid "Unsupported daemon version %s, client version is %s" -msgstr "Uunderstøttet dæmonversion %s, klientversionen er %s" +msgstr "Ikke-understøttet dæmonversion %s, klientversionen er %s" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Untainted" +msgstr "Untainted" #. TRANSLATORS: Device is updatable in this or any other mode msgid "Updatable" @@ -1283,7 +1783,7 @@ #. TRANSLATORS: helpful messages from last update #. TRANSLATORS: helpful messages for the update msgid "Update Message" -msgstr "Opdateringsmeddelelese" +msgstr "Opdateringsmeddelelse" #. TRANSLATORS: hardware state, e.g. "pending" msgid "Update State" @@ -1320,6 +1820,9 @@ msgid "Updates all firmware to latest versions available" msgstr "Opdaterer alle firmware til de seneste versioner" +msgid "Updating" +msgstr "Opdaterer" + #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second and third are #. * version numbers e.g. "1.2.3" @@ -1338,10 +1841,6 @@ msgid "Upgrade available for %s from %s to %s" msgstr "Opgradering tilgængelig for %s fra %s til %s" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Uploadmeddelelse:" - msgid "Upload report just this one time, but prompt again for future updates" msgid_plural "Upload reports just this one time, but prompt again for future updates" msgstr[0] "Upload rapport denne ene gang men spørg igen om fremtidige opdateringer" @@ -1360,6 +1859,18 @@ msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." msgstr "Upload af firmwarerapporter hjælper hardwareproducenter til hurtigt at identificere opdateringer som fejlede og lykkedes på rigtigt hardware." +#. TRANSLATORS: how important the release is +msgid "Urgency" +msgstr "Vigtighed" + +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdmgr --help for help" +msgstr "Brug fwupdmgr --help for hjælp" + +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdtool --help for help" +msgstr "Brug fwupdtool --help for hjælp" + #. TRANSLATORS: command line option msgid "Use quirk flags when installing firmware" msgstr "Brug quirk-flag ved installation af firmware" @@ -1372,6 +1883,14 @@ msgid "Username" msgstr "Brugernavn" +#. TRANSLATORS: Suffix: the HSI result +msgid "Valid" +msgstr "Gyldig" + +#. TRANSLATORS: ESP refers to the EFI System Partition +msgid "Validating ESP contents…" +msgstr "Validerer ESP-indhold …" + #. TRANSLATORS: one line variant of release (e.g. 'Prerelease' or 'China') msgid "Variant" msgstr "Variant" @@ -1384,19 +1903,19 @@ msgid "Verifying…" msgstr "Verificerer …" -#. TRANSLATORS: try to help -msgid "WARNING: Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" -msgstr "ADVARSEL: Ignorerer strikse SSL-tjeks. Eksportér DISABLE_SSL_STRICT i dit miljø for at gøre det automatisk i fremtiden" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Version" + +#. TRANSLATORS: this is a prefix on the console +msgid "WARNING:" +msgstr "ADVARSEL:" #. TRANSLATORS: waiting for device to do something msgid "Waiting…" msgstr "Venter …" #. TRANSLATORS: command description -msgid "Watch DFU devices being hotplugged" -msgstr "Hold øje med DFU-enheder som hotplugges" - -#. TRANSLATORS: command description msgid "Watch for hardware changes" msgstr "Hold øje med hardwareændringer" @@ -1408,6 +1927,10 @@ msgid "Write firmware from file into one partition" msgstr "Skriv firmware fra fil ind i en partition" +#. TRANSLATORS: decompressing images from a container firmware +msgid "Writing file:" +msgstr "Skriver fil:" + #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Skriver …" @@ -1416,19 +1939,19 @@ msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "Din distributør har måske ikke verificeret kompatibiliteten af firmwareopdateringerne med dit system eller tilsluttede enheder." +#. TRANSLATORS: %1 is the device vendor name +#, c-format +msgid "Your hardware may be damaged using this firmware, and installing this release may void any warranty with %s." +msgstr "Der er mulighed for at din hardware kan tage skade hvis firmwaren bruges og installation af udgivelsen kan ugyldiggøre garantien med %s." + +#. TRANSLATORS: this is the default branch name when unset +msgid "default" +msgstr "standard" + #. TRANSLATORS: program name msgid "fwupd TPM event log utility" msgstr "fwupd TPM-hændelseslogredskab" -#. TRANSLATORS: message letting the user know no device upgrade available due -#. to missing on LVFS -#. * %1 is the device name -#, c-format -msgid "• %s has no available firmware updates" -msgstr "• %s har ingen tilgængelige firmwareopdateringer" - -#. TRANSLATORS: message letting the user know no device upgrade available -#. * %1 is the device name -#, c-format -msgid "• %s has the latest available firmware version" -msgstr "• %s har den seneste tilgængelige firmwareversion" +#. TRANSLATORS: Title: if the fwupd plugins are all present and correct +msgid "fwupd plugins" +msgstr "fwupd-plugins" diff -Nru fwupd-1.4.5/po/de.po fwupd-1.5.8/po/de.po --- fwupd-1.4.5/po/de.po 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/po/de.po 2021-03-31 20:08:32.000000000 +0000 @@ -24,10 +24,6 @@ msgstr[0] "%.0f Minute verbleibt" msgstr[1] "%.0f Minuten verbleiben" -#. TRANSLATORS: this is when a device is hotplugged -msgid "Added" -msgstr "Hinzugefügt" - #. TRANSLATORS: the age of the metadata msgid "Age" msgstr "Alter" @@ -93,7 +89,6 @@ msgid "Cancelled" msgstr "Abgebrochen" -#. TRANSLATORS: this is when a device is hotplugged #. TRANSLATORS: this is when the daemon state changes msgid "Changed" msgstr "Geändert" @@ -177,6 +172,7 @@ msgid "Do not write to the history database" msgstr "Nicht in die Verlaufsdatenbank schreiben" +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Fertig." @@ -213,6 +209,8 @@ msgid "Enable firmware update support on supported systems" msgstr "Firmware-Aktualisierungsunterstützung auf unterstützten Systemen aktivieren" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Aktiviert" @@ -243,22 +241,6 @@ msgid "Failed to parse arguments" msgstr "Verarbeitung der Argumente schlug fehl" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "Datei wird abgerufen" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "Firmware wird abgerufen" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "Metadaten werden abgerufen" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "Signatur wird abgerufen" - #. TRANSLATORS: filename of the local file msgid "Filename" msgstr "Dateiname" @@ -299,6 +281,15 @@ msgid "Force the action ignoring all warnings" msgstr "Aktion erzwingen, bei der alle Warnungen ignoriert werden" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Gefunden" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgctxt "A single GUID" +msgid "GUID" +msgstr "GUID" + #. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "Alle Geräte ermitteln, die Firmware-Aktualisierungen unterstützen" @@ -392,6 +383,7 @@ msgid "Monitor the daemon for events" msgstr "Hintergrundprogramm auf Ereignisse überwachen" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "Keine Aktion angegeben!" @@ -403,9 +395,9 @@ msgid "No plugins found" msgstr "Keine Plugins gefunden" -#. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Plugin-Warnung überschreiben" +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "Ok" #. TRANSLATORS: command line option msgid "Override the default ESP path" @@ -463,10 +455,6 @@ msgid "Reinstalling %s with %s... " msgstr "Erneute Installation von %s mit %s …" -#. TRANSLATORS: this is when a device is hotplugged -msgid "Removed" -msgstr "Entfernt" - #. TRANSLATORS: command description msgid "Replace data in an existing firmware file" msgstr "Daten in einer bestehenden Firmware-Datei ersetzen" @@ -601,10 +589,6 @@ msgid "Updating %s…" msgstr "%s wird aktualisiert …" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Nachricht beim Hochladen:" - #. TRANSLATORS: ask the user to upload msgid "Upload report now?" msgstr "Bericht jetzt hochladen?" @@ -621,15 +605,15 @@ msgid "Verifying…" msgstr "Überprüfung …" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Version" + #. TRANSLATORS: waiting for device to do something msgid "Waiting…" msgstr "Warten …" #. TRANSLATORS: command description -msgid "Watch DFU devices being hotplugged" -msgstr "Geräteanschluss von DFU-Geräten überwachen" - -#. TRANSLATORS: command description msgid "Watch for hardware changes" msgstr "Auf Hardware-Änderungen achten" diff -Nru fwupd-1.4.5/po/en_GB.po fwupd-1.5.8/po/en_GB.po --- fwupd-1.4.5/po/en_GB.po 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/po/en_GB.po 2021-03-31 20:08:32.000000000 +0000 @@ -3,8 +3,8 @@ # This file is distributed under the same license as the fwupd package. # # Translators: -# Andi Chandler , 2019 -# Richard Hughes , 2015,2017-2019 +# Andi Chandler , 2019-2020 +# Richard Hughes , 2015,2017-2021 msgid "" msgstr "" "Project-Id-Version: fwupd\n" @@ -23,6 +23,18 @@ msgstr[0] "%.0f minute remaining" msgstr[1] "%.0f minutes remaining" +#. TRANSLATORS: the CPU microcode is firmware loaded onto the CPU +#. * at system bootup +#, c-format +msgid "%s CPU Microcode Update" +msgstr "%s CPU Microcode Update" + +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Secure Boot` +#, c-format +msgid "%s Configuration Update" +msgstr "%s Configuration Update" + #. TRANSLATORS: ME stands for Management Engine, where #. * the first %s is the device name, e.g. 'ThinkPad P50` #, c-format @@ -86,6 +98,11 @@ msgid "%s and all connected devices may not be usable while updating." msgstr "%s and all connected devices may not be usable while updating." +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s manufacturing mode" +msgstr "%s manufacturing mode" + #. TRANSLATORS: warn the user before updating, %1 is a device name #, c-format msgid "%s must remain connected for the duration of the update to avoid damage." @@ -96,6 +113,21 @@ msgid "%s must remain plugged into a power source for the duration of the update to avoid damage." msgstr "%s must remain plugged into a power source for the duration of the update to avoid damage." +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s override" +msgstr "%s override" + +#. TRANSLATORS: Title: %1 is ME kind, e.g. CSME/TXT, %2 is a version number +#, c-format +msgid "%s v%s" +msgstr "%s v%s" + +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s version" +msgstr "%s version" + #. TRANSLATORS: duration in days! #, c-format msgid "%u day" @@ -103,6 +135,12 @@ msgstr[0] "%u day" msgstr[1] "%u days" +#, c-format +msgid "%u device has a firmware upgrade available." +msgid_plural "%u devices have a firmware upgrade available." +msgstr[0] "%u device has a firmware upgrade available." +msgstr[1] "%u devices have a firmware upgrade available." + #. TRANSLATORS: duration in minutes #, c-format msgid "%u hour" @@ -131,6 +169,10 @@ msgstr[0] "%u second" msgstr[1] "%u seconds" +#. TRANSLATORS: this is shown as a suffix for obsoleted tests +msgid "(obsoleted)" +msgstr "(obsoleted)" + #. TRANSLATORS: command description msgid "Activate devices" msgstr "Activate devices" @@ -150,10 +192,6 @@ msgid "Activating firmware update for" msgstr "Activating firmware update for" -#. TRANSLATORS: this is when a device is hotplugged -msgid "Added" -msgstr "Added" - #. TRANSLATORS: the age of the metadata msgid "Age" msgstr "Age" @@ -175,6 +213,10 @@ msgid "Allow reinstalling existing firmware versions" msgstr "Allow reinstalling existing firmware versions" +#. TRANSLATORS: command line option +msgid "Allow switching firmware branch" +msgstr "Allow switching firmware branch" + #. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "An update requires a reboot to complete." @@ -191,6 +233,18 @@ msgid "Apply firmware updates" msgstr "Apply firmware updates" +#. TRANSLATORS: command line option +msgid "Apply update even when not advised" +msgstr "Apply update even when not advised" + +#. TRANSLATORS: command line option +msgid "Apply update files" +msgstr "Apply update files" + +#. TRANSLATORS: actually sending the update to the hardware +msgid "Applying update…" +msgstr "Applying update…" + #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator msgid "Approved firmware:" @@ -198,6 +252,10 @@ msgstr[0] "Approved firmware:" msgstr[1] "Approved firmware:" +#. TRANSLATORS: stop nagging the user +msgid "Ask again next time?" +msgstr "Ask again next time?" + #. TRANSLATORS: command description msgid "Attach to firmware mode" msgstr "Attach to firmware mode" @@ -254,14 +312,53 @@ msgid "Automatic Reporting" msgstr "Automatic Reporting" +#. TRANSLATORS: can we JFDI? +msgid "Automatically upload every time?" +msgstr "Automatically upload every time?" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "BUILDER-XML FILENAME-DST" +msgstr "BUILDER-XML FILENAME-DST" + +msgid "BYTES" +msgstr "BYTES" + +#. TRANSLATORS: command description +msgid "Bind new kernel driver" +msgstr "Bind new kernel driver" + +#. TRANSLATORS: there follows a list of hashes +msgid "Blocked firmware files:" +msgstr "Blocked firmware files:" + +#. TRANSLATORS: we will not offer this firmware to the user +msgid "Blocking firmware:" +msgstr "Blocking firmware:" + +#. TRANSLATORS: command description +msgid "Blocks a specific firmware from being installed" +msgstr "Blocks a specific firmware from being installed" + #. TRANSLATORS: firmware version of bootloader msgid "Bootloader Version" msgstr "Bootloader Version" +#. TRANSLATORS: the stream of firmware, e.g. nonfree or open-source +msgid "Branch" +msgstr "Branch" + +#. TRANSLATORS: command description +msgid "Build a firmware file" +msgstr "Build a firmware file" + #. TRANSLATORS: command description msgid "Build firmware using a sandbox" msgstr "Build firmware using a sandbox" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "CHECKSUM1[,CHECKSUM2][,CHECKSUM3]" +msgstr "CHECKSUM1[,CHECKSUM2][,CHECKSUM3]" + #. TRANSLATORS: this is to abort the interactive prompt msgid "Cancel" msgstr "Cancel" @@ -270,7 +367,14 @@ msgid "Cancelled" msgstr "Cancelled" -#. TRANSLATORS: this is when a device is hotplugged +#. TRANSLATORS: same or newer update already applied +msgid "Cannot apply as dbx update has already been applied." +msgstr "Cannot apply as dbx update has already been applied." + +#. TRANSLATORS: the user is using a LiveCD or LiveUSB install disk +msgid "Cannot apply updates on live media" +msgstr "Cannot apply updates on live media" + #. TRANSLATORS: this is when the daemon state changes msgid "Changed" msgstr "Changed" @@ -283,6 +387,11 @@ msgid "Checksum" msgstr "Checksum" +#. TRANSLATORS: get interactive prompt, where branch is the +#. * supplier of the firmware, e.g. "non-free" or "free" +msgid "Choose a branch:" +msgstr "Choose a branch:" + #. TRANSLATORS: get interactive prompt msgid "Choose a device:" msgstr "Choose a device:" @@ -295,6 +404,10 @@ msgid "Choose a release:" msgstr "Choose a release:" +#. TRANSLATORS: get interactive prompt +msgid "Choose a volume:" +msgstr "Choose a volume:" + #. TRANSLATORS: command description msgid "Clears any updates scheduled to be updated offline" msgstr "Clears any updates scheduled to be updated offline" @@ -311,6 +424,18 @@ msgid "Continue with update?" msgstr "Continue with update?" +#. TRANSLATORS: command description +msgid "Convert a firmware file" +msgstr "Convert a firmware file" + +#. TRANSLATORS: when the update was built +msgid "Created" +msgstr "Created" + +#. TRANSLATORS: the release urgency +msgid "Critical" +msgstr "Critical" + #. TRANSLATORS: Device supports some form of checksum verification msgid "Cryptographic hash verification is available" msgstr "Cryptographic hash verification is available" @@ -319,6 +444,10 @@ msgid "Current version" msgstr "Current version" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "DEVICE-ID|GUID" +msgstr "DEVICE-ID|GUID" + #. TRANSLATORS: DFU stands for device firmware update msgid "DFU Utility" msgstr "DFU Utility" @@ -363,10 +492,18 @@ msgid "Device changed:" msgstr "Device changed:" +#. TRANSLATORS: a version check is required for all firmware +msgid "Device firmware is required to have a version check" +msgstr "Device firmware is required to have a version check" + #. TRANSLATORS: Is locked and can be unlocked msgid "Device is locked" msgstr "Device is locked" +#. TRANSLATORS: a version check is required for all firmware +msgid "Device is required to install all provided releases" +msgstr "Device is required to install all provided releases" + #. TRANSLATORS: Device remains usable during update msgid "Device is usable for the duration of the update" msgstr "Device is usable for the duration of the update" @@ -379,10 +516,18 @@ msgid "Device stages updates" msgstr "Device stages updates" +#. TRANSLATORS: there is more than one supplier of the firmware +msgid "Device supports switching to a different branch of firmware" +msgstr "Device supports switching to a different branch of firmware" + #. TRANSLATORS: Device update needs to be separately activated msgid "Device update needs activation" msgstr "Device update needs activation" +#. TRANSLATORS: save the old firmware to disk before installing the new one +msgid "Device will backup firmware before installing" +msgstr "Device will backup firmware before installing" + #. TRANSLATORS: Device will not return after update completes msgid "Device will not re-appear after update completes" msgstr "Device will not re-appear after update completes" @@ -395,6 +540,20 @@ msgid "Devices that were not updated correctly:" msgstr "Devices that were not updated correctly:" +#. TRANSLATORS: message letting the user know no device upgrade available due +#. to missing on LVFS +msgid "Devices with no available firmware updates: " +msgstr "Devices with no available firmware updates: " + +#. TRANSLATORS: message letting the user know no device upgrade available +msgid "Devices with the latest available firmware version:" +msgstr "Devices with the latest available firmware version:" + +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is inactive and not used +msgid "Disabled" +msgstr "Disabled" + msgid "Disabled fwupdate debugging" msgstr "Disabled fwupdate debugging" @@ -418,6 +577,10 @@ msgid "Do not check for unreported history" msgstr "Do not check for unreported history" +#. TRANSLATORS: command line option +msgid "Do not check if download remotes should be enabled" +msgstr "Do not check if download remotes should be enabled" + #. TRANSLATORS: turn on all debugging msgid "Do not include log domain prefix" msgstr "Do not include log domain prefix" @@ -444,6 +607,11 @@ msgid "Do not write to the history database" msgstr "Do not write to the history database" +#. TRANSLATORS: should the branch be changed +msgid "Do you understand the consequences of changing the firmware branch?" +msgstr "Do you understand the consequences of changing the firmware branch?" + +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Done!" @@ -488,6 +656,8 @@ msgid "Enable this remote?" msgstr "Enable this remote?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Enabled" @@ -506,6 +676,14 @@ msgid "Enabling this remote is done at your own risk." msgstr "Enabling this remote is done at your own risk." +#. TRANSLATORS: Suffix: the HSI result +msgid "Encrypted" +msgstr "Encrypted" + +#. TRANSLATORS: Title: Memory contents are encrypted, e.g. Intel TME +msgid "Encrypted RAM" +msgstr "Encrypted RAM" + #. TRANSLATORS: command description msgid "Erase all firmware update history" msgstr "Erase all firmware update history" @@ -522,14 +700,63 @@ msgid "Exit after the engine has loaded" msgstr "Exit after the engine has loaded" +#. TRANSLATORS: command description +msgid "Extract a firmware blob to images" +msgstr "Extract a firmware blob to images" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILE" +msgstr "FILE" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILE [DEVICE-ID|GUID]" +msgstr "FILE [DEVICE-ID|GUID]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILE-IN FILE-OUT [SCRIPT] [OUTPUT]" +msgstr "FILE-IN FILE-OUT [SCRIPT] [OUTPUT]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME" +msgstr "FILENAME" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME DEVICE-ALT-NAME|DEVICE-ALT-ID" +msgstr "FILENAME DEVICE-ALT-NAME|DEVICE-ALT-ID" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME DEVICE-ALT-NAME|DEVICE-ALT-ID [IMAGE-ALT-NAME|IMAGE-ALT-ID]" +msgstr "FILENAME DEVICE-ALT-NAME|DEVICE-ALT-ID [IMAGE-ALT-NAME|IMAGE-ALT-ID]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME DEVICE-ID" +msgstr "FILENAME DEVICE-ID" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME [DEVICE-ID|GUID]" +msgstr "FILENAME [DEVICE-ID|GUID]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME [FIRMWARE-TYPE]" +msgstr "FILENAME [FIRMWARE-TYPE]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME-SRC FILENAME-DST [FIRMWARE-TYPE-SRC] [FIRMWARE-TYPE-DST]" +msgstr "FILENAME-SRC FILENAME-DST [FIRMWARE-TYPE-SRC] [FIRMWARE-TYPE-DST]" + +#. TRANSLATORS: Suffix: the fallback HSI result +#. TRANSLATORS: The update state of the specific device +msgid "Failed" +msgstr "Failed" + +#. TRANSLATORS: dbx file failed to be applied as an update +msgid "Failed to apply update" +msgstr "Failed to apply update" + #. TRANSLATORS: we could not talk to the fwupd daemon msgid "Failed to connect to daemon" msgstr "Failed to connect to daemon" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "Failed to download due to server limit" - #. TRANSLATORS: we could not get the devices to update offline msgid "Failed to get pending devices" msgstr "Failed to get pending devices" @@ -538,10 +765,19 @@ msgid "Failed to install firmware update" msgstr "Failed to install firmware update" +#. TRANSLATORS: could not read existing system data +#. TRANSLATORS: could not read file +msgid "Failed to load local dbx" +msgstr "Failed to load local dbx" + #. TRANSLATORS: quirks are device-specific workarounds msgid "Failed to load quirks" msgstr "Failed to load quirks" +#. TRANSLATORS: could not read existing system data +msgid "Failed to load system dbx" +msgstr "Failed to load system dbx" + #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Failed to parse arguments" @@ -554,6 +790,10 @@ msgid "Failed to parse flags for --filter" msgstr "Failed to parse flags for --filter" +#. TRANSLATORS: could not parse file +msgid "Failed to parse local dbx" +msgstr "Failed to parse local dbx" + #. TRANSLATORS: we could not reboot for some reason msgid "Failed to reboot" msgstr "Failed to reboot" @@ -562,21 +802,10 @@ msgid "Failed to set splash mode" msgstr "Failed to set splash mode" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "Fetching file" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "Fetching firmware" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "Fetching metadata" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "Fetching signature" +#. TRANSLATORS: something with a blocked hash exists +#. * in the users ESP -- which would be bad! +msgid "Failed to validate ESP contents" +msgstr "Failed to validate ESP contents" #. TRANSLATORS: filename of the local file msgid "Filename" @@ -586,6 +815,10 @@ msgid "Filename Signature" msgstr "Filename Signature" +#. TRANSLATORS: user did not include a filename parameter +msgid "Filename required" +msgstr "Filename required" + #. TRANSLATORS: command line option msgid "Filter with a set of device flags using a ~ prefix to exclude, e.g. 'internal,~needs-reboot'" msgstr "Filter with a set of device flags using a ~ prefix to exclude, e.g. 'internal,~needs-reboot'" @@ -610,6 +843,22 @@ msgid "Firmware Utility" msgstr "Firmware Utility" +#. TRANSLATORS: Title: if we can verify the firmware checksums +msgid "Firmware attestation" +msgstr "Firmware attestation" + +#. TRANSLATORS: system is not booted in UEFI mode +msgid "Firmware can not be updated in legacy BIOS mode" +msgstr "Firmware can not be updated in legacy BIOS mode" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is already blocked" +msgstr "Firmware is already blocked" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is not already blocked" +msgstr "Firmware is not already blocked" + #. TRANSLATORS: the metadata is very out of date; %u is a number > 1 #, c-format msgid "Firmware metadata has not been updated for %u day and may not be up to date." @@ -617,25 +866,47 @@ msgstr[0] "Firmware metadata has not been updated for %u day and may not be up to date." msgstr[1] "Firmware metadata has not been updated for %u days and may not be up to date." +#. TRANSLATORS: Title: if firmware updates are available +msgid "Firmware updates" +msgstr "Firmware updates" + msgid "Firmware updates are not supported on this machine." msgstr "Firmware updates are not supported on this machine." msgid "Firmware updates are supported on this machine." msgstr "Firmware updates are supported on this machine." +#. TRANSLATORS: user needs to run a command +msgid "Firmware updates disabled; run 'fwupdmgr unlock' to enable" +msgstr "Firmware updates disabled; run 'fwupdmgr unlock' to enable" + +#. TRANSLATORS: description of plugin state, e.g. disabled #. TRANSLATORS: release properties msgid "Flags" msgstr "Flags" +#. TRANSLATORS: command line option +msgid "Force the action by relaxing some runtime checks" +msgstr "Force the action by relaxing some runtime checks" + msgid "Force the action ignoring all warnings" msgstr "Force the action ignoring all warnings" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Found" + #. TRANSLATORS: global ID common to all similar hardware msgid "GUID" msgid_plural "GUIDs" msgstr[0] "GUID" msgstr[1] "GUIDs" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgctxt "A single GUID" +msgid "GUID" +msgstr "GUID" + #. TRANSLATORS: command description msgid "Get all device flags supported by fwupd" msgstr "Get all device flags supported by fwupd" @@ -660,9 +931,17 @@ msgid "Gets the configured remotes" msgstr "Gets the configured remotes" +#. TRANSLATORS: command description +msgid "Gets the host security attributes" +msgstr "Gets the host security attributes" + #. TRANSLATORS: firmware approved by the admin -msgid "Gets the list of approved firmware." -msgstr "Gets the list of approved firmware." +msgid "Gets the list of approved firmware" +msgstr "Gets the list of approved firmware" + +#. TRANSLATORS: command description +msgid "Gets the list of blocked firmware" +msgstr "Gets the list of blocked firmware" #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" @@ -676,10 +955,27 @@ msgid "Gets the results from the last update" msgstr "Gets the results from the last update" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "HWIDS-FILE" +msgstr "HWIDS-FILE" + #. TRANSLATORS: The hardware is waiting to be replugged msgid "Hardware is waiting to be replugged" msgstr "Hardware is waiting to be replugged" +#. TRANSLATORS: the release urgency +msgid "High" +msgstr "High" + +#. TRANSLATORS: this is a string like 'HSI:2-U' +msgid "Host Security ID:" +msgstr "Host Security ID:" + +#. TRANSLATORS: Title: +#. https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit +msgid "IOMMU" +msgstr "IOMMU" + #. TRANSLATORS: daemon is inactive msgid "Idle…" msgstr "Idle…" @@ -688,10 +984,26 @@ msgid "Ignore SSL strict checks when downloading files" msgstr "Ignore SSL strict checks when downloading files" +#. TRANSLATORS: command line option +msgid "Ignore firmware checksum failures" +msgstr "Ignore firmware checksum failures" + +#. TRANSLATORS: command line option +msgid "Ignore firmware hardware mismatch failures" +msgstr "Ignore firmware hardware mismatch failures" + +#. TRANSLATORS: command line option +msgid "Ignore requirement of external power source" +msgstr "Ignore requirement of external power source" + #. TRANSLATORS: Ignore validation safety checks when flashing this device msgid "Ignore validation safety checks" msgstr "Ignore validation safety checks" +#. TRANSLATORS: try to help +msgid "Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" +msgstr "Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" + #. TRANSLATORS: length of time the update takes to apply msgid "Install Duration" msgstr "Install Duration" @@ -736,10 +1048,57 @@ msgid "Installing on %s…" msgstr "Installing on %s…" +#. TRANSLATORS: Title: BootGuard is a trademark from Intel +msgid "Intel BootGuard" +msgstr "Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * ACM means to verify the integrity of Initial Boot Block +msgid "Intel BootGuard ACM protected" +msgstr "Intel BootGuard ACM protected" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * OTP = one time programmable +msgid "Intel BootGuard OTP fuse" +msgstr "Intel BootGuard OTP fuse" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * error policy is what to do on failure +msgid "Intel BootGuard error policy" +msgstr "Intel BootGuard error policy" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * verified boot refers to the way the boot process is verified +msgid "Intel BootGuard verified boot" +msgstr "Intel BootGuard verified boot" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * active means being used by the OS +msgid "Intel CET Active" +msgstr "Intel CET Active" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * enabled means supported by the processor +msgid "Intel CET Enabled" +msgstr "Intel CET Enabled" + +#. TRANSLATORS: Title: Direct Connect Interface (DCI) allows +#. * debugging of Intel processors using the USB3 port +msgid "Intel DCI debugger" +msgstr "Intel DCI debugger" + +#. TRANSLATORS: Title: SMAP = Supervisor Mode Access Prevention +msgid "Intel SMAP" +msgstr "Intel SMAP" + #. TRANSLATORS: Device cannot be removed easily msgid "Internal device" msgstr "Internal device" +#. TRANSLATORS: Suffix: the HSI result +msgid "Invalid" +msgstr "Invalid" + #. TRANSLATORS: Is currently in bootloader mode msgid "Is in bootloader mode" msgstr "Is in bootloader mode" @@ -750,6 +1109,10 @@ msgstr[0] "Issue" msgstr[1] "Issues" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "KEY,VALUE" +msgstr "KEY,VALUE" + msgid "Keyring" msgstr "Keyring" @@ -771,6 +1134,22 @@ msgid "Linux Vendor Firmware Service (testing firmware)" msgstr "Linux Vendor Firmware Service (testing firmware)" +#. TRANSLATORS: Title: if it's tainted or not +msgid "Linux kernel" +msgstr "Linux kernel" + +#. TRANSLATORS: Title: lockdown is a security mode of the kernel +msgid "Linux kernel lockdown" +msgstr "Linux kernel lockdown" + +#. TRANSLATORS: Title: swap space or swap partition +msgid "Linux swap" +msgstr "Linux swap" + +#. TRANSLATORS: command line option +msgid "List entries in dbx" +msgstr "List entries in dbx" + #. TRANSLATORS: command line option msgid "List supported firmware updates" msgstr "List supported firmware updates" @@ -779,13 +1158,43 @@ msgid "List the available firmware types" msgstr "List the available firmware types" +#. TRANSLATORS: command description +msgid "Lists files on the ESP" +msgstr "Lists files on the ESP" + #. TRANSLATORS: parsing the firmware information msgid "Loading…" msgstr "Loading…" -#. TRANSLATORS: command line option -msgid "Manually whitelist specific plugins" -msgstr "Manually whitelist specific plugins" +#. TRANSLATORS: Suffix: the HSI result +msgid "Locked" +msgstr "Locked" + +#. TRANSLATORS: the release urgency +msgid "Low" +msgstr "Low" + +#. TRANSLATORS: Title: MEI = Intel Management Engine +msgid "MEI manufacturing mode" +msgstr "MEI manufacturing mode" + +#. TRANSLATORS: Title: MEI = Intel Management Engine, and the +#. * "override" is the physical PIN that can be driven to +#. * logic high -- luckily it is probably not accessible to +#. * end users on consumer boards +msgid "MEI override" +msgstr "MEI override" + +msgid "MEI version" +msgstr "MEI version" + +#. TRANSLATORS: command line option +msgid "Manually enable specific plugins" +msgstr "Manually enable specific plugins" + +#. TRANSLATORS: the release urgency +msgid "Medium" +msgstr "Medium" #. TRANSLATORS: remote URI msgid "Metadata Signature" @@ -809,8 +1218,8 @@ msgstr "Mismatched daemon and client, use %s instead" #. TRANSLATORS: sets something in daemon.conf -msgid "Modifies a daemon configuration value." -msgstr "Modifies a daemon configuration value." +msgid "Modifies a daemon configuration value" +msgstr "Modifies a daemon configuration value" #. TRANSLATORS: command description msgid "Modifies a given remote" @@ -826,10 +1235,18 @@ msgid "Monitor the daemon for events" msgstr "Monitor the daemon for events" +#. TRANSLATORS: command description +msgid "Mounts the ESP" +msgstr "Mounts the ESP" + #. TRANSLATORS: Requires a reboot to apply firmware or to reload hardware msgid "Needs a reboot after installation" msgstr "Needs a reboot after installation" +#. TRANSLATORS: The update state of the specific device +msgid "Needs reboot" +msgstr "Needs reboot" + #. TRANSLATORS: Requires system shutdown to apply firmware msgid "Needs shutdown after installation" msgstr "Needs shutdown after installation" @@ -838,6 +1255,7 @@ msgid "New version" msgstr "New version" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "No action specified!" @@ -875,13 +1293,25 @@ msgid "No updates were applied" msgstr "No updates were applied" +#. TRANSLATORS: Suffix: the HSI result +msgid "Not found" +msgstr "Not found" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Not supported" +msgstr "Not supported" + +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "OK" + #. TRANSLATORS: command line option msgid "Only show single PCR value" msgstr "Only show single PCR value" #. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Override plugin warning" +msgid "Only use IPFS when downloading files" +msgstr "Only use IPFS when downloading files" #. TRANSLATORS: command line option msgid "Override the default ESP path" @@ -891,10 +1321,22 @@ msgid "Override warnings and force the action" msgstr "Override warnings and force the action" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "PATH" +msgstr "PATH" + #. TRANSLATORS: command description msgid "Parse and show details about a firmware file" msgstr "Parse and show details about a firmware file" +#. TRANSLATORS: reading new dbx from the update +msgid "Parsing dbx update…" +msgstr "Parsing dbx update…" + +#. TRANSLATORS: reading existing dbx from the system +msgid "Parsing system dbx…" +msgstr "Parsing system dbx…" + #. TRANSLATORS: remote filename base msgid "Password" msgstr "Password" @@ -902,6 +1344,10 @@ msgid "Payload" msgstr "Payload" +#. TRANSLATORS: The update state of the specific device +msgid "Pending" +msgstr "Pending" + #. TRANSLATORS: console message when not using plymouth msgid "Percentage complete" msgstr "Percentage complete" @@ -911,6 +1357,14 @@ msgid "Please enter a number from 0 to %u: " msgstr "Please enter a number from 0 to %u: " +#. TRANSLATORS: Failed to open plugin, hey Arch users +msgid "Plugin dependencies missing" +msgstr "Plugin dependencies missing" + +#. TRANSLATORS: Title: DMA as in https://en.wikipedia.org/wiki/DMA_attack +msgid "Pre-boot DMA protection" +msgstr "Pre-boot DMA protection" + #. TRANSLATORS: version number of previous firmware msgid "Previous version" msgstr "Previous version" @@ -936,6 +1390,14 @@ msgid "Query for firmware update support" msgstr "Query for firmware update support" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "REMOTE-ID" +msgstr "REMOTE-ID" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "REMOTE-ID KEY VALUE" +msgstr "REMOTE-ID KEY VALUE" + #. TRANSLATORS: command description msgid "Read a firmware blob from a device" msgstr "Read a firmware blob from a device" @@ -966,8 +1428,12 @@ msgstr "Refresh metadata from remote server" #. TRANSLATORS: command description -msgid "Reinstall current firmware on the device." -msgstr "Reinstall current firmware on the device." +msgid "Reinstall current firmware on the device" +msgstr "Reinstall current firmware on the device" + +#. TRANSLATORS: command description +msgid "Reinstall firmware on a device" +msgstr "Reinstall firmware on a device" #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second is a version number @@ -976,15 +1442,15 @@ msgid "Reinstalling %s with %s... " msgstr "Reinstalling %s with %s... " +#. TRANSLATORS: the stream of firmware, e.g. nonfree or open-source +msgid "Release Branch" +msgstr "Release Branch" + #. TRANSLATORS: the server the file is coming from #. TRANSLATORS: remote identifier, e.g. lvfs-testing msgid "Remote ID" msgstr "Remote ID" -#. TRANSLATORS: this is when a device is hotplugged -msgid "Removed" -msgstr "Removed" - #. TRANSLATORS: command description msgid "Replace data in an existing firmware file" msgstr "Replace data in an existing firmware file" @@ -997,9 +1463,13 @@ msgid "Reported to remote server" msgstr "Reported to remote server" -#. TRANSLATORS: Must be plugged in to an outlet -msgid "Requires AC power" -msgstr "Requires AC power" +#. TRANSLATORS: the user is using Gentoo/Arch and has screwed something up +msgid "Required efivarfs filesystem was not found" +msgstr "Required efivarfs filesystem was not found" + +#. TRANSLATORS: not required for this system +msgid "Required hardware was not found" +msgstr "Required hardware was not found" #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user msgid "Requires a bootloader" @@ -1025,6 +1495,9 @@ msgid "Return all the hardware IDs for the machine" msgstr "Return all the hardware IDs for the machine" +msgid "Run `fwupdmgr get-upgrades` for more information." +msgstr "Run `fwupdmgr get-upgrades` for more information." + #. TRANSLATORS: command line option msgid "Run the plugin composite cleanup routine when using install-blob" msgstr "Run the plugin composite cleanup routine when using install-blob" @@ -1033,6 +1506,30 @@ msgid "Run the plugin composite prepare routine when using install-blob" msgstr "Run the plugin composite prepare routine when using install-blob" +#. TRANSLATORS: this is the HSI suffix +msgid "Runtime Suffix" +msgstr "Runtime Suffix" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI BIOS region" +msgstr "SPI BIOS region" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI lock" +msgstr "SPI lock" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI write" +msgstr "SPI write" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "SUBSYSTEM DRIVER [DEVICE-ID|GUID]" +msgstr "SUBSYSTEM DRIVER [DEVICE-ID|GUID]" + +#. TRANSLATORS: command description +msgid "Save a file that allows generation of hardware IDs" +msgstr "Save a file that allows generation of hardware IDs" + #. TRANSLATORS: command line option msgid "Save device state into a JSON file between executions" msgstr "Save device state into a JSON file between executions" @@ -1045,10 +1542,19 @@ msgid "Scheduling…" msgstr "Scheduling…" +#. TRANSLATORS: %s is a link to a website +#, c-format +msgid "See %s for more information." +msgstr "See %s for more information." + #. TRANSLATORS: Device has been chosen by the daemon for the user msgid "Selected device" msgstr "Selected device" +#. TRANSLATORS: Volume has been chosen by the user +msgid "Selected volume" +msgstr "Selected volume" + #. TRANSLATORS: serial number of hardware msgid "Serial Number" msgstr "Serial Number" @@ -1057,18 +1563,19 @@ msgid "Set the debugging flag during update" msgstr "Set the debugging flag during update" +#. TRANSLATORS: firmware approved by the admin msgid "Sets the list of approved firmware" msgstr "Sets the list of approved firmware" -#. TRANSLATORS: firmware approved by the admin -msgid "Sets the list of approved firmware." -msgstr "Sets the list of approved firmware." - #. TRANSLATORS: command description msgid "Share firmware history with the developers" msgstr "Share firmware history with the developers" #. TRANSLATORS: command line option +msgid "Show all results" +msgstr "Show all results" + +#. TRANSLATORS: command line option msgid "Show client and daemon versions" msgstr "Show client and daemon versions" @@ -1101,6 +1608,10 @@ msgstr "Show plugin verbose information" #. TRANSLATORS: command line option +msgid "Show the calculated version of the dbx" +msgstr "Show the calculated version of the dbx" + +#. TRANSLATORS: command line option msgid "Show the debug log from the last attempted update" msgstr "Show the debug log from the last attempted update" @@ -1137,9 +1648,17 @@ msgid "Specify Vendor/Product ID(s) of DFU device" msgstr "Specify Vendor/Product ID(s) of DFU device" +#. TRANSLATORS: command line option +msgid "Specify the dbx database file" +msgstr "Specify the dbx database file" + msgid "Specify the number of bytes per USB transfer" msgstr "Specify the number of bytes per USB transfer" +#. TRANSLATORS: The update state of the specific device +msgid "Success" +msgstr "Success" + #. TRANSLATORS: success message -- where activation is making the new #. * firmware take effect, usually after updating offline msgid "Successfully activated all devices" @@ -1194,10 +1713,46 @@ msgid "Summary" msgstr "Summary" +#. TRANSLATORS: Suffix: the HSI result +msgid "Supported" +msgstr "Supported" + #. TRANSLATORS: Is found in current metadata msgid "Supported on remote server" msgstr "Supported on remote server" +#. TRANSLATORS: Title: a better sleep state +msgid "Suspend-to-idle" +msgstr "Suspend-to-idle" + +#. TRANSLATORS: Title: sleep state +msgid "Suspend-to-ram" +msgstr "Suspend-to-ram" + +#. TRANSLATORS: command description +msgid "Switch the firmware branch on the device" +msgstr "Switch the firmware branch on the device" + +#. TRANSLATORS: Must be plugged in to an outlet +msgid "System requires external power source" +msgstr "System requires external power source" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "TEXT" +msgstr "TEXT" + +#. TRANSLATORS: Title: the PCR is rebuilt from the TPM event log +msgid "TPM PCR0 reconstruction" +msgstr "TPM PCR0 reconstruction" + +#. TRANSLATORS: Title: TPM = Trusted Platform Module +msgid "TPM v2.0" +msgstr "TPM v2.0" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Tainted" +msgstr "Tainted" + msgid "Target" msgstr "Target" @@ -1205,11 +1760,36 @@ msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." +#. TRANSLATORS: this is more background on a security measurement problem +msgid "The TPM PCR0 differs from reconstruction." +msgstr "The TPM PCR0 differs from reconstruction." + +#. TRANSLATORS: the user is SOL for support... +msgid "The daemon has loaded 3rd party code and is no longer supported by the upstream developers!" +msgstr "The daemon has loaded 3rd party code and is no longer supported by the upstream developers!" + +#. TRANSLATORS: %1 is the firmware vendor, %2 is the device vendor name +#, c-format +msgid "The firmware from %s is not supplied by %s, the hardware vendor." +msgstr "The firmware from %s is not supplied by %s, the hardware vendor." + +#. TRANSLATORS: try to help +msgid "The system clock has not been set correctly and downloading files may fail." +msgstr "The system clock has not been set correctly and downloading files may fail." + +#. TRANSLATORS: nothing to show +msgid "There are no blocked firmware files" +msgstr "There are no blocked firmware files" + #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator msgid "There is no approved firmware." msgstr "There is no approved firmware." +#. TRANSLATORS: unsupported build of the package +msgid "This package has not been validated, it may not work properly." +msgstr "This package has not been validated, it may not work properly." + #. TRANSLATORS: we're poking around as a power user msgid "This program may only work correctly as root" msgstr "This program may only work correctly as root" @@ -1217,18 +1797,98 @@ msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." +#. TRANSLATORS: this is instructions on how to improve the HSI suffix +msgid "This system has HSI runtime issues." +msgstr "This system has HSI runtime issues." + +#. TRANSLATORS: this is instructions on how to improve the HSI security level +msgid "This system has a low HSI security level." +msgstr "This system has a low HSI security level." + +#. TRANSLATORS: description of dbxtool +msgid "This tool allows an administrator to apply UEFI dbx updates." +msgstr "This tool allows an administrator to apply UEFI dbx updates." + +#. TRANSLATORS: CLI description +msgid "This tool allows an administrator to debug UpdateCapsule operation." +msgstr "This tool allows an administrator to debug UpdateCapsule operation." + +#. TRANSLATORS: CLI description +msgid "This tool allows an administrator to query and control the fwupd daemon, allowing them to perform actions such as installing or downgrading firmware." +msgstr "This tool allows an administrator to query and control the fwupd daemon, allowing them to perform actions such as installing or downgrading firmware." + +#. TRANSLATORS: CLI description +msgid "This tool allows an administrator to use the fwupd plugins without being installed on the host system." +msgstr "This tool allows an administrator to use the fwupd plugins without being installed on the host system." + +#. TRANSLATORS: CLI description +msgid "This tool can be used from other tools and from shell scripts." +msgstr "This tool can be used from other tools and from shell scripts." + #. TRANSLATORS: the user needs to stop playing with stuff msgid "This tool can only be used by the root user" msgstr "This tool can only be used by the root user" +#. TRANSLATORS: CLI description +msgid "This tool will read and parse the TPM event log from the system firmware." +msgstr "This tool will read and parse the TPM event log from the system firmware." + +#. TRANSLATORS: command line option +msgid "Timeout in milliseconds for each parse" +msgstr "Timeout in milliseconds for each parse" + +#. TRANSLATORS: The update state of the specific device +msgid "Transient failure" +msgstr "Transient failure" + #. TRANSLATORS: remote type, e.g. remote or local msgid "Type" msgstr "Type" +#. TRANSLATORS: partition refers to something on disk, again, hey Arch users +msgid "UEFI ESP partition not detected or configured" +msgstr "UEFI ESP partition not detected or configured" + #. TRANSLATORS: program name msgid "UEFI Firmware Utility" msgstr "UEFI Firmware Utility" +#. TRANSLATORS: capsule updates are an optional BIOS feature +msgid "UEFI capsule updates not available or enabled in firmware setup" +msgstr "UEFI capsule updates not available or enabled in firmware setup" + +#. TRANSLATORS: program name +msgid "UEFI dbx Utility" +msgstr "UEFI dbx Utility" + +#. TRANSLATORS: Title: PK is the 'platform key' for the machine +msgid "UEFI platform key" +msgstr "UEFI platform key" + +#. TRANSLATORS: Title: SB is a way of locking down UEFI +msgid "UEFI secure boot" +msgstr "UEFI secure boot" + +#. TRANSLATORS: error message +msgid "Unable to connect to service" +msgstr "Unable to connect to service" + +#. TRANSLATORS: command description +msgid "Unbind current driver" +msgstr "Unbind current driver" + +#. TRANSLATORS: we will now offer this firmware to the user +msgid "Unblocking firmware:" +msgstr "Unblocking firmware:" + +#. TRANSLATORS: command description +msgid "Unblocks a specific firmware from being installed" +msgstr "Unblocks a specific firmware from being installed" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Unencrypted" +msgstr "Unencrypted" + #. TRANSLATORS: current daemon status is unknown #. TRANSLATORS: we don't know the license of the update #. TRANSLATORS: unknown release urgency @@ -1242,10 +1902,18 @@ msgid "Unlock the device to allow access" msgstr "Unlock the device to allow access" +#. TRANSLATORS: Suffix: the HSI result +msgid "Unlocked" +msgstr "Unlocked" + #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "Unlocks the device for firmware access" +#. TRANSLATORS: command description +msgid "Unmounts the ESP" +msgstr "Unmounts the ESP" + #. TRANSLATORS: command line option msgid "Unset the debugging flag during update" msgstr "Unset the debugging flag during update" @@ -1255,6 +1923,10 @@ msgid "Unsupported daemon version %s, client version is %s" msgstr "Unsupported daemon version %s, client version is %s" +#. TRANSLATORS: Suffix: the HSI result +msgid "Untainted" +msgstr "Untainted" + #. TRANSLATORS: Device is updatable in this or any other mode msgid "Updatable" msgstr "Updatable" @@ -1303,6 +1975,9 @@ msgid "Updates all firmware to latest versions available" msgstr "Updates all firmware to latest versions available" +msgid "Updating" +msgstr "Updating" + #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second and third are #. * version numbers e.g. "1.2.3" @@ -1321,10 +1996,6 @@ msgid "Upgrade available for %s from %s to %s" msgstr "Upgrade available for %s from %s to %s" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Upload message:" - msgid "Upload report just this one time, but prompt again for future updates" msgid_plural "Upload reports just this one time, but prompt again for future updates" msgstr[0] "Upload report just this one time, but prompt again for future updates" @@ -1343,6 +2014,18 @@ msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." msgstr "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." +#. TRANSLATORS: how important the release is +msgid "Urgency" +msgstr "Urgency" + +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdmgr --help for help" +msgstr "Use fwupdmgr --help for help" + +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdtool --help for help" +msgstr "Use fwupdtool --help for help" + #. TRANSLATORS: command line option msgid "Use quirk flags when installing firmware" msgstr "Use quirk flags when installing firmware" @@ -1355,6 +2038,17 @@ msgid "Username" msgstr "Username" +msgid "VID:PID" +msgstr "VID:PID" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Valid" +msgstr "Valid" + +#. TRANSLATORS: ESP refers to the EFI System Partition +msgid "Validating ESP contents…" +msgstr "Validating ESP contents…" + #. TRANSLATORS: one line variant of release (e.g. 'Prerelease' or 'China') msgid "Variant" msgstr "Variant" @@ -1367,19 +2061,19 @@ msgid "Verifying…" msgstr "Verifying…" -#. TRANSLATORS: try to help -msgid "WARNING: Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" -msgstr "WARNING: Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Version" + +#. TRANSLATORS: this is a prefix on the console +msgid "WARNING:" +msgstr "WARNING:" #. TRANSLATORS: waiting for device to do something msgid "Waiting…" msgstr "Waiting…" #. TRANSLATORS: command description -msgid "Watch DFU devices being hotplugged" -msgstr "Watch DFU devices being hotplugged" - -#. TRANSLATORS: command description msgid "Watch for hardware changes" msgstr "Watch for hardware changes" @@ -1391,6 +2085,10 @@ msgid "Write firmware from file into one partition" msgstr "Write firmware from file into one partition" +#. TRANSLATORS: decompressing images from a container firmware +msgid "Writing file:" +msgstr "Writing file:" + #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Writing…" @@ -1398,3 +2096,40 @@ #. TRANSLATORS: show the user a warning msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." + +#. TRANSLATORS: %1 is the device vendor name +#, c-format +msgid "Your hardware may be damaged using this firmware, and installing this release may void any warranty with %s." +msgstr "Your hardware may be damaged using this firmware, and installing this release may void any warranty with %s." + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "[CHECKSUM]" +msgstr "[CHECKSUM]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "[DEVICE-ID|GUID]" +msgstr "[DEVICE-ID|GUID]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "[DEVICE-ID|GUID] [BRANCH]" +msgstr "[DEVICE-ID|GUID] [BRANCH]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "[FILE FILE_SIG REMOTE-ID]" +msgstr "[FILE FILE_SIG REMOTE-ID]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "[SMBIOS-FILE|HWIDS-FILE]" +msgstr "[SMBIOS-FILE|HWIDS-FILE]" + +#. TRANSLATORS: this is the default branch name when unset +msgid "default" +msgstr "default" + +#. TRANSLATORS: program name +msgid "fwupd TPM event log utility" +msgstr "fwupd TPM event log utility" + +#. TRANSLATORS: Title: if the fwupd plugins are all present and correct +msgid "fwupd plugins" +msgstr "fwupd plugins" diff -Nru fwupd-1.4.5/po/fi.po fwupd-1.5.8/po/fi.po --- fwupd-1.4.5/po/fi.po 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/po/fi.po 2021-03-31 20:08:32.000000000 +0000 @@ -3,8 +3,8 @@ # This file is distributed under the same license as the fwupd package. # # Translators: -# Jiri Grönroos , 2017-2018 -# Kimmo Kujansuu , 2019-2020 +# Jiri Grönroos , 2017-2018,2020 +# Kimmo Kujansuu , 2019-2021 msgid "" msgstr "" "Project-Id-Version: fwupd\n" @@ -20,64 +20,70 @@ #, c-format msgid "%.0f minute remaining" msgid_plural "%.0f minutes remaining" -msgstr[0] "%.0f minuuttia jäljellä" +msgstr[0] "%.0f minuutti jäljellä" msgstr[1] "%.0f minuuttia jäljellä" #. TRANSLATORS: the CPU microcode is firmware loaded onto the CPU #. * at system bootup #, c-format msgid "%s CPU Microcode Update" -msgstr "%s CPU Microcode päivitys" +msgstr "Laitteen %s suorittimen mikrokoodipäivitys" + +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Secure Boot` +#, c-format +msgid "%s Configuration Update" +msgstr "%s kokoonpanon päivitys" #. TRANSLATORS: ME stands for Management Engine, where #. * the first %s is the device name, e.g. 'ThinkPad P50` #, c-format msgid "%s Consumer ME Update" -msgstr "%sKuluttajan ME-päivitys" +msgstr "Laitteen %s kuluttajan ME-päivitys" #. TRANSLATORS: the controller is a device that has other devices #. * plugged into it, for example ThunderBolt, FireWire or USB, #. * the first %s is the device name, e.g. 'Intel ThunderBolt` #, c-format msgid "%s Controller Update" -msgstr "%sOhjaimen päivitys" +msgstr "Laitten %s ohjaimen päivitys" #. TRANSLATORS: ME stands for Management Engine (with Intel AMT), #. * where the first %s is the device name, e.g. 'ThinkPad P50` #, c-format msgid "%s Corporate ME Update" -msgstr "%sYrityksen ME-päivitys" +msgstr "Laitteen %s yrityksen ME-päivitys" #. TRANSLATORS: a specific part of hardware, #. * the first %s is the device name, e.g. 'Unifying Receiver` #, c-format msgid "%s Device Update" -msgstr "%sLaitteen päivitys" +msgstr "Laitteen %s laitepäivitys" #. TRANSLATORS: the EC is typically the keyboard controller chip, #. * the first %s is the device name, e.g. 'ThinkPad P50` #, c-format msgid "%s Embedded Controller Update" -msgstr "%sSulautetun ohjaimen päivitys" +msgstr "Laitteen %s sulautetun ohjaimen päivitys" #. TRANSLATORS: ME stands for Management Engine, the Intel AMT thing, #. * the first %s is the device name, e.g. 'ThinkPad P50` #, c-format msgid "%s ME Update" -msgstr "%sME päivitys" +msgstr "Laitteen %s ME-päivitys" #. TRANSLATORS: the entire system, e.g. all internal devices, #. * the first %s is the device name, e.g. 'ThinkPad P50` #, c-format msgid "%s System Update" -msgstr "%sJärjestelmän päivitys" +msgstr "Laitteen %s järjestelmäpäivitys" #. TRANSLATORS: the Thunderbolt controller is a device that #. * has other high speed Thunderbolt devices plugged into it; #. * the first %s is the system name, e.g. 'ThinkPad P50` #, c-format msgid "%s Thunderbolt Controller Update" -msgstr "%s Thunderbolt-ohjaimen päivitys" +msgstr "Laitteen %s Thunderbolt-ohjaimen päivitys" #. TRANSLATORS: this is the fallback where we don't know if the release #. * is updating the system, the device, or a device class, or something else @@ -85,13 +91,18 @@ #. * the first %s is the device name, e.g. 'ThinkPad P50` #, c-format msgid "%s Update" -msgstr "%sPäivitys" +msgstr "Laitteen %s päivitys" #. TRANSLATORS: warn the user before updating, %1 is a device name #, c-format msgid "%s and all connected devices may not be usable while updating." msgstr "%s ja kaikki kytketyt laitteet eivät välttämättä ole käyttökelpoisia päivityksen aikana." +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s manufacturing mode" +msgstr "%s tuotantotekniikka" + #. TRANSLATORS: warn the user before updating, %1 is a device name #, c-format msgid "%s must remain connected for the duration of the update to avoid damage." @@ -102,12 +113,27 @@ msgid "%s must remain plugged into a power source for the duration of the update to avoid damage." msgstr "%s on oltava kytkettynä virtalähteeseen päivityksen ajaksi vaurioiden välttämiseksi." +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s override" +msgstr "%s ohita" + +#. TRANSLATORS: Title: %1 is ME kind, e.g. CSME/TXT, %2 is a version number +#, c-format +msgid "%s v%s" +msgstr "%s v%s" + +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s version" +msgstr "%s versio" + #. TRANSLATORS: duration in days! #, c-format msgid "%u day" msgid_plural "%u days" -msgstr[0] "%upäivää" -msgstr[1] "%upäivää" +msgstr[0] "%u päivä" +msgstr[1] "%u päivää" #, c-format msgid "%u device has a firmware upgrade available." @@ -119,8 +145,8 @@ #, c-format msgid "%u hour" msgid_plural "%u hours" -msgstr[0] "%u tuntia" -msgstr[1] "%utuntia" +msgstr[0] "%u tunti" +msgstr[1] "%u tuntia" #. TRANSLATORS: how many local devices can expect updates now #, c-format @@ -133,15 +159,19 @@ #, c-format msgid "%u minute" msgid_plural "%u minutes" -msgstr[0] "%u minuuttia" +msgstr[0] "%u minuutti" msgstr[1] "%u minuuttia" #. TRANSLATORS: duration in seconds #, c-format msgid "%u second" msgid_plural "%u seconds" -msgstr[0] "%u " -msgstr[1] "%u sekunttia" +msgstr[0] "%u sekunti" +msgstr[1] "%u sekuntia" + +#. TRANSLATORS: this is shown as a suffix for obsoleted tests +msgid "(obsoleted)" +msgstr "(vanhentunut)" #. TRANSLATORS: command description msgid "Activate devices" @@ -162,10 +192,6 @@ msgid "Activating firmware update for" msgstr "Käynnistä laiteohjelmiston päivitys" -#. TRANSLATORS: this is when a device is hotplugged -msgid "Added" -msgstr "Lisätty" - #. TRANSLATORS: the age of the metadata msgid "Age" msgstr "Ikä" @@ -187,6 +213,10 @@ msgid "Allow reinstalling existing firmware versions" msgstr "Salli laiteohjelmiston versioiden asentaminen uudelleen" +#. TRANSLATORS: command line option +msgid "Allow switching firmware branch" +msgstr "Salli vaihtaa laiteohjelmiston haara" + #. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Päivitys vaatii uudelleenkäynnistyksen." @@ -201,7 +231,19 @@ #. TRANSLATORS: command line option msgid "Apply firmware updates" -msgstr "Käytä firmware-päivityksiä" +msgstr "Toteuta firmware-päivitykset" + +#. TRANSLATORS: command line option +msgid "Apply update even when not advised" +msgstr "Käytä päivitystä myös silloin, kun sitä ei suositella" + +#. TRANSLATORS: command line option +msgid "Apply update files" +msgstr "Käytä päivitystiedostoja" + +#. TRANSLATORS: actually sending the update to the hardware +msgid "Applying update…" +msgstr "Sovelletaan päivitystä..." #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator @@ -210,6 +252,10 @@ msgstr[0] "Hyväksytty laiteohjelmisto:" msgstr[1] "Hyväksytty laiteohjelmisto:" +#. TRANSLATORS: stop nagging the user +msgid "Ask again next time?" +msgstr "Kysy uudestaan ensi kerralla?" + #. TRANSLATORS: command description msgid "Attach to firmware mode" msgstr "Kiinnitä laiteohjelmistotilaan" @@ -224,7 +270,7 @@ #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "Todennus on tarpeen tämän laitteen firmwaren alentamiseksi" +msgstr "Tunnistautuminen vaaditaan tämän laitteen laiteohjelmiston version alentamiseksi" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to modify a configured remote used for firmware updates" @@ -232,7 +278,7 @@ #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to modify daemon configuration" -msgstr "Todennusta tarvitaan taustaprosessin asetusten muokkaamiseen" +msgstr "Tunnistautuminen vaaditaan taustaprosessin asetusten muokkaamiseksi" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to set the list of approved firmware" @@ -266,14 +312,53 @@ msgid "Automatic Reporting" msgstr "Automaattinen raportointi" +#. TRANSLATORS: can we JFDI? +msgid "Automatically upload every time?" +msgstr "Ladataan automaattisesti joka kerta?" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "BUILDER-XML FILENAME-DST" +msgstr "BUILDER-XML FILENAME-DST" + +msgid "BYTES" +msgstr "BYTES" + +#. TRANSLATORS: command description +msgid "Bind new kernel driver" +msgstr "Kytke uusi laiteohjain" + +#. TRANSLATORS: there follows a list of hashes +msgid "Blocked firmware files:" +msgstr "Estetyt laiteohjelmiston tiedostot:" + +#. TRANSLATORS: we will not offer this firmware to the user +msgid "Blocking firmware:" +msgstr "Laiteohjelmiston estäminen:" + +#. TRANSLATORS: command description +msgid "Blocks a specific firmware from being installed" +msgstr "Estää tietyn laiteohjelmiston asentamisen" + #. TRANSLATORS: firmware version of bootloader msgid "Bootloader Version" msgstr "Käynnistyslataimen versio" +#. TRANSLATORS: the stream of firmware, e.g. nonfree or open-source +msgid "Branch" +msgstr "Haara" + +#. TRANSLATORS: command description +msgid "Build a firmware file" +msgstr "Luo laiteohjelmiston tiedosto" + #. TRANSLATORS: command description msgid "Build firmware using a sandbox" msgstr "Rakenna laiteohjelmisto hiekkalaatikon avulla" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "CHECKSUM1[,CHECKSUM2][,CHECKSUM3]" +msgstr "CHECKSUM1[,CHECKSUM2][,CHECKSUM3]" + #. TRANSLATORS: this is to abort the interactive prompt msgid "Cancel" msgstr "Peru" @@ -282,7 +367,14 @@ msgid "Cancelled" msgstr "Peruttu" -#. TRANSLATORS: this is when a device is hotplugged +#. TRANSLATORS: same or newer update already applied +msgid "Cannot apply as dbx update has already been applied." +msgstr "Ei voida käyttää, koska dbx-päivitys on jo asennettu." + +#. TRANSLATORS: the user is using a LiveCD or LiveUSB install disk +msgid "Cannot apply updates on live media" +msgstr "Päivityksiä ei voi käyttää asennus-mediassa" + #. TRANSLATORS: this is when the daemon state changes msgid "Changed" msgstr "Muutettu" @@ -295,6 +387,11 @@ msgid "Checksum" msgstr "Tarkistussumma" +#. TRANSLATORS: get interactive prompt, where branch is the +#. * supplier of the firmware, e.g. "non-free" or "free" +msgid "Choose a branch:" +msgstr "Valitse haara:" + #. TRANSLATORS: get interactive prompt msgid "Choose a device:" msgstr "Valitse laite:" @@ -307,6 +404,10 @@ msgid "Choose a release:" msgstr "Valitse julkaisu:" +#. TRANSLATORS: get interactive prompt +msgid "Choose a volume:" +msgstr "Valitse asema:" + #. TRANSLATORS: command description msgid "Clears any updates scheduled to be updated offline" msgstr "Tyhjentää päivitykset, jotka on tarkoitus päivittää offline-tilassa" @@ -343,6 +444,10 @@ msgid "Current version" msgstr "Nykyinen versio" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "DEVICE-ID|GUID" +msgstr "DEVICE-ID|GUID" + #. TRANSLATORS: DFU stands for device firmware update msgid "DFU Utility" msgstr "DFU-apuohjelma" @@ -411,10 +516,18 @@ msgid "Device stages updates" msgstr "Laitevyöhykkeen päivitykset" +#. TRANSLATORS: there is more than one supplier of the firmware +msgid "Device supports switching to a different branch of firmware" +msgstr "Laite tukee vaihtamista toiseen laiteohjelmiston haaraan" + #. TRANSLATORS: Device update needs to be separately activated msgid "Device update needs activation" msgstr "Laitteen päivitys tarvitsee aktivointia" +#. TRANSLATORS: save the old firmware to disk before installing the new one +msgid "Device will backup firmware before installing" +msgstr "Laite varmuuskopioi laiteohjelmiston ennen asennusta" + #. TRANSLATORS: Device will not return after update completes msgid "Device will not re-appear after update completes" msgstr "Laitetta ei näytetä uudelleen päivityksen päätyttyä" @@ -427,6 +540,20 @@ msgid "Devices that were not updated correctly:" msgstr "Laitteet, joita ei päivitetty oikein:" +#. TRANSLATORS: message letting the user know no device upgrade available due +#. to missing on LVFS +msgid "Devices with no available firmware updates: " +msgstr "Laitteet, joista ei ole saatavilla firmware-päivityksiä:" + +#. TRANSLATORS: message letting the user know no device upgrade available +msgid "Devices with the latest available firmware version:" +msgstr "Laitteet, joista on saatavilla uusin firmware-versio:" + +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is inactive and not used +msgid "Disabled" +msgstr "Ei käytössä" + msgid "Disabled fwupdate debugging" msgstr "fw-päivityksen virheenkorjaus poistettu" @@ -450,6 +577,10 @@ msgid "Do not check for unreported history" msgstr "Älä tarkista ilmoittamattomasta historiasta" +#. TRANSLATORS: command line option +msgid "Do not check if download remotes should be enabled" +msgstr "Älä tarkista, kannattaako etänä lataus ottaa käyttöön" + #. TRANSLATORS: turn on all debugging msgid "Do not include log domain prefix" msgstr "Älä sisällytä lokiin toimialueen etuliitettä" @@ -476,6 +607,11 @@ msgid "Do not write to the history database" msgstr "Älä kirjoita historiatietokantaan" +#. TRANSLATORS: should the branch be changed +msgid "Do you understand the consequences of changing the firmware branch?" +msgstr "Ymmärrätkö laiteohjelmiston haaran vaihtamisen seuraukset?" + +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Valmis!" @@ -494,7 +630,7 @@ #. TRANSLATORS: %1 is a device name #, c-format msgid "Downgrading %s…" -msgstr "Alentaa %s…" +msgstr "Alennetaan laitetta %s…" #. TRANSLATORS: downloading from a remote server msgid "Downloading…" @@ -520,6 +656,8 @@ msgid "Enable this remote?" msgstr "Ota etäyhteys käyttöön?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Käytössä" @@ -538,6 +676,14 @@ msgid "Enabling this remote is done at your own risk." msgstr "Tämän etä-ohjaimen käyttöönotto tapahtuu omalla vastuullasi." +#. TRANSLATORS: Suffix: the HSI result +msgid "Encrypted" +msgstr "Salattu" + +#. TRANSLATORS: Title: Memory contents are encrypted, e.g. Intel TME +msgid "Encrypted RAM" +msgstr "Salattu RAM-muisti" + #. TRANSLATORS: command description msgid "Erase all firmware update history" msgstr "Poista kaikki laiteohjelmiston päivityshistoria" @@ -554,61 +700,112 @@ msgid "Exit after the engine has loaded" msgstr "Poistu kun moottori on ladattu" +#. TRANSLATORS: command description +msgid "Extract a firmware blob to images" +msgstr "Laiteohjelmiston blob purkaminen kuvaksi " + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILE" +msgstr "FILE" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILE [DEVICE-ID|GUID]" +msgstr "FILE [DEVICE-ID|GUID]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILE-IN FILE-OUT [SCRIPT] [OUTPUT]" +msgstr "FILE-IN FILE-OUT [SCRIPT] [OUTPUT]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME" +msgstr "FILENAME" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME DEVICE-ALT-NAME|DEVICE-ALT-ID" +msgstr "FILENAME DEVICE-ALT-NAME|DEVICE-ALT-ID" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME DEVICE-ALT-NAME|DEVICE-ALT-ID [IMAGE-ALT-NAME|IMAGE-ALT-ID]" +msgstr "FILENAME DEVICE-ALT-NAME|DEVICE-ALT-ID [IMAGE-ALT-NAME|IMAGE-ALT-ID]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME DEVICE-ID" +msgstr "FILENAME DEVICE-ID" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME [DEVICE-ID|GUID]" +msgstr "FILENAME [DEVICE-ID|GUID]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME [FIRMWARE-TYPE]" +msgstr "FILENAME [FIRMWARE-TYPE]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME-SRC FILENAME-DST [FIRMWARE-TYPE-SRC] [FIRMWARE-TYPE-DST]" +msgstr "FILENAME-SRC FILENAME-DST [FIRMWARE-TYPE-SRC] [FIRMWARE-TYPE-DST]" + +#. TRANSLATORS: Suffix: the fallback HSI result +#. TRANSLATORS: The update state of the specific device +msgid "Failed" +msgstr "Epäonnistui" + +#. TRANSLATORS: dbx file failed to be applied as an update +msgid "Failed to apply update" +msgstr "Päivityksen asentaminen epäonnistui" + #. TRANSLATORS: we could not talk to the fwupd daemon msgid "Failed to connect to daemon" msgstr "Yhteys taustaprosessiin epäonnistui" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "Lataaminen epäonnistui palvelimen rajoituksen vuoksi" - #. TRANSLATORS: we could not get the devices to update offline msgid "Failed to get pending devices" msgstr "Vireillä olevien laitteiden saaminen epäonnistui" #. TRANSLATORS: we could not install for some reason msgid "Failed to install firmware update" -msgstr "Laiteohjelmiston firmware päivityksen asennus epäonnistui" +msgstr "Laiteohjelmiston päivityksen asennus epäonnistui" + +#. TRANSLATORS: could not read existing system data +#. TRANSLATORS: could not read file +msgid "Failed to load local dbx" +msgstr "Paikallisen dbx-tiedoston lataus epäonnistui" #. TRANSLATORS: quirks are device-specific workarounds msgid "Failed to load quirks" msgstr "Quirksin lataaminen epäonnistui" +#. TRANSLATORS: could not read existing system data +msgid "Failed to load system dbx" +msgstr "Järjestelmän dbx-tiedoston lataus epäonnistui" + #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Argumenttien jäsentäminen epäonnistui" #. TRANSLATORS: failed to read measurements file msgid "Failed to parse file" -msgstr "Tiedoston käsittely epäonnistui" +msgstr "Tiedoston jäsentäminen epäonnistui" #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse flags for --filter" msgstr "Lippujen erittely ei onnistunut --suodatin" +#. TRANSLATORS: could not parse file +msgid "Failed to parse local dbx" +msgstr "Paikallisen dbx-tiedoston lukeminen epäonnistui" + #. TRANSLATORS: we could not reboot for some reason msgid "Failed to reboot" -msgstr "Käynnistys epäonnistui" +msgstr "Uudelleenkäynnistys epäonnistui" #. TRANSLATORS: we could not talk to plymouth msgid "Failed to set splash mode" msgstr "Splash-tilan asettaminen epäonnistui" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "Noudetaan tiedosto" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "Noudetaan firmware" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "Noudetaan metatietoja" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "Noudetaan allekirjoitus" +#. TRANSLATORS: something with a blocked hash exists +#. * in the users ESP -- which would be bad! +msgid "Failed to validate ESP contents" +msgstr "ESP-sisällön vahvistaminen epäonnistui" #. TRANSLATORS: filename of the local file msgid "Filename" @@ -618,6 +815,10 @@ msgid "Filename Signature" msgstr "Tiedoston allekirjoitus" +#. TRANSLATORS: user did not include a filename parameter +msgid "Filename required" +msgstr "Tiedostonimi vaaditaan" + #. TRANSLATORS: command line option msgid "Filter with a set of device flags using a ~ prefix to exclude, e.g. 'internal,~needs-reboot'" msgstr "Suodata laite lippuja käyttäen ~ etuliiteellä sulkea pois, esim. 'sisäiset, ~ vaatii käynnistyksen'" @@ -642,6 +843,22 @@ msgid "Firmware Utility" msgstr "Firmware-työkalu" +#. TRANSLATORS: Title: if we can verify the firmware checksums +msgid "Firmware attestation" +msgstr "Firmware-aitoustodistus" + +#. TRANSLATORS: system is not booted in UEFI mode +msgid "Firmware can not be updated in legacy BIOS mode" +msgstr "Laiteohjelmistoa ei voi päivittää legacy BIOS-tilassa" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is already blocked" +msgstr "Laiteohjelmisto on jo estetty" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is not already blocked" +msgstr "Laiteohjelmistoa ei ole jo estetty" + #. TRANSLATORS: the metadata is very out of date; %u is a number > 1 #, c-format msgid "Firmware metadata has not been updated for %u day and may not be up to date." @@ -649,25 +866,47 @@ msgstr[0] "Laiteohjelmiston metatietoja ei ole päivitetty %upäivään ja ne eivät välttämättä ole ajan tasalla." msgstr[1] "Laiteohjelmiston metatietoja ei ole päivitetty %upäivään ja ne eivät välttämättä ole ajan tasalla." +#. TRANSLATORS: Title: if firmware updates are available +msgid "Firmware updates" +msgstr "Firmware-päivitykset" + msgid "Firmware updates are not supported on this machine." msgstr "Ohjelmistopäivitys 'firmware' ei tue tätä laitetta" msgid "Firmware updates are supported on this machine." msgstr "Ohjelmistopäivitys 'firmware' tukee tätä laitetta" +#. TRANSLATORS: user needs to run a command +msgid "Firmware updates disabled; run 'fwupdmgr unlock' to enable" +msgstr "Laiteohjelmiston päivitykset poistettu käytöstä; suorita 'fwupdmgr unlock' ottaaksesi käyttöön" + +#. TRANSLATORS: description of plugin state, e.g. disabled #. TRANSLATORS: release properties msgid "Flags" msgstr "Liput" +#. TRANSLATORS: command line option +msgid "Force the action by relaxing some runtime checks" +msgstr "Pakota toiminta vapauttamalla joitakin ajonaikaisia tarkistuksia" + msgid "Force the action ignoring all warnings" msgstr "Pakota toimenpide huomioimatta kaikki varoitukset" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Löydetty" + #. TRANSLATORS: global ID common to all similar hardware msgid "GUID" msgid_plural "GUIDs" msgstr[0] "GUIDs" msgstr[1] "GUIDs" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgctxt "A single GUID" +msgid "GUID" +msgstr "GUID" + #. TRANSLATORS: command description msgid "Get all device flags supported by fwupd" msgstr "Hanki kaikki fwupd -tukemat laiteliput" @@ -692,9 +931,17 @@ msgid "Gets the configured remotes" msgstr "Määrittää konfiguroidut etäyhteydet" +#. TRANSLATORS: command description +msgid "Gets the host security attributes" +msgstr "Hanki tietoturvan määritteet" + #. TRANSLATORS: firmware approved by the admin -msgid "Gets the list of approved firmware." -msgstr "Hae hyväksytty laiteohjelmiston luettelo." +msgid "Gets the list of approved firmware" +msgstr "Hae hyväksytty laiteohjelmiston luettelo" + +#. TRANSLATORS: command description +msgid "Gets the list of blocked firmware" +msgstr "Hakee estettyjen laiteohjelmistojen luettelon" #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" @@ -708,6 +955,10 @@ msgid "Gets the results from the last update" msgstr "Saat viimeisimmän päivityksen tulokset" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "HWIDS-FILE" +msgstr "HWIDS-FILE" + #. TRANSLATORS: The hardware is waiting to be replugged msgid "Hardware is waiting to be replugged" msgstr "Laitteisto odottaa uudelleen kytkemistä" @@ -716,6 +967,15 @@ msgid "High" msgstr "Korkea" +#. TRANSLATORS: this is a string like 'HSI:2-U' +msgid "Host Security ID:" +msgstr "Koneen tietoturva ID:" + +#. TRANSLATORS: Title: +#. https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit +msgid "IOMMU" +msgstr "IOMMU" + #. TRANSLATORS: daemon is inactive msgid "Idle…" msgstr "Jouten…" @@ -724,10 +984,26 @@ msgid "Ignore SSL strict checks when downloading files" msgstr "Ohita tiukat SSL tarkistukset tiedostoja ladattaessa" +#. TRANSLATORS: command line option +msgid "Ignore firmware checksum failures" +msgstr "Ohita laiteohjelmiston tarkistussumman virheet" + +#. TRANSLATORS: command line option +msgid "Ignore firmware hardware mismatch failures" +msgstr "Ohita laitteiden yhteensopimattomuuden virheet" + +#. TRANSLATORS: command line option +msgid "Ignore requirement of external power source" +msgstr "Ohita ulkoisen virtalähteen vaatimus" + #. TRANSLATORS: Ignore validation safety checks when flashing this device msgid "Ignore validation safety checks" msgstr "Ohita turvatarkastukset" +#. TRANSLATORS: try to help +msgid "Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" +msgstr "Ohitetaan tiukat SSL-tarkistukset, jos haluat tehdä tämän tulevaisuudessa automaattisesti tee DISABLE_SSL_STRICT ympäristöösi" + #. TRANSLATORS: length of time the update takes to apply msgid "Install Duration" msgstr "Asennuksen kesto" @@ -741,7 +1017,7 @@ msgstr "Asenna laiteohjelmisto tähän laitteistoon" msgid "Install old version of system firmware" -msgstr "Asenna vanha firmware versio" +msgstr "Asenna vanha firmware-versio" msgid "Install signed device firmware" msgstr "Asenna allekirjoitettu laitteen firmware" @@ -770,15 +1046,62 @@ #. TRANSLATORS: %1 is a device name #, c-format msgid "Installing on %s…" -msgstr "Asentaa %s…" +msgstr "Asentaa laitteelle %s…" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel +msgid "Intel BootGuard" +msgstr "Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * ACM means to verify the integrity of Initial Boot Block +msgid "Intel BootGuard ACM protected" +msgstr "Intel BootGuard ACM suojattu" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * OTP = one time programmable +msgid "Intel BootGuard OTP fuse" +msgstr "Intel BootGuard OTP fuse" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * error policy is what to do on failure +msgid "Intel BootGuard error policy" +msgstr "Intel BootGuard virhekäytäntö" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * verified boot refers to the way the boot process is verified +msgid "Intel BootGuard verified boot" +msgstr "Intel BootGuard vahvistettu käynnistys" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * active means being used by the OS +msgid "Intel CET Active" +msgstr "Intel CET aktiivinen" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * enabled means supported by the processor +msgid "Intel CET Enabled" +msgstr "Intel CET käytössä" + +#. TRANSLATORS: Title: Direct Connect Interface (DCI) allows +#. * debugging of Intel processors using the USB3 port +msgid "Intel DCI debugger" +msgstr "Intel DCI virheenkorjaus" + +#. TRANSLATORS: Title: SMAP = Supervisor Mode Access Prevention +msgid "Intel SMAP" +msgstr "Intel SMAP" #. TRANSLATORS: Device cannot be removed easily msgid "Internal device" msgstr "Sisäinen laite" +#. TRANSLATORS: Suffix: the HSI result +msgid "Invalid" +msgstr "Virheellinen" + #. TRANSLATORS: Is currently in bootloader mode msgid "Is in bootloader mode" -msgstr "On käynnistyslatain moodissa" +msgstr "On käynnistyslataintilassa" #. TRANSLATORS: issue fixed with the release, e.g. CVE msgid "Issue" @@ -786,6 +1109,10 @@ msgstr[0] "Kysymykset" msgstr[1] "Kysymykset" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "KEY,VALUE" +msgstr "KEY,VALUE" + msgid "Keyring" msgstr "Avaimet" @@ -807,6 +1134,22 @@ msgid "Linux Vendor Firmware Service (testing firmware)" msgstr "Linux-toimittajan laiteohjelmisto (firmware testaus)" +#. TRANSLATORS: Title: if it's tainted or not +msgid "Linux kernel" +msgstr "Linux kernel" + +#. TRANSLATORS: Title: lockdown is a security mode of the kernel +msgid "Linux kernel lockdown" +msgstr "Linux kernel lukitus" + +#. TRANSLATORS: Title: swap space or swap partition +msgid "Linux swap" +msgstr "Linux swap" + +#. TRANSLATORS: command line option +msgid "List entries in dbx" +msgstr "Listaa merkinnät dbx-muodossa" + #. TRANSLATORS: command line option msgid "List supported firmware updates" msgstr "Lista tuetuista firmware-päivityksistä" @@ -815,17 +1158,39 @@ msgid "List the available firmware types" msgstr "Luettelo käytettävissä olevista laiteohjelmistotyypeistä" +#. TRANSLATORS: command description +msgid "Lists files on the ESP" +msgstr "Listaa ESP:n tiedostot" + #. TRANSLATORS: parsing the firmware information msgid "Loading…" msgstr "Ladataan…" +#. TRANSLATORS: Suffix: the HSI result +msgid "Locked" +msgstr "Lukittu" + #. TRANSLATORS: the release urgency msgid "Low" msgstr "Matala" +#. TRANSLATORS: Title: MEI = Intel Management Engine +msgid "MEI manufacturing mode" +msgstr "MEI tuotantotekniikka" + +#. TRANSLATORS: Title: MEI = Intel Management Engine, and the +#. * "override" is the physical PIN that can be driven to +#. * logic high -- luckily it is probably not accessible to +#. * end users on consumer boards +msgid "MEI override" +msgstr "Ohita MEI" + +msgid "MEI version" +msgstr "MEI versio" + #. TRANSLATORS: command line option -msgid "Manually whitelist specific plugins" -msgstr "Luetteloi tiettyjä lisäosia manuaalisesti" +msgid "Manually enable specific plugins" +msgstr "Ota manuaalisesti tietyt laajennukset käyttöön" #. TRANSLATORS: the release urgency msgid "Medium" @@ -853,8 +1218,8 @@ msgstr "Virheellinen taustaprosessi ja asiakas, käytä sen sijaan %s" #. TRANSLATORS: sets something in daemon.conf -msgid "Modifies a daemon configuration value." -msgstr "Muuta taustaprosessin määritysarvoja." +msgid "Modifies a daemon configuration value" +msgstr "Muuta taustaprosessin määritysarvoja" #. TRANSLATORS: command description msgid "Modifies a given remote" @@ -870,10 +1235,18 @@ msgid "Monitor the daemon for events" msgstr "Seuraa tapahtumien taustaprosessia" +#. TRANSLATORS: command description +msgid "Mounts the ESP" +msgstr "Kytkee ESP:n käyttöön" + #. TRANSLATORS: Requires a reboot to apply firmware or to reload hardware msgid "Needs a reboot after installation" msgstr "Tarvitsee käynnistyksen asennuksen jälkeen" +#. TRANSLATORS: The update state of the specific device +msgid "Needs reboot" +msgstr "Käynnistys tarvitaan" + #. TRANSLATORS: Requires system shutdown to apply firmware msgid "Needs shutdown after installation" msgstr "Tarvitsee sammutuksen asennuksen jälkeen" @@ -882,6 +1255,7 @@ msgid "New version" msgstr "Uusi versio" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "Toimintoa ei ole määritetty!" @@ -897,11 +1271,11 @@ #. TRANSLATORS: nothing attached that can be upgraded msgid "No hardware detected with firmware update capability" -msgstr "Ei havaittu sopivaa laitteistoa firmware päivitykselle" +msgstr "Ei havaittu sopivaa laitteistoa firmware-päivitykselle" #. TRANSLATORS: nothing found msgid "No plugins found" -msgstr "Ei laajennuksia" +msgstr "Liitännäisiä ei löytynyt" #. TRANSLATORS: no repositories to download from msgid "No releases available" @@ -917,17 +1291,25 @@ #. TRANSLATORS: nothing was updated offline msgid "No updates were applied" -msgstr "Ei soveltuvia päivityksiä" +msgstr "Päivityksiä ei toteutettu" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Not found" +msgstr "Ei löydy" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Not supported" +msgstr "Ei tueta" + +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "OK" #. TRANSLATORS: command line option msgid "Only show single PCR value" msgstr "Näytä vain yksi PCR-arvo" #. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Ohita plugin-varoitus" - -#. TRANSLATORS: command line option msgid "Override the default ESP path" msgstr "Ohita oletusarvoinen ESP-polku" @@ -935,10 +1317,22 @@ msgid "Override warnings and force the action" msgstr "Ohita varoitukset ja pakota toiminto" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "PATH" +msgstr "PATH" + #. TRANSLATORS: command description msgid "Parse and show details about a firmware file" msgstr "Analysoi ja näytä tiedot laiteohjelmiston tiedostosta" +#. TRANSLATORS: reading new dbx from the update +msgid "Parsing dbx update…" +msgstr "Luetaan dbx päivitys..." + +#. TRANSLATORS: reading existing dbx from the system +msgid "Parsing system dbx…" +msgstr "Luetaan järjestelmä dbx..." + #. TRANSLATORS: remote filename base msgid "Password" msgstr "Salasana" @@ -946,6 +1340,10 @@ msgid "Payload" msgstr "Tietosisältö" +#. TRANSLATORS: The update state of the specific device +msgid "Pending" +msgstr "Odottaa" + #. TRANSLATORS: console message when not using plymouth msgid "Percentage complete" msgstr "Prosenttiosuus valmis" @@ -955,6 +1353,14 @@ msgid "Please enter a number from 0 to %u: " msgstr "Anna numero 0 -%u" +#. TRANSLATORS: Failed to open plugin, hey Arch users +msgid "Plugin dependencies missing" +msgstr "Laajennuksen riippuvuudet puuttuvat" + +#. TRANSLATORS: Title: DMA as in https://en.wikipedia.org/wiki/DMA_attack +msgid "Pre-boot DMA protection" +msgstr "Pre-boot DMA-suojaus" + #. TRANSLATORS: version number of previous firmware msgid "Previous version" msgstr "Aiempi versio" @@ -974,12 +1380,20 @@ #. TRANSLATORS: a non-free software license msgid "Proprietary" -msgstr "Patentoitu" +msgstr "Suljettu" #. TRANSLATORS: command line option msgid "Query for firmware update support" msgstr "Kysely firmware-päivityksen tuesta" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "REMOTE-ID" +msgstr "REMOTE-ID" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "REMOTE-ID KEY VALUE" +msgstr "REMOTE-ID KEY VALUE" + #. TRANSLATORS: command description msgid "Read a firmware blob from a device" msgstr "Lue laiteohjelmiston BLOB laitteesta" @@ -995,7 +1409,7 @@ #. TRANSLATORS: %1 is a device name #, c-format msgid "Reading from %s…" -msgstr "Lukeminen %s…" +msgstr "Lukee laitteelta %s…" #. TRANSLATORS: reading from the flash chips msgid "Reading…" @@ -1010,8 +1424,8 @@ msgstr "Päivitä etäpalvelimen metatiedot" #. TRANSLATORS: command description -msgid "Reinstall current firmware on the device." -msgstr "Asenna nykyinen laiteohjelmisto laitteeseen." +msgid "Reinstall current firmware on the device" +msgstr "Asenna nykyinen laiteohjelmisto laitteeseen" #. TRANSLATORS: command description msgid "Reinstall firmware on a device" @@ -1024,15 +1438,15 @@ msgid "Reinstalling %s with %s... " msgstr "Uudelleenasennus %s kera %s... " +#. TRANSLATORS: the stream of firmware, e.g. nonfree or open-source +msgid "Release Branch" +msgstr "Julkaisuhaara" + #. TRANSLATORS: the server the file is coming from #. TRANSLATORS: remote identifier, e.g. lvfs-testing msgid "Remote ID" msgstr "Etätunnus" -#. TRANSLATORS: this is when a device is hotplugged -msgid "Removed" -msgstr "Poistettu" - #. TRANSLATORS: command description msgid "Replace data in an existing firmware file" msgstr "Vaihda tiedot olemassa olevaan firmware-tiedostoon" @@ -1045,9 +1459,13 @@ msgid "Reported to remote server" msgstr "Raportoitu etäpalvelimelle" -#. TRANSLATORS: Must be plugged in to an outlet -msgid "Requires AC power" -msgstr "Vaatii verkkovirtaa" +#. TRANSLATORS: the user is using Gentoo/Arch and has screwed something up +msgid "Required efivarfs filesystem was not found" +msgstr "Vaadittua efivarfs-tiedostojärjestelmää ei löytynyt" + +#. TRANSLATORS: not required for this system +msgid "Required hardware was not found" +msgstr "Vaadittavaa laitteistoa ei löytynyt" #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user msgid "Requires a bootloader" @@ -1055,7 +1473,7 @@ #. TRANSLATORS: metadata is downloaded from the Internet msgid "Requires internet connection" -msgstr "Vaatii Internet-yhteyden" +msgstr "Vaatii internetyhteyden" #. TRANSLATORS: reboot to apply the update msgid "Restart now?" @@ -1084,6 +1502,30 @@ msgid "Run the plugin composite prepare routine when using install-blob" msgstr "Asennus-blobia ajamalla käytät yhdistelmän valmiita laajennus rutiineja " +#. TRANSLATORS: this is the HSI suffix +msgid "Runtime Suffix" +msgstr "Suoritusaika" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI BIOS region" +msgstr "SPI BIOS-alue" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI lock" +msgstr "SPI-lukko" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI write" +msgstr "SPI-kirjoitus" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "SUBSYSTEM DRIVER [DEVICE-ID|GUID]" +msgstr "SUBSYSTEM DRIVER [DEVICE-ID|GUID]" + +#. TRANSLATORS: command description +msgid "Save a file that allows generation of hardware IDs" +msgstr "Tallenna tiedosto, joka sallii laitteistotunnusten luomisen" + #. TRANSLATORS: command line option msgid "Save device state into a JSON file between executions" msgstr "Tallenna laitteen tila JSON-tiedostoon suoritusten välillä" @@ -1096,10 +1538,19 @@ msgid "Scheduling…" msgstr "Ajoitetaan…" +#. TRANSLATORS: %s is a link to a website +#, c-format +msgid "See %s for more information." +msgstr "Katso %s saadaksesi lisätietoja." + #. TRANSLATORS: Device has been chosen by the daemon for the user msgid "Selected device" msgstr "Valittu laite" +#. TRANSLATORS: Volume has been chosen by the user +msgid "Selected volume" +msgstr "Valittu asema" + #. TRANSLATORS: serial number of hardware msgid "Serial Number" msgstr "Sarjanumero" @@ -1108,18 +1559,19 @@ msgid "Set the debugging flag during update" msgstr "Aseta virheenkorjauksen lippu päivityksen aikana" +#. TRANSLATORS: firmware approved by the admin msgid "Sets the list of approved firmware" msgstr "Asettaa listan hyväksytyjä 'firmware' laiteohjelmistoja " -#. TRANSLATORS: firmware approved by the admin -msgid "Sets the list of approved firmware." -msgstr "Asettaa hyväksytyn laiteohjelmiston luettelon." - #. TRANSLATORS: command description msgid "Share firmware history with the developers" msgstr "Jaa laiteohjelmiston historia kehittäjien kanssa" #. TRANSLATORS: command line option +msgid "Show all results" +msgstr "Näytä kaikki tulokset" + +#. TRANSLATORS: command line option msgid "Show client and daemon versions" msgstr "Näytä asiakas- ja taustaprosessin versiot" @@ -1152,6 +1604,10 @@ msgstr "Näytä plugin tiedot" #. TRANSLATORS: command line option +msgid "Show the calculated version of the dbx" +msgstr "Näytä dbx laskettu versio" + +#. TRANSLATORS: command line option msgid "Show the debug log from the last attempted update" msgstr "Näytä virheenkorjausloki viimeisestä päivitysyrityksestä" @@ -1188,9 +1644,17 @@ msgid "Specify Vendor/Product ID(s) of DFU device" msgstr "Määritä DFU laitteen toimittaja/tuotetunnus(s)" +#. TRANSLATORS: command line option +msgid "Specify the dbx database file" +msgstr "Määritä dbx-tietokantatiedosto" + msgid "Specify the number of bytes per USB transfer" msgstr "Määritä tavujen määrä USB-siirtoa kohti" +#. TRANSLATORS: The update state of the specific device +msgid "Success" +msgstr "Onnistui" + #. TRANSLATORS: success message -- where activation is making the new #. * firmware take effect, usually after updating offline msgid "Successfully activated all devices" @@ -1245,10 +1709,46 @@ msgid "Summary" msgstr "Yhteenveto" +#. TRANSLATORS: Suffix: the HSI result +msgid "Supported" +msgstr "Tuettu" + #. TRANSLATORS: Is found in current metadata msgid "Supported on remote server" msgstr "Tuettu etäpalvelimella" +#. TRANSLATORS: Title: a better sleep state +msgid "Suspend-to-idle" +msgstr "Keskeytä-tyhjäkäynnille" + +#. TRANSLATORS: Title: sleep state +msgid "Suspend-to-ram" +msgstr "Keskeytä-muistiin" + +#. TRANSLATORS: command description +msgid "Switch the firmware branch on the device" +msgstr "Vaihda laitteen laiteohjelmiston haaraa" + +#. TRANSLATORS: Must be plugged in to an outlet +msgid "System requires external power source" +msgstr "Järjestelmä vaatii ulkoisen virtalähteen" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "TEXT" +msgstr "TEXT" + +#. TRANSLATORS: Title: the PCR is rebuilt from the TPM event log +msgid "TPM PCR0 reconstruction" +msgstr "TPM PCR0 -jälleenrakennus" + +#. TRANSLATORS: Title: TPM = Trusted Platform Module +msgid "TPM v2.0" +msgstr "TPM v2.0" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Tainted" +msgstr "Pilaantunut" + msgid "Target" msgstr "Kohde" @@ -1256,30 +1756,135 @@ msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "LVFS on ilmainen palvelu, joka toimii itsenäisenä oikeushenkilönä eikä sillä ole yhteyttä $OS_RELEASE:NAME$. Jakelijasi ei ehkä ole tarkistanut mitään laiteohjelmistopäivityksiä, jotka ovat yhteensopivia järjestelmän tai liitettyjen laitteiden kanssa. Kaikki laiteohjelmistot on tarkoitettu vain alkuperäisen laitteen valmistajalle." +#. TRANSLATORS: this is more background on a security measurement problem +msgid "The TPM PCR0 differs from reconstruction." +msgstr "TPM PCR0 eroaa rakennettavasta." + +#. TRANSLATORS: the user is SOL for support... +msgid "The daemon has loaded 3rd party code and is no longer supported by the upstream developers!" +msgstr "Palvelu on ladannut 3-osapuolen koodin, eikä kehittäjät enää jatkossa tue sitä!" + +#. TRANSLATORS: %1 is the firmware vendor, %2 is the device vendor name +#, c-format +msgid "The firmware from %s is not supplied by %s, the hardware vendor." +msgstr "Laitteistotoimittaja %s ei toimita ohjelmistoa kohteesta %s." + +#. TRANSLATORS: try to help +msgid "The system clock has not been set correctly and downloading files may fail." +msgstr "Järjestelmän kelloa ei ole asetettu oikein ja tiedostojen lataaminen saattaa epäonnistua." + +#. TRANSLATORS: nothing to show +msgid "There are no blocked firmware files" +msgstr "Estettyjä firmware-tiedostoja ei ole" + #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator msgid "There is no approved firmware." msgstr "Hyväksyttyä laiteohjelmistoa ei ole." +#. TRANSLATORS: unsupported build of the package +msgid "This package has not been validated, it may not work properly." +msgstr "Tätä pakettia ei ole vahvistettu, se ei välttämättä toimi oikein." + #. TRANSLATORS: we're poking around as a power user msgid "This program may only work correctly as root" -msgstr "Tämä ohjelma voi toimia vain juuressa 'root'" +msgstr "Tämä ohjelma toimii oikein vain root-käyttäjän oikeuksin" msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "Tämä sisältää firmwaren, jota ei ole vientikiellossa, mutta jota laitteistotoimittaja testaa edelleen. Varmista, että voit päivittää firmwaren manuaalisesti, jos päivitys epäonnistuu." +#. TRANSLATORS: this is instructions on how to improve the HSI suffix +msgid "This system has HSI runtime issues." +msgstr "Järjestelmässä on HSI-suoritusajan ongelma." + +#. TRANSLATORS: this is instructions on how to improve the HSI security level +msgid "This system has a low HSI security level." +msgstr "Tämän järjestelmän HSI-tietoturvataso on alhainen." + +#. TRANSLATORS: description of dbxtool +msgid "This tool allows an administrator to apply UEFI dbx updates." +msgstr "Tämän työkalun avulla järjestelmänvalvoja voi käyttää UEFI dbx-päivityksiä." + +#. TRANSLATORS: CLI description +msgid "This tool allows an administrator to debug UpdateCapsule operation." +msgstr "Tämän työkalun avulla järjestelmänvalvoja voi korjata päivitys-kapselin toiminnan." + +#. TRANSLATORS: CLI description +msgid "This tool allows an administrator to query and control the fwupd daemon, allowing them to perform actions such as installing or downgrading firmware." +msgstr "Tämän työkalun avulla järjestelmänvalvoja voi kysellä ja hallita fwupd-palvelua, jolloin voi suorittaa toimintoja, kuten laiteohjelmiston asennus tai päivittäminen." + +#. TRANSLATORS: CLI description +msgid "This tool allows an administrator to use the fwupd plugins without being installed on the host system." +msgstr "Tämän työkalun avulla järjestelmänvalvoja voi käyttää fwupd-laajennuksia asentamatta sitä järjestelmään." + +#. TRANSLATORS: CLI description +msgid "This tool can be used from other tools and from shell scripts." +msgstr "Tätä työkalua voidaan käyttää muista työkaluista ja päätteellä. " + #. TRANSLATORS: the user needs to stop playing with stuff msgid "This tool can only be used by the root user" msgstr "Tätä työkalua voi käyttää vain root-käyttäjä" +#. TRANSLATORS: CLI description +msgid "This tool will read and parse the TPM event log from the system firmware." +msgstr "Tämä työkalu lukee ja TPM-tapahtumalokin järjestelmän laiteohjelmistosta." + +#. TRANSLATORS: command line option +msgid "Timeout in milliseconds for each parse" +msgstr "Aikakatkaisu millisekunteina kutakin jäsentämistä varten" + +#. TRANSLATORS: The update state of the specific device +msgid "Transient failure" +msgstr "Ohimenevä häiriö" + #. TRANSLATORS: remote type, e.g. remote or local msgid "Type" msgstr "Tyyppi" +#. TRANSLATORS: partition refers to something on disk, again, hey Arch users +msgid "UEFI ESP partition not detected or configured" +msgstr "UEFI ESP-osiota ei havaittu tai määritetty" + #. TRANSLATORS: program name msgid "UEFI Firmware Utility" msgstr "UEFI firmware -apuohjelma" +#. TRANSLATORS: capsule updates are an optional BIOS feature +msgid "UEFI capsule updates not available or enabled in firmware setup" +msgstr "UEFI-kapselipäivitykset eivät ole saatavilla tai käytössä laiteohjelmiston asennuksessa" + +#. TRANSLATORS: program name +msgid "UEFI dbx Utility" +msgstr "UEFI dbx-apuohjelma" + +#. TRANSLATORS: Title: PK is the 'platform key' for the machine +msgid "UEFI platform key" +msgstr "UEFI-alustan avain" + +#. TRANSLATORS: Title: SB is a way of locking down UEFI +msgid "UEFI secure boot" +msgstr "UEFI secure boot" + +#. TRANSLATORS: error message +msgid "Unable to connect to service" +msgstr "Yhteys palveluun ei onnistu" + +#. TRANSLATORS: command description +msgid "Unbind current driver" +msgstr "Pura nykyinen ohjain" + +#. TRANSLATORS: we will now offer this firmware to the user +msgid "Unblocking firmware:" +msgstr "Laiteohjelmiston poistaminen käytöstä:" + +#. TRANSLATORS: command description +msgid "Unblocks a specific firmware from being installed" +msgstr "Poistaa asennuseston laiteohjelmistosta" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Unencrypted" +msgstr "Salaamaton" + #. TRANSLATORS: current daemon status is unknown #. TRANSLATORS: we don't know the license of the update #. TRANSLATORS: unknown release urgency @@ -1291,12 +1896,20 @@ msgstr "Tuntematon laite" msgid "Unlock the device to allow access" -msgstr "Sallia pääsy laitteeseen" +msgstr "Avaa laitteen lukitus salliaksesi käytön" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Unlocked" +msgstr "Auki" #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "Avaa pääsy laitteen laiteohjelmistoon" +#. TRANSLATORS: command description +msgid "Unmounts the ESP" +msgstr "Poistaa ESP:n käytöstä" + #. TRANSLATORS: command line option msgid "Unset the debugging flag during update" msgstr "Poista virheenkorjauksen lippu päivityksen aikana" @@ -1306,13 +1919,17 @@ msgid "Unsupported daemon version %s, client version is %s" msgstr "Ei tuettu taustaprosessin versio %s, asiakasversio on %s" +#. TRANSLATORS: Suffix: the HSI result +msgid "Untainted" +msgstr "Puhdistettu" + #. TRANSLATORS: Device is updatable in this or any other mode msgid "Updatable" msgstr "Päivitettävissä" #. TRANSLATORS: error message from last update attempt msgid "Update Error" -msgstr "Päivitys virhe" +msgstr "Päivitysvirhe" #. TRANSLATORS: helpful messages from last update #. TRANSLATORS: helpful messages for the update @@ -1337,7 +1954,7 @@ #. TRANSLATORS: Update can only be done from offline mode msgid "Update requires a reboot" -msgstr "Päivitys edellyttää käynnistyksen" +msgstr "Päivitys edellyttää uudelleenkäynnistyksen" #. TRANSLATORS: command description msgid "Update the stored cryptographic hash with current ROM contents" @@ -1354,6 +1971,9 @@ msgid "Updates all firmware to latest versions available" msgstr "Päivittää kaikki laiteohjaimet uusimpiin saatavilla oleviin versioihin" +msgid "Updating" +msgstr "Päivittää" + #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second and third are #. * version numbers e.g. "1.2.3" @@ -1364,7 +1984,7 @@ #. TRANSLATORS: %1 is a device name #, c-format msgid "Updating %s…" -msgstr "Päivittää %s…" +msgstr "Päivittää laitetta %s…" #. TRANSLATORS: message letting the user know an upgrade is available #. * %1 is the device name and %2 and %3 are version strings @@ -1372,10 +1992,6 @@ msgid "Upgrade available for %s from %s to %s" msgstr "Päivitys saatavilla %s alkaen %s kohde %s" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Lähetä viesti:" - msgid "Upload report just this one time, but prompt again for future updates" msgid_plural "Upload reports just this one time, but prompt again for future updates" msgstr[0] "Lataa raportit vain tällä kertaa, mutta pyydä uudelleen tulevissa päivityksissä" @@ -1383,7 +1999,7 @@ #. TRANSLATORS: ask the user to upload msgid "Upload report now?" -msgstr "Lataa raportti nyt?" +msgstr "Lähetetäänkö raportti nyt?" msgid "Upload report this time and automatically upload reports after completing future updates" msgid_plural "Upload reports this time and automatically upload reports after completing future updates" @@ -1398,6 +2014,14 @@ msgid "Urgency" msgstr "Kiireellisyys" +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdmgr --help for help" +msgstr "Suorita fwupdmgr --help nähdäksesi ohjeet" + +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdtool --help for help" +msgstr "Suorita fwupdtool --help nähdäksesi ohjeet" + #. TRANSLATORS: command line option msgid "Use quirk flags when installing firmware" msgstr "Käytä Quirk-lippuja asennettaessa laiteohjelmistoa" @@ -1410,6 +2034,17 @@ msgid "Username" msgstr "Käyttäjätunnus" +msgid "VID:PID" +msgstr "VID:PID" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Valid" +msgstr "Voimassa" + +#. TRANSLATORS: ESP refers to the EFI System Partition +msgid "Validating ESP contents…" +msgstr "Vahvistetaan ESP-sisältöä..." + #. TRANSLATORS: one line variant of release (e.g. 'Prerelease' or 'China') msgid "Variant" msgstr "Muunnelma" @@ -1422,19 +2057,19 @@ msgid "Verifying…" msgstr "Vahvistetaan…" -#. TRANSLATORS: try to help -msgid "WARNING: Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" -msgstr "VAROITUS: SSL tarkistusten sivuuttaminen, jotta se tapahtuu automaattisesti tulevassa DISABLE_SSL_STRICT ympäristössä" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Versio" + +#. TRANSLATORS: this is a prefix on the console +msgid "WARNING:" +msgstr "VAROITUS:" #. TRANSLATORS: waiting for device to do something msgid "Waiting…" msgstr "Odotetaan…" #. TRANSLATORS: command description -msgid "Watch DFU devices being hotplugged" -msgstr "Katso, että DFU-laitteet on kytketty" - -#. TRANSLATORS: command description msgid "Watch for hardware changes" msgstr "Katso laitteiston muutoksia" @@ -1446,6 +2081,10 @@ msgid "Write firmware from file into one partition" msgstr "Kirjoita firmware tiedostosta osioon" +#. TRANSLATORS: decompressing images from a container firmware +msgid "Writing file:" +msgstr "Kirjoitetaan tiedosto:" + #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Kirjoitetaan…" @@ -1454,19 +2093,39 @@ msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "Jakelijasi ei ehkä ole tarkistanut mitään laiteohjelmistopäivityksiä, jotka ovat yhteensopivia järjestelmän tai liitettyjen laitteiden kanssa." +#. TRANSLATORS: %1 is the device vendor name +#, c-format +msgid "Your hardware may be damaged using this firmware, and installing this release may void any warranty with %s." +msgstr "Laitteistosi saattaa vaurioitua tämän laiteohjelmiston avulla ja asentaminen voi mitätöidä %stakuun." + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "[CHECKSUM]" +msgstr "[CHECKSUM]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "[DEVICE-ID|GUID]" +msgstr "[DEVICE-ID|GUID]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "[DEVICE-ID|GUID] [BRANCH]" +msgstr "[DEVICE-ID|GUID] [BRANCH]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "[FILE FILE_SIG REMOTE-ID]" +msgstr "[FILE FILE_SIG REMOTE-ID]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "[SMBIOS-FILE|HWIDS-FILE]" +msgstr "[SMBIOS-FILE|HWIDS-FILE]" + +#. TRANSLATORS: this is the default branch name when unset +msgid "default" +msgstr "oletus" + #. TRANSLATORS: program name msgid "fwupd TPM event log utility" -msgstr "fwupd TPM tapahtumalokin apuohjelma" +msgstr "fwupd:n TPM-tapahtumalokin apuohjelma" -#. TRANSLATORS: message letting the user know no device upgrade available due -#. to missing on LVFS -#. * %1 is the device name -#, c-format -msgid "• %s has no available firmware updates" -msgstr "• %s ei ole saatavilla firmware päivityksiä" - -#. TRANSLATORS: message letting the user know no device upgrade available -#. * %1 is the device name -#, c-format -msgid "• %s has the latest available firmware version" -msgstr "• %s on uusin saatavilla oleva firmware-versio" +#. TRANSLATORS: Title: if the fwupd plugins are all present and correct +msgid "fwupd plugins" +msgstr "fwupd-liitännäiset" diff -Nru fwupd-1.4.5/po/fr.po fwupd-1.5.8/po/fr.po --- fwupd-1.4.5/po/fr.po 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/po/fr.po 2021-03-31 20:08:32.000000000 +0000 @@ -3,7 +3,9 @@ # This file is distributed under the same license as the fwupd package. # # Translators: +# Corentin Noël , 2020 # Franck , 2015 +# Julien Humbert , 2020-2021 msgid "" msgstr "" "Project-Id-Version: fwupd\n" @@ -15,19 +17,147 @@ "Language: fr\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "%.0f minute restante" +msgstr[1] "%.0f minutes restantes" + +#. TRANSLATORS: Title: %1 is ME kind, e.g. CSME/TXT, %2 is a version number +#, c-format +msgid "%s v%s" +msgstr "%s v%s" + +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s version" +msgstr "Version %s" + +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u jour" +msgstr[1] "%u jours" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u heure" +msgstr[1] "%u heures" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u minute" +msgstr[1] "%u minutes" + +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u seconde" +msgstr[1] "%u secondes" + +#. TRANSLATORS: the age of the metadata +msgid "Age" +msgstr "Âge" + #. TRANSLATORS: this is a command alias, e.g. 'get-devices' #, c-format msgid "Alias to %s" msgstr "Alias de %s" +#. TRANSLATORS: waiting for user to authenticate +msgid "Authenticating…" +msgstr "Authentification…" + #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to update the firmware on this machine" msgstr "Une authentification est nécessaire pour mettre à jour le micrologiciel sur cette machine" +#. TRANSLATORS: firmware version of bootloader +msgid "Bootloader Version" +msgstr "Version du chargeur d’amorçage" + +#. TRANSLATORS: this is to abort the interactive prompt +msgid "Cancel" +msgstr "Annuler" + +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "Annulé" + +#. TRANSLATORS: this is when the daemon state changes +msgid "Changed" +msgstr "Modifié" + +#. TRANSLATORS: remote checksum +msgid "Checksum" +msgstr "Somme de contrôle" + +#. TRANSLATORS: get interactive prompt, where branch is the +#. * supplier of the firmware, e.g. "non-free" or "free" +msgid "Choose a branch:" +msgstr "Choisir une branche :" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a volume:" +msgstr "Choisir un volume :" + +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "Commande non trouvée" + +#. TRANSLATORS: the release urgency +msgid "Critical" +msgstr "Critique" + +#. TRANSLATORS: version number of current firmware +msgid "Current version" +msgstr "Version actuelle" + #. TRANSLATORS: for the --verbose arg msgid "Debugging Options" msgstr "Options de débogage" +#. TRANSLATORS: decompressing the firmware file +msgid "Decompressing…" +msgstr "Décompression…" + +#. TRANSLATORS: multiline description of device +msgid "Description" +msgstr "Description" + +#. TRANSLATORS: more details about the update link +msgid "Details" +msgstr "Détails" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device added:" +msgstr "Périphérique ajouté :" + +#. TRANSLATORS: this is when a device has been updated +msgid "Device changed:" +msgstr "Périphérique modifié :" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device removed:" +msgstr "Périphérique retiré :" + +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is inactive and not used +msgid "Disabled" +msgstr "Désactivé" + +#. TRANSLATORS: command line option +msgid "Display version" +msgstr "Afficher la version" + +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Terminé !" @@ -39,6 +169,28 @@ msgid "Downgrading %s from %s to %s... " msgstr "Rétrogradation de %s de %s en %s" +#. TRANSLATORS: downloading from a remote server +msgid "Downloading…" +msgstr "Téléchargement…" + +#. TRANSLATORS: length of time the update takes to apply +msgid "Duration" +msgstr "Durée" + +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use +#. TRANSLATORS: if the remote is enabled +msgid "Enabled" +msgstr "Activé" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Encrypted" +msgstr "Chiffré" + +#. TRANSLATORS: Title: Memory contents are encrypted, e.g. Intel TME +msgid "Encrypted RAM" +msgstr "RAM chiffrée" + #. TRANSLATORS: exit after we've started up, used for user profiling msgid "Exit after a small delay" msgstr "Quitter après un bref délai" @@ -47,14 +199,41 @@ msgid "Exit after the engine has loaded" msgstr "Quitter après le chargement du moteur" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILE" +msgstr "FICHIER" + +#. TRANSLATORS: Suffix: the fallback HSI result +#. TRANSLATORS: The update state of the specific device +msgid "Failed" +msgstr "Échec" + #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Echec de l'analyse des paramètres" +#. TRANSLATORS: filename of the local file +msgid "Filename" +msgstr "Nom de fichier" + #. TRANSLATORS: program summary msgid "Firmware Update D-Bus Service" msgstr "Service D-Bus de mise à jour des micrologiciels" +#. TRANSLATORS: description of plugin state, e.g. disabled +#. TRANSLATORS: release properties +msgid "Flags" +msgstr "Drapeaux" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Trouvé" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgctxt "A single GUID" +msgid "GUID" +msgstr "GUID" + #. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "Obtenir la liste des périphériques supportant les mises à jour de micrologiciel" @@ -63,14 +242,145 @@ msgid "Gets details about a firmware file" msgstr "Obtenir les détails d'un fichier de micrologiciel" +#. TRANSLATORS: the release urgency +msgid "High" +msgstr "Haute" + +#. TRANSLATORS: Title: +#. https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit +msgid "IOMMU" +msgstr "IOMMU" + #. TRANSLATORS: command description msgid "Install a firmware file on this hardware" msgstr "Installer un fichier de micrologiciel sur ce matériel" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing on %s…" +msgstr "Installation sur %s…" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel +msgid "Intel BootGuard" +msgstr "Intel BootGuard" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * active means being used by the OS +msgid "Intel CET Active" +msgstr "Intel CET actif" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * enabled means supported by the processor +msgid "Intel CET Enabled" +msgstr "Intel CET activé" + +#. TRANSLATORS: Title: SMAP = Supervisor Mode Access Prevention +msgid "Intel SMAP" +msgstr "Intel SMAP" + +#. TRANSLATORS: Device cannot be removed easily +msgid "Internal device" +msgstr "Périphérique interne" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Invalid" +msgstr "Invalide" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "KEY,VALUE" +msgstr "CLÉ,VALEUR" + +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Moins d’une minute restante" + +#. TRANSLATORS: e.g. GPLv2+, Proprietary etc +msgid "License" +msgstr "Licence" + +#. TRANSLATORS: Title: if it's tainted or not +msgid "Linux kernel" +msgstr "Noyau Linux" + +#. TRANSLATORS: parsing the firmware information +msgid "Loading…" +msgstr "Chargement…" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Locked" +msgstr "Verrouillé" + +#. TRANSLATORS: the release urgency +msgid "Low" +msgstr "Faible" + +msgid "MEI version" +msgstr "Version MEI" + +#. TRANSLATORS: the release urgency +msgid "Medium" +msgstr "Moyenne" + +#. TRANSLATORS: smallest version number installable on device +msgid "Minimum Version" +msgstr "Version minimum" + +#. TRANSLATORS: version number of new firmware +msgid "New version" +msgstr "Nouvelle version" + #. TRANSLATORS: nothing attached that can be upgraded msgid "No hardware detected with firmware update capability" msgstr "Aucun matériel ayant des capacités de mise à jour du micrologiciel n'a été détecté" +#. TRANSLATORS: Suffix: the HSI result +msgid "Not found" +msgstr "Non trouvé" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Not supported" +msgstr "Non pris en charge" + +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "OK" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "PATH" +msgstr "CHEMIN" + +#. TRANSLATORS: remote filename base +msgid "Password" +msgstr "Mot de passe" + +#. TRANSLATORS: version number of previous firmware +msgid "Previous version" +msgstr "Version précédente" + +msgid "Print the version number" +msgstr "Afficher le numéro de version" + +#. TRANSLATORS: the numeric priority +msgid "Priority" +msgstr "Priorité" + +#. TRANSLATORS: a non-free software license +msgid "Proprietary" +msgstr "Propriétaire" + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Reading from %s…" +msgstr "Lecture depuis %s…" + +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "Lecture…" + +#. TRANSLATORS: console message when not using plymouth +msgid "Rebooting…" +msgstr "Redémarrage…" + #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second is a version number #. * e.g. "1.2.3" @@ -78,6 +388,22 @@ msgid "Reinstalling %s with %s... " msgstr "Réinstallation de %s en %s" +#. TRANSLATORS: reboot to apply the update +msgid "Restart now?" +msgstr "Redémarrer maintenant ?" + +#. TRANSLATORS: restarting the device to pick up new F/W +msgid "Restarting device…" +msgstr "Redémarrage du périphérique…" + +#. TRANSLATORS: Volume has been chosen by the user +msgid "Selected volume" +msgstr "Volume sélectionné" + +#. TRANSLATORS: command line option +msgid "Show all results" +msgstr "Afficher tous les résultats" + #. TRANSLATORS: for the --verbose arg msgid "Show debugging options" msgstr "Montrer les options de débogage" @@ -86,9 +412,105 @@ msgid "Show extra debugging information" msgstr "Montre des informations de débogage complémentaires" +msgid "Signature" +msgstr "Signature" + +#. TRANSLATORS: file size of the download +msgid "Size" +msgstr "Taille" + +#. TRANSLATORS: source (as in code) link +msgid "Source" +msgstr "Source" + +#. TRANSLATORS: one line summary of device +msgid "Summary" +msgstr "Résumé" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Supported" +msgstr "Pris en charge" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "TEXT" +msgstr "TEXTE" + +#. TRANSLATORS: Title: TPM = Trusted Platform Module +msgid "TPM v2.0" +msgstr "TPM v2.0" + +msgid "Target" +msgstr "Cible" + +#. TRANSLATORS: remote type, e.g. remote or local +msgid "Type" +msgstr "Type" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Unencrypted" +msgstr "Déchiffré" + +#. TRANSLATORS: current daemon status is unknown +#. TRANSLATORS: we don't know the license of the update +#. TRANSLATORS: unknown release urgency +msgid "Unknown" +msgstr "Inconnu" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Unlocked" +msgstr "Déverrouillé" + +#. TRANSLATORS: ask the user if we can update the metadata +msgid "Update now?" +msgstr "Mettre à jour maintenant ?" + +msgid "Updating" +msgstr "Mise à jour" + #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second and third are #. * version numbers e.g. "1.2.3" #, c-format msgid "Updating %s from %s to %s... " msgstr "Mise à jour de %s de %s en %s" + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "Mise à jour de %s…" + +#. TRANSLATORS: remote filename base +msgid "Username" +msgstr "Nom d’utilisateur" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Valid" +msgstr "Valide" + +#. TRANSLATORS: one line variant of release (e.g. 'Prerelease' or 'China') +msgid "Variant" +msgstr "Variante" + +#. TRANSLATORS: manufacturer of hardware +msgid "Vendor" +msgstr "Fournisseur" + +#. TRANSLATORS: verifying we wrote the firmware correctly +msgid "Verifying…" +msgstr "Vérification…" + +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Version" + +#. TRANSLATORS: waiting for device to do something +msgid "Waiting…" +msgstr "En attente…" + +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "Écriture…" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "[CHECKSUM]" +msgstr "[SOMME DE CONTRÔLE]" diff -Nru fwupd-1.4.5/po/fur.po fwupd-1.5.8/po/fur.po --- fwupd-1.4.5/po/fur.po 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/po/fur.po 2021-03-31 20:08:32.000000000 +0000 @@ -42,10 +42,6 @@ msgid "Activating firmware update" msgstr "Ativazion inzornament firmware" -#. TRANSLATORS: this is when a device is hotplugged -msgid "Added" -msgstr "Zontât" - #. TRANSLATORS: the age of the metadata msgid "Age" msgstr "Etât" @@ -150,7 +146,6 @@ msgid "Cancelled" msgstr "Anulât" -#. TRANSLATORS: this is when a device is hotplugged #. TRANSLATORS: this is when the daemon state changes msgid "Changed" msgstr "Modificât" @@ -252,6 +247,7 @@ msgstr[0] "No sta inviâ il rapuart e no sta domandâ plui di inviâ i rapuarts pai inzornaments futûrs" msgstr[1] "No sta inviâ i rapuarts e no sta domandâ plui di inviâ i rapuarts pai inzornaments futûrs" +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Fat!" @@ -292,6 +288,8 @@ msgid "Enable this remote?" msgstr "Abilitâ chest rimot?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Abilitât" @@ -394,6 +392,15 @@ msgid "Force the action ignoring all warnings" msgstr "Sfuarce la azion ignorant ducj i avertiments" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Cjatât" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgctxt "A single GUID" +msgid "GUID" +msgstr "GUID" + #. TRANSLATORS: command description msgid "Get all devices and possible releases" msgstr "Oten ducj i dispositîfs e lis pussibilis publicazions" @@ -497,6 +504,7 @@ msgid "Monitor the daemon for events" msgstr "Monitore il demoni pai events" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "Nissune azion specificade!" @@ -530,15 +538,15 @@ msgid "No updates were applied" msgstr "Nol è stât aplicât nissun inzornament" +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "Va ben" + #. TRANSLATORS: command line option msgid "Only show single PCR value" msgstr "Mostre dome il valôr PCR" #. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Ignore i avertiments dal plugin" - -#. TRANSLATORS: command line option msgid "Override the default ESP path" msgstr "Passe parsore al valôr dal percors ESP predefinît" @@ -613,10 +621,6 @@ msgid "Remote ID" msgstr "ID rimot" -#. TRANSLATORS: this is when a device is hotplugged -msgid "Removed" -msgstr "Gjavât" - #. TRANSLATORS: command description msgid "Replace data in an existing firmware file" msgstr "Sostituìs i dâts intun file di firmware esistent" @@ -664,6 +668,7 @@ msgid "Set the debugging flag during update" msgstr "Stabilìs la opzion di debug dilunc l'inzornament" +#. TRANSLATORS: firmware approved by the admin msgid "Sets the list of approved firmware" msgstr "Al stabilìs la liste dai firmware aprovâts" @@ -858,10 +863,6 @@ msgid "Upgrade available for %s from %s to %s" msgstr "Inzornament disponibil par %s di %s a %s" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Messaç dal inviament:" - msgid "Upload report just this one time, but prompt again for future updates" msgid_plural "Upload reports just this one time, but prompt again for future updates" msgstr[0] "Invie il rapuart dome cheste volte, ma torne domande pai inzornaments futûrs" @@ -888,6 +889,10 @@ msgid "Verifying…" msgstr "Daûr a verificâ…" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Version" + #. TRANSLATORS: waiting for device to do something msgid "Waiting…" msgstr "In spiete…" diff -Nru fwupd-1.4.5/po/gl.po fwupd-1.5.8/po/gl.po --- fwupd-1.4.5/po/gl.po 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.5.8/po/gl.po 2021-03-31 20:08:32.000000000 +0000 @@ -0,0 +1,998 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the fwupd package. +# +# Translators: +# Fran Diéguez , 2020 +msgid "" +msgstr "" +"Project-Id-Version: fwupd\n" +"Report-Msgid-Bugs-To: \n" +"Language-Team: Galician (http://www.transifex.com/freedesktop/fwupd/language/gl/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: gl\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] " Falta %.0f minuto" +msgstr[1] " Faltan %.0f minutos" + +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s manufacturing mode" +msgstr "Modo de fabricación %s" + +#. TRANSLATORS: Title: %1 is ME kind, e.g. CSME/TXT, %2 is a version number +#, c-format +msgid "%s v%s" +msgstr "%s v%s" + +#. TRANSLATORS: command description +msgid "Activate pending devices" +msgstr "Activar os dispositivos pendentes" + +msgid "Activate the new firmware on the device" +msgstr "Activar o novo firmware no dispositivo" + +#. TRANSLATORS: should the remote still be enabled +msgid "Agree and enable the remote?" +msgstr "Aceptar e activar o remoto?" + +#. TRANSLATORS: this is a command alias, e.g. 'get-devices' +#, c-format +msgid "Alias to %s" +msgstr "Alias a %s" + +#. TRANSLATORS: command line option +msgid "Allow downgrading firmware versions" +msgstr "Permitir a desactualización de versións de firmware" + +#. TRANSLATORS: command line option +msgid "Allow reinstalling existing firmware versions" +msgstr "Permitir a reinstalación de versións de firmware existentes" + +#. TRANSLATORS: command line option +msgid "Apply firmware updates" +msgstr "Aplicar actualizacións de firmware" + +#. TRANSLATORS: command line option +msgid "Apply update even when not advised" +msgstr "Aplicar actualización incluso cando non se avise" + +#. TRANSLATORS: command line option +msgid "Apply update files" +msgstr "Aplicar ficheiros de actualización" + +#. TRANSLATORS: actually sending the update to the hardware +msgid "Applying update…" +msgstr "Aplicando actualización…" + +#. TRANSLATORS: approved firmware has been checked by +#. * the domain administrator +msgid "Approved firmware:" +msgid_plural "Approved firmware:" +msgstr[0] "Firmware aprovados:" +msgstr[1] "Firmware aprovado:" + +#. TRANSLATORS: stop nagging the user +msgid "Ask again next time?" +msgstr "Preguntar de novo a seguinte vez?" + +#. TRANSLATORS: command description +msgid "Attach to firmware mode" +msgstr "Anexarse ao modo de firmware" + +#. TRANSLATORS: waiting for user to authenticate +msgid "Authenticating…" +msgstr "Autenticando…" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on a removable device" +msgstr "Requírese autenticación para desactualizar o firmware nun dispositivo extraíbel" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on this machine" +msgstr "Requírese autenticación para desactualizar o firmware nesta máquina" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify a configured remote used for firmware updates" +msgstr "Requírese autenticación para modificar a configuración do remoto usado para actualizar firmwares" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify daemon configuration" +msgstr "Requírese autenticación para modificar a configuración do demonio" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to set the list of approved firmware" +msgstr "Requírese autenticación para estabelecer a lista do firmware aprovado" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to sign data using the client certificate" +msgstr "Requírese autenticación para asinar os datos usando o certificado do cliente" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to switch to the new firmware version" +msgstr "Requírese autenticación para trocar a unha nova versión do firmware" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to unlock a device" +msgstr "Requírese autenticación para desbloquear un dispositivo" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on a removable device" +msgstr "Requírese autenticación para actualizar o firmware nun dispositivo extraíbel" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on this machine" +msgstr "Requírese autenticación para actualizar o firmware nesta máquina" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the stored checksums for the device" +msgstr "Requírese autenticación para actualizar as sumas de verificación para o dispositivo" + +#. TRANSLATORS: this is to abort the interactive prompt +msgid "Cancel" +msgstr "Cancelar" + +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "Cancelado" + +#. TRANSLATORS: the user is using a LiveCD or LiveUSB install disk +msgid "Cannot apply updates on live media" +msgstr "Non foi posíbel aplicar as actualizacións no soporte multimedia" + +#. TRANSLATORS: this is when the daemon state changes +msgid "Changed" +msgstr "Cambiado" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a device:" +msgstr "Seleccione un dispositivo:" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a firmware type:" +msgstr "Escolla o tipo de firmware:" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a release:" +msgstr "Escolla a publicación:" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a volume:" +msgstr "Escolla un volume:" + +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "Orde non atopada" + +#. TRANSLATORS: command description +msgid "Convert a firmware file" +msgstr "Converter un ficheiro de firmware" + +#. TRANSLATORS: DFU stands for device firmware update +msgid "DFU Utility" +msgstr "Utilidad DFU" + +#. TRANSLATORS: for the --verbose arg +msgid "Debugging Options" +msgstr "Opcións de depuración" + +#. TRANSLATORS: decompressing the firmware file +msgid "Decompressing…" +msgstr "Descomprimindo…" + +#. TRANSLATORS: command description +msgid "Detach to bootloader mode" +msgstr "Desanexarse ao modo de firmware" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device added:" +msgstr "Dispositivo engadido:" + +#. TRANSLATORS: this is when a device has been updated +msgid "Device changed:" +msgstr "Dispositivo cambiado" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device removed:" +msgstr "Dispositivo retirado:" + +#. TRANSLATORS: a list of successful updates +msgid "Devices that have been updated successfully:" +msgstr "Dispositivos que foron actualizados con éxito:" + +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is inactive and not used +msgid "Disabled" +msgstr "Desactivado" + +msgid "Disabled fwupdate debugging" +msgstr "Desactivar a depuración de fwupdate" + +#. TRANSLATORS: command line option +msgid "Display version" +msgstr "Mostrar versión" + +#. TRANSLATORS: command line option +msgid "Do not check for reboot after update" +msgstr "Non marcar para reiniciar despois de actualizar" + +#. TRANSLATORS: turn on all debugging +msgid "Do not include log domain prefix" +msgstr "Non incluír o dominio do rexistro" + +#. TRANSLATORS: turn on all debugging +msgid "Do not include timestamp prefix" +msgstr "Non incluír o prefixo de marca de tempo" + +#. TRANSLATORS: command line option +msgid "Do not perform device safety checks" +msgstr "Non levar a cabo comprobacións de dispositivo" + +msgid "Do not upload report at this time, but prompt again for future updates" +msgid_plural "Do not upload reports at this time, but prompt again for future updates" +msgstr[0] "Non subir reporte esta vez, pero preguntar de novo en futuras actualizacións" +msgstr[1] "Non subir reportes esta vez, pero preguntar de novo en futuras actualizacións" + +#. TRANSLATORS: success +#. success +msgid "Done!" +msgstr "Feito!" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Downgrading %s from %s to %s... " +msgstr "Desactualizando %s desde %s a %s... " + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "Desactualizando %s" + +#. TRANSLATORS: downloading from a remote server +msgid "Downloading…" +msgstr "Descargando…" + +#. TRANSLATORS: command description +msgid "Dump SMBIOS data from a file" +msgstr "Volcar os datos da SMBIOS desde un ficheiro " + +#. TRANSLATORS: ESP is EFI System Partition +msgid "ESP specified was not valid" +msgstr "O ESP especificado non é válido" + +#. TRANSLATORS: command line option +msgid "Enable firmware update support on supported systems" +msgstr "Activar a compatibilidade de actualización de firmware nos sistemas admitidos" + +#. TRANSLATORS: Turn on the remote +msgid "Enable this remote?" +msgstr "Desexa activar este remoto?" + +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use +#. TRANSLATORS: if the remote is enabled +msgid "Enabled" +msgstr "Activad" + +msgid "Enabled fwupdate debugging" +msgstr "Activar a depuración de fwupdate" + +msgid "Enabling this functionality is done at your own risk, which means you have to contact your original equipment manufacturer regarding any problems caused by these updates. Only problems with the update process itself should be filed at $OS_RELEASE:BUG_REPORT_URL$." +msgstr "Active esta funcionalidade baixo o seu risco, o que significa que ten que contactar co seu fabricante de equipamento orixinal se ten calquera problema con estas actualizacións. Só os problemas co proceso de actualización en si deberían enviarse en $OS_RELEASE:BUG_REPORT_URL$." + +#. TRANSLATORS: Suffix: the HSI result +msgid "Encrypted" +msgstr "Cifrad" + +#. TRANSLATORS: Title: Memory contents are encrypted, e.g. Intel TME +msgid "Encrypted RAM" +msgstr "RAM cifrada" + +#. TRANSLATORS: erasing contents of the flash chips +msgid "Erasing…" +msgstr "Borrando…" + +#. TRANSLATORS: exit after we've started up, used for user profiling +msgid "Exit after a small delay" +msgstr "Saír despois dun pequeno atraso" + +#. TRANSLATORS: exit straight away, used for automatic profiling +msgid "Exit after the engine has loaded" +msgstr "Saír despois de que se cargue o motor" + +#. TRANSLATORS: Suffix: the fallback HSI result +#. TRANSLATORS: The update state of the specific device +msgid "Failed" +msgstr "Fallido" + +#. TRANSLATORS: dbx file failed to be applied as an update +msgid "Failed to apply update" +msgstr "Produciuse un fallo ao aplicar a actualización" + +#. TRANSLATORS: we could not talk to the fwupd daemon +msgid "Failed to connect to daemon" +msgstr "Produciuse un fallo ao conectarse ao demoni" + +#. TRANSLATORS: we could not get the devices to update offline +msgid "Failed to get pending devices" +msgstr "Produciuse un fallo ao obter a lista de dispositivos pendentes" + +#. TRANSLATORS: we could not install for some reason +msgid "Failed to install firmware update" +msgstr "Produciuse un fallo ao instalar a actualización do firmware" + +#. TRANSLATORS: could not read existing system data +#. TRANSLATORS: could not read file +msgid "Failed to load local dbx" +msgstr "Produciuse un fallo ao cargar o dbx local" + +#. TRANSLATORS: could not read existing system data +msgid "Failed to load system dbx" +msgstr "Produciuse un fallo ao cargar o dbx do sistema" + +#. TRANSLATORS: the user didn't read the man page +msgid "Failed to parse arguments" +msgstr "Produciuse un fallo ao analizar os argumentos" + +#. TRANSLATORS: failed to read measurements file +msgid "Failed to parse file" +msgstr "Produciuse un fallo ao analizar o ficheiro" + +#. TRANSLATORS: the user didn't read the man page +msgid "Failed to parse flags for --filter" +msgstr "Produciuse un fallo ao analizar as bandeiras para --filter" + +#. TRANSLATORS: could not parse file +msgid "Failed to parse local dbx" +msgstr "Produciuse un fallo ao analizar a dbx local" + +#. TRANSLATORS: we could not reboot for some reason +msgid "Failed to reboot" +msgstr "Produciuse un fallo ao reiniciar" + +#. TRANSLATORS: we could not talk to plymouth +msgid "Failed to set splash mode" +msgstr "Produciuse un fallo ao modo splash" + +#. TRANSLATORS: something with a blocked hash exists +#. * in the users ESP -- which would be bad! +msgid "Failed to validate ESP contents" +msgstr "Produciuse un fallo ao validar os contidos do ESP" + +#. TRANSLATORS: user did not include a filename parameter +msgid "Filename required" +msgstr "Requírese un nome de ficheiro" + +#. TRANSLATORS: program name +msgid "Firmware Agent" +msgstr "Axente do firmware" + +#. TRANSLATORS: program summary +msgid "Firmware Update D-Bus Service" +msgstr "Servizo D-Bus da Actualización do Firmware" + +#. TRANSLATORS: program name +msgid "Firmware Update Daemon" +msgstr "Demonio de Actualización de Firmware" + +#. TRANSLATORS: program name +msgid "Firmware Utility" +msgstr "Utilidade de Firmware" + +#. TRANSLATORS: Title: if firmware updates are available +msgid "Firmware updates" +msgstr "Actualizacións de firmware" + +msgid "Firmware updates are not supported on this machine." +msgstr "Esta máquina non admite as actualizacións de firmware." + +msgid "Firmware updates are supported on this machine." +msgstr "Esta máquina admite as actualizacións de firmware." + +msgid "Force the action ignoring all warnings" +msgstr "Forzar a acción ignorando todas as advertencias" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Atopado" + +#. TRANSLATORS: command description +msgid "Get all device flags supported by fwupd" +msgstr "Obter todas as bandeiras de dispositivos admitidos por fwupd" + +#. TRANSLATORS: command description +msgid "Get all devices and possible releases" +msgstr "Obter todos os dispositivos e publicacións posíbeis" + +#. TRANSLATORS: command description +msgid "Get all devices that support firmware updates" +msgstr "Obtén todos os dispositivos que admiten actualizacións de firmware" + +#. TRANSLATORS: command description +msgid "Get all enabled plugins registered with the system" +msgstr "Obter todos os engadidos activos rexistrados no sistema" + +#. TRANSLATORS: command description +msgid "Gets details about a firmware file" +msgstr "Obtén a información sobre o ficheiro de firmware" + +#. TRANSLATORS: command description +msgid "Gets the configured remotes" +msgstr "Obten os remotos configurados" + +#. TRANSLATORS: command description +msgid "Gets the host security attributes" +msgstr "Obtén os atributos de seguranza do equipo" + +#. TRANSLATORS: command description +msgid "Gets the list of updates for connected hardware" +msgstr "Obtén a lista de actualizacións para o hardware conectado" + +#. TRANSLATORS: this is a string like 'HSI:2-U' +msgid "Host Security ID:" +msgstr "ID de seguranza do equipo:" + +#. TRANSLATORS: Title: +#. https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit +msgid "IOMMU" +msgstr "IOMMU" + +#. TRANSLATORS: daemon is inactive +msgid "Idle…" +msgstr "Ocioso…" + +#. TRANSLATORS: command description +msgid "Install a firmware blob on a device" +msgstr "Instalar un blob de firmware nun dispositivo" + +#. TRANSLATORS: command description +msgid "Install a firmware file on this hardware" +msgstr "Instalar un ficheiro de firmware neste hardware" + +msgid "Install old version of system firmware" +msgstr "Instalar unha versión antiga do firmware do sistema" + +msgid "Install signed device firmware" +msgstr "Instalar firmware de dispositivo asinado" + +msgid "Install signed system firmware" +msgstr "Instalar firmware do sistema asinado" + +msgid "Install unsigned device firmware" +msgstr "Instalar firmware de dispositivo non asinado" + +msgid "Install unsigned system firmware" +msgstr "Instalar firmware do sistema non asinado" + +#. TRANSLATORS: console message when no Plymouth is installed +msgid "Installing Firmware…" +msgstr "Instalando Firmware…" + +#. TRANSLATORS: this is shown when updating the firmware after the reboot +msgid "Installing firmware update…" +msgstr "Instalando actualización do firmware…" + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing on %s…" +msgstr "Instalando en %s…" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel +msgid "Intel BootGuard" +msgstr "Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * ACM means to verify the integrity of Initial Boot Block +msgid "Intel BootGuard ACM protected" +msgstr "ACM protexido Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * error policy is what to do on failure +msgid "Intel BootGuard error policy" +msgstr "Política de erro de Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * verified boot refers to the way the boot process is verified +msgid "Intel BootGuard verified boot" +msgstr "Arrinque verificado de Intel BootGuard" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * active means being used by the OS +msgid "Intel CET Active" +msgstr "Intel CET activo" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * enabled means supported by the processor +msgid "Intel CET Enabled" +msgstr "Intel CET activado" + +#. TRANSLATORS: Title: Direct Connect Interface (DCI) allows +#. * debugging of Intel processors using the USB3 port +msgid "Intel DCI debugger" +msgstr "Depurador de Intel DCI" + +#. TRANSLATORS: Title: SMAP = Supervisor Mode Access Prevention +msgid "Intel SMAP" +msgstr "SMAP de Intel" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Invalid" +msgstr "Non válido" + +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Falta menos dun minuto" + +msgid "Linux Vendor Firmware Service (stable firmware)" +msgstr "Servizo de Linux Vendor Firmware (firmware estábel)" + +msgid "Linux Vendor Firmware Service (testing firmware)" +msgstr "Servizo de Linux Vendor Firmware (firmware de probas)" + +#. TRANSLATORS: Title: if it's tainted or not +msgid "Linux kernel" +msgstr "Núcleo de Linux" + +#. TRANSLATORS: Title: lockdown is a security mode of the kernel +msgid "Linux kernel lockdown" +msgstr "Bloqueo de kernel de Linux" + +#. TRANSLATORS: Title: swap space or swap partition +msgid "Linux swap" +msgstr "Swap de Linux" + +#. TRANSLATORS: command line option +msgid "List entries in dbx" +msgstr "Mostrar as entradas no dbx" + +#. TRANSLATORS: command line option +msgid "List supported firmware updates" +msgstr "Mostrar actualizacións de firmware compatíbeis" + +#. TRANSLATORS: command description +msgid "List the available firmware types" +msgstr "Lista todos os tipos de firmware dispoñíbeis" + +#. TRANSLATORS: parsing the firmware information +msgid "Loading…" +msgstr "Cargando…" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Locked" +msgstr "Bloqueado" + +#. TRANSLATORS: Title: MEI = Intel Management Engine +msgid "MEI manufacturing mode" +msgstr "Modo de fabricación MEI" + +#. TRANSLATORS: Title: MEI = Intel Management Engine, and the +#. * "override" is the physical PIN that can be driven to +#. * logic high -- luckily it is probably not accessible to +#. * end users on consumer boards +msgid "MEI override" +msgstr "Omitir MEI" + +msgid "MEI version" +msgstr "Versión do MEI" + +#. TRANSLATORS: command line option +msgid "Manually enable specific plugins" +msgstr "Activar manualmente engadidos específicos" + +msgid "Modify a configured remote" +msgstr "Modificar un remoto configuración" + +msgid "Modify daemon configuration" +msgstr "Modificación configuración do demonio" + +#. TRANSLATORS: command description +msgid "Monitor the daemon for events" +msgstr "Monitorizar eventos no demonio" + +#. TRANSLATORS: user did not tell the tool what to do +msgid "No action specified!" +msgstr "Non se require ningunha acción!" + +#. TRANSLATORS: nothing found +msgid "No firmware IDs found" +msgstr "Non se atoparon IDs de firmware" + +#. TRANSLATORS: nothing found +msgid "No plugins found" +msgstr "Non se atoparon engadidos" + +#. TRANSLATORS: no repositories to download from +msgid "No releases available" +msgstr "Non hai publicacións dispoñíbeis" + +#. TRANSLATORS: no repositories to download from +msgid "No remotes available" +msgstr "Non hai remotos dispoñíbeis" + +#. TRANSLATORS: nothing was updated offline +msgid "No updates were applied" +msgstr "Non se aplicou ningunha actualización" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Not found" +msgstr "Non atopado" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Not supported" +msgstr "Non compatíbel" + +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "OK" + +#. TRANSLATORS: command line option +msgid "Only show single PCR value" +msgstr "Mostrar só un valor de PCR" + +#. TRANSLATORS: command line option +msgid "Override the default ESP path" +msgstr "Sobrescribir a ruta predefinida do ESP" + +#. TRANSLATORS: command line option +msgid "Override warnings and force the action" +msgstr "Omitir avisos e forzar a acción" + +#. TRANSLATORS: command description +msgid "Parse and show details about a firmware file" +msgstr "Analixar e mostrar a información dun ficheiro de firmware" + +#. TRANSLATORS: reading new dbx from the update +msgid "Parsing dbx update…" +msgstr "Analizando a dbx de actualizacións…" + +#. TRANSLATORS: reading existing dbx from the system +msgid "Parsing system dbx…" +msgstr "Analizando o dbx do sistema…" + +#. TRANSLATORS: console message when not using plymouth +msgid "Percentage complete" +msgstr "Porcentaxe completado" + +#. TRANSLATORS: Title: DMA as in https://en.wikipedia.org/wiki/DMA_attack +msgid "Pre-boot DMA protection" +msgstr "Protección de DMA pre-arrinque" + +msgid "Print the version number" +msgstr "Imprime o número de versión" + +msgid "Print verbose debug statements" +msgstr "Imprime as sentencias de depuración verbosas" + +msgid "Proceed with upload?" +msgstr "Desexa seguir coa subida?" + +#. TRANSLATORS: command line option +msgid "Query for firmware update support" +msgstr "Consultar compatibilidade da actualización do firmware" + +#. TRANSLATORS: command description +msgid "Read a firmware blob from a device" +msgstr "Ler un blob de firmware desde un dispositivo" + +#. TRANSLATORS: command description +msgid "Read firmware from device into a file" +msgstr "Ler firmware desde o dispositivo nun ficheiro" + +#. TRANSLATORS: command description +msgid "Read firmware from one partition into a file" +msgstr "Ler firmware desde unha partición nun ficheiro" + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Reading from %s…" +msgstr "Lendo de %s…" + +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "Lendo…" + +#. TRANSLATORS: console message when not using plymouth +msgid "Rebooting…" +msgstr "Reiniciando…" + +#. TRANSLATORS: command description +msgid "Refresh metadata from remote server" +msgstr "Actualiza os metadatos desde un servidor remoto" + +#. TRANSLATORS: command description +msgid "Reinstall firmware on a device" +msgstr "Reinstalar firmware nun dispositivo" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second is a version number +#. * e.g. "1.2.3" +#, c-format +msgid "Reinstalling %s with %s... " +msgstr "Reinstalando %s con %s... " + +#. TRANSLATORS: command description +msgid "Replace data in an existing firmware file" +msgstr "Substituír datos nun ficheiro de firmware existente" + +#. TRANSLATORS: metadata is downloaded from the Internet +msgid "Requires internet connection" +msgstr "Require conexión a internet" + +#. TRANSLATORS: configuration changes only take effect on restart +msgid "Restart the daemon to make the change effective?" +msgstr "Desexa reiniciar o demonio para facer o cambio efectivo?" + +#. TRANSLATORS: restarting the device to pick up new F/W +msgid "Restarting device…" +msgstr "Reiniciando dispositivo…" + +#. TRANSLATORS: command description +msgid "Return all the hardware IDs for the machine" +msgstr "Devolve todos os IDs do hardware da máquina" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI BIOS region" +msgstr "Rexión da BIOS Do SPI" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI lock" +msgstr "Bloqueo do SPI" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI write" +msgstr "Escritura do SPI" + +#. TRANSLATORS: scheduling an update to be done on the next boot +msgid "Scheduling…" +msgstr "Planificando…" + +#. TRANSLATORS: Device has been chosen by the daemon for the user +msgid "Selected device" +msgstr "Seleccionar un dispositivo" + +#. TRANSLATORS: Volume has been chosen by the user +msgid "Selected volume" +msgstr "Volume seleccionado" + +#. TRANSLATORS: command line option +msgid "Set the debugging flag during update" +msgstr "Establecer a bandeira de depuración durante a actualización" + +#. TRANSLATORS: firmware approved by the admin +msgid "Sets the list of approved firmware" +msgstr "Estabelece a lista do firmware aprobado" + +#. TRANSLATORS: command line option +msgid "Show client and daemon versions" +msgstr "Mostrar as versións de cliente e demonio" + +#. TRANSLATORS: for the --verbose arg +msgid "Show debugging options" +msgstr "Mostrar opcións de depuración" + +#. TRANSLATORS: command line option +msgid "Show devices that are not updatable" +msgstr "Mostrar os dispositivos que non son actualizábeis" + +#. TRANSLATORS: command line option +msgid "Show extra debugging information" +msgstr "Mostrar información de depuración adicional" + +#. TRANSLATORS: command description +msgid "Show history of firmware updates" +msgstr "Mostrar o historial das actualizacións de firmware" + +#. TRANSLATORS: this is for plugin development +msgid "Show plugin verbose information" +msgstr "Mostrar información de depuración do engadido" + +#. TRANSLATORS: command line option +msgid "Show the calculated version of the dbx" +msgstr "Mostrar a versión calculada do dbx" + +#. TRANSLATORS: command line option +msgid "Show the debug log from the last attempted update" +msgstr "Mostrar rexistro de depuración desde o último intento de actualización" + +#. TRANSLATORS: command line option +msgid "Show the information of firmware update status" +msgstr "Mostrar a información de estado da actualización do firmware" + +msgid "Sign data using the client certificate" +msgstr "Asinar os datos usando o certificafo do cliente" + +msgctxt "command-description" +msgid "Sign data using the client certificate" +msgstr "Asinar os datos usando o certificafo do cliente" + +msgid "Signature" +msgstr "Sinatura" + +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Especifique os IDs do Fabricante/Produto do dispositivo DFU" + +#. TRANSLATORS: command line option +msgid "Specify the dbx database file" +msgstr "Especificar o ficheiro de base de datos dbx" + +msgid "Specify the number of bytes per USB transfer" +msgstr "Especifique o número de bytes por transferenvia USB" + +#. TRANSLATORS: success message +msgid "Successfully disabled remote" +msgstr "Remoto desactivado correctamente" + +#. TRANSLATORS: success message +msgid "Successfully enabled remote" +msgstr "Remoto activado correctamente" + +#. TRANSLATORS: success message +msgid "Successfully installed firmware" +msgstr "Instalación do firmware exitosa" + +#. TRANSLATORS: success message for a per-remote setting change +msgid "Successfully modified remote" +msgstr "Remoto modficado correctamente" + +#. TRANSLATORS: success message when user verified device checksums +msgid "Successfully verified device checksums" +msgstr "Comprobáronse correctamente as sumas de verificación do dispositivo" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Supported" +msgstr "Compatíbel" + +#. TRANSLATORS: Title: a better sleep state +msgid "Suspend-to-idle" +msgstr "Suspend-a-ocioso" + +#. TRANSLATORS: Title: sleep state +msgid "Suspend-to-ram" +msgstr "Suspender-a-ram" + +#. TRANSLATORS: Title: the PCR is rebuilt from the TPM event log +msgid "TPM PCR0 reconstruction" +msgstr "Reconstrución do PCR0 de TPM" + +#. TRANSLATORS: Title: TPM = Trusted Platform Module +msgid "TPM v2.0" +msgstr "TPM v2.0" + +msgid "Target" +msgstr "Obxectivo" + +#. TRANSLATORS: do not translate the variables marked using $ +msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." +msgstr "O LVFS é o servizo que opera como unha entidade legal independente e non ten ligazón con $OS_RELEASE:NAME$. O seu distribuidor podería non ter que comprobar se as actualizacións de firmware teñen compatibilidade co seu sistema ou dispositivos conectados. Todos os firmware son fornecidos por fabricantes de equipamento orixinal." + +#. TRANSLATORS: we're poking around as a power user +msgid "This program may only work correctly as root" +msgstr "Este programa podería funcionar correctamente só como root" + +#. TRANSLATORS: the user needs to stop playing with stuff +msgid "This tool can only be used by the root user" +msgstr "Esta ferrametne só pode ser usada por un usuario root" + +#. TRANSLATORS: program name +msgid "UEFI Firmware Utility" +msgstr "Utilidade de firmware de UEFI" + +#. TRANSLATORS: program name +msgid "UEFI dbx Utility" +msgstr "Utilidade UEFI dbx" + +#. TRANSLATORS: Title: SB is a way of locking down UEFI +msgid "UEFI secure boot" +msgstr "Arrinque seguro de UEFI" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Unencrypted" +msgstr "Descifrado" + +#. TRANSLATORS: current daemon status is unknown +#. TRANSLATORS: we don't know the license of the update +#. TRANSLATORS: unknown release urgency +msgid "Unknown" +msgstr "Descoñecido" + +msgid "Unlock the device to allow access" +msgstr "Desbloquear o dispositivo para permitir o acceso" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Unlocked" +msgstr "Desbloqueado" + +#. TRANSLATORS: command line option +msgid "Unset the debugging flag during update" +msgstr "Quitar a bandeira de depuración durante a actualización" + +#. TRANSLATORS: command description +msgid "Update all devices that match local metadata" +msgstr "Actualizar todos os dispositivos que coincidan os metadatos locais" + +#. TRANSLATORS: ask the user if we can update the metadata +msgid "Update now?" +msgstr "Actualizar agora" + +msgid "Update the stored device verification information" +msgstr "Actualizar a información de verificación almacenada no dispositivo" + +#. TRANSLATORS: command description +msgid "Update the stored metadata with current contents" +msgstr "Actualizaar os metadatos almacenados cos contidos actuais" + +msgid "Updating" +msgstr "Actualizando" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Updating %s from %s to %s... " +msgstr "Actualizando %s desde %s a %s... " + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "Actualizando %s…" + +#. TRANSLATORS: ask the user to upload +msgid "Upload report now?" +msgstr "Desexa subir o informe agora?" + +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdtool --help for help" +msgstr "Usar fwupdtool --help para obter axuda" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Valid" +msgstr "Válido" + +#. TRANSLATORS: ESP refers to the EFI System Partition +msgid "Validating ESP contents…" +msgstr "Validando os contidos do ESP…" + +#. TRANSLATORS: verifying we wrote the firmware correctly +msgid "Verifying…" +msgstr "Verificando…" + +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Versión" + +#. TRANSLATORS: waiting for device to do something +msgid "Waiting…" +msgstr "Agardando…" + +#. TRANSLATORS: command description +msgid "Watch for hardware changes" +msgstr "Facer seguimento dos cambios de hardware" + +#. TRANSLATORS: command description +msgid "Write firmware from file into device" +msgstr "Escribir firmware desde un ficheiro nun dispositivo" + +#. TRANSLATORS: command description +msgid "Write firmware from file into one partition" +msgstr "Escribir firmware desde un ficheiro nunha partición" + +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "Escribindo…" + +#. TRANSLATORS: program name +msgid "fwupd TPM event log utility" +msgstr "Utilidade de rexistro de eventos de TPM de fwupd" + +#. TRANSLATORS: Title: if the fwupd plugins are all present and correct +msgid "fwupd plugins" +msgstr "Engadidos de fwupd" diff -Nru fwupd-1.4.5/po/he.po fwupd-1.5.8/po/he.po --- fwupd-1.4.5/po/he.po 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/po/he.po 2021-03-31 20:08:32.000000000 +0000 @@ -41,6 +41,7 @@ msgid "Description" msgstr "תיאור" +#. TRANSLATORS: success #. success msgid "Done!" msgstr "הסתיים!" @@ -88,6 +89,10 @@ msgid "No hardware detected with firmware update capability" msgstr "לא אותרה חומרה בעלת יכולת עדכון קושחה" +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "אישור" + #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second is a version number #. * e.g. "1.2.3" @@ -109,3 +114,7 @@ #, c-format msgid "Updating %s from %s to %s... " msgstr "מעדכן %s מ־%s ל־%s..." + +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "גרסא" diff -Nru fwupd-1.4.5/po/hr.po fwupd-1.5.8/po/hr.po --- fwupd-1.4.5/po/hr.po 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/po/hr.po 2021-03-31 20:08:32.000000000 +0000 @@ -5,6 +5,7 @@ # Translators: # FIRST AUTHOR , 2016 # gogo , 2016 +# milotype , 2020 # gogo , 2016-2020 msgid "" msgstr "" @@ -31,6 +32,12 @@ msgid "%s CPU Microcode Update" msgstr "%s nadopuna CPU mikrokôda" +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Secure Boot` +#, c-format +msgid "%s Configuration Update" +msgstr "%s nadopuna podešavanja" + #. TRANSLATORS: ME stands for Management Engine, where #. * the first %s is the device name, e.g. 'ThinkPad P50` #, c-format @@ -94,6 +101,11 @@ msgid "%s and all connected devices may not be usable while updating." msgstr "%s i svi spojeni uređaji možda neće biti upotrebljivi tijekom nadopune." +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s manufacturing mode" +msgstr "%s način rada za proizvođače" + #. TRANSLATORS: warn the user before updating, %1 is a device name #, c-format msgid "%s must remain connected for the duration of the update to avoid damage." @@ -104,6 +116,21 @@ msgid "%s must remain plugged into a power source for the duration of the update to avoid damage." msgstr "%s mora ostati spojen s izvorom energije tijekom trajanja nadopune kako bi se izbjeglo oštećenje." +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s override" +msgstr "%s zaobilaženje" + +#. TRANSLATORS: Title: %1 is ME kind, e.g. CSME/TXT, %2 is a version number +#, c-format +msgid "%s v%s" +msgstr "%s v%s" + +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s version" +msgstr "%s inačica" + #. TRANSLATORS: duration in days! #, c-format msgid "%u day" @@ -151,6 +178,10 @@ msgstr[1] "%u sekunde" msgstr[2] "%u sekundi" +#. TRANSLATORS: this is shown as a suffix for obsoleted tests +msgid "(obsoleted)" +msgstr "(zastarjelo)" + #. TRANSLATORS: command description msgid "Activate devices" msgstr "Aktiviraj uređaj" @@ -170,10 +201,6 @@ msgid "Activating firmware update for" msgstr "Aktivacija nadopune firmvera za" -#. TRANSLATORS: this is when a device is hotplugged -msgid "Added" -msgstr "Dodano" - #. TRANSLATORS: the age of the metadata msgid "Age" msgstr "Dob" @@ -195,6 +222,10 @@ msgid "Allow reinstalling existing firmware versions" msgstr "Dopusti ponovnu instalaciju firmvera postojeće inačice" +#. TRANSLATORS: command line option +msgid "Allow switching firmware branch" +msgstr "Dopusti prebacivanje između firmver grana" + #. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Nadopuna zahtijeva ponovno pokretanje za završetak." @@ -211,6 +242,18 @@ msgid "Apply firmware updates" msgstr "Primijeni nadopune firmvera" +#. TRANSLATORS: command line option +msgid "Apply update even when not advised" +msgstr "Primijeni nadopunu iako nije preporučljivo" + +#. TRANSLATORS: command line option +msgid "Apply update files" +msgstr "Primijeni nadopunu datoteka" + +#. TRANSLATORS: actually sending the update to the hardware +msgid "Applying update…" +msgstr "Primjena nadopuna…" + #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator msgid "Approved firmware:" @@ -219,6 +262,10 @@ msgstr[1] "Odobreni firmveri:" msgstr[2] "Odobreni firmveri:" +#. TRANSLATORS: stop nagging the user +msgid "Ask again next time?" +msgstr "Upitaj ponovno sljedeći put?" + #. TRANSLATORS: command description msgid "Attach to firmware mode" msgstr "Prebaci u način firmvera" @@ -275,10 +322,38 @@ msgid "Automatic Reporting" msgstr "Automatsko izvještavanje" +#. TRANSLATORS: can we JFDI? +msgid "Automatically upload every time?" +msgstr "Automatski pošalji svaki put?" + +#. TRANSLATORS: command description +msgid "Bind new kernel driver" +msgstr "Spoji novi pogon jezgre" + +#. TRANSLATORS: there follows a list of hashes +msgid "Blocked firmware files:" +msgstr "Datoteke blokiranog firmvera:" + +#. TRANSLATORS: we will not offer this firmware to the user +msgid "Blocking firmware:" +msgstr "Blokiranje firmvera:" + +#. TRANSLATORS: command description +msgid "Blocks a specific firmware from being installed" +msgstr "Blokira instalaciju određenog firmvera" + #. TRANSLATORS: firmware version of bootloader msgid "Bootloader Version" msgstr "Inačica učitača pokretanja" +#. TRANSLATORS: the stream of firmware, e.g. nonfree or open-source +msgid "Branch" +msgstr "Grana" + +#. TRANSLATORS: command description +msgid "Build a firmware file" +msgstr "Izgradi datoteku firmvera" + #. TRANSLATORS: command description msgid "Build firmware using a sandbox" msgstr "Izgradi firmver u osiguranom okruženju" @@ -291,7 +366,14 @@ msgid "Cancelled" msgstr "Prekinuto" -#. TRANSLATORS: this is when a device is hotplugged +#. TRANSLATORS: same or newer update already applied +msgid "Cannot apply as dbx update has already been applied." +msgstr "Nemoguća primjena kao dbx nadopune jer je već primijenjeno." + +#. TRANSLATORS: the user is using a LiveCD or LiveUSB install disk +msgid "Cannot apply updates on live media" +msgstr "Nemoguća primjena na live medij" + #. TRANSLATORS: this is when the daemon state changes msgid "Changed" msgstr "Promijenjeno" @@ -304,6 +386,11 @@ msgid "Checksum" msgstr "Kontrolni zbroj" +#. TRANSLATORS: get interactive prompt, where branch is the +#. * supplier of the firmware, e.g. "non-free" or "free" +msgid "Choose a branch:" +msgstr "Odaberi granu:" + #. TRANSLATORS: get interactive prompt msgid "Choose a device:" msgstr "Odaberite uređaj:" @@ -316,6 +403,10 @@ msgid "Choose a release:" msgstr "Odaberi izdanje:" +#. TRANSLATORS: get interactive prompt +msgid "Choose a volume:" +msgstr "Odaberite uređaj:" + #. TRANSLATORS: command description msgid "Clears any updates scheduled to be updated offline" msgstr "Uklanja sve nadopune zakazne za izvanmrežno nadopunjivanje" @@ -420,10 +511,18 @@ msgid "Device stages updates" msgstr "Nadopune uređaja u fazama" +#. TRANSLATORS: there is more than one supplier of the firmware +msgid "Device supports switching to a different branch of firmware" +msgstr "Uređaj podržava mijenjanje na jednu drugu granu firmvera" + #. TRANSLATORS: Device update needs to be separately activated msgid "Device update needs activation" msgstr "Nadopuni uređaja je potrebna aktivacija" +#. TRANSLATORS: save the old firmware to disk before installing the new one +msgid "Device will backup firmware before installing" +msgstr "Uređaj će spremiti sigurnosnu kopiju firmvera prije instaliranja" + #. TRANSLATORS: Device will not return after update completes msgid "Device will not re-appear after update completes" msgstr "Uređaj se neće ponovno pojaviti nakon završetka nadopune" @@ -436,6 +535,20 @@ msgid "Devices that were not updated correctly:" msgstr "Uređaji koji nisu ispravno nadopunjeni:" +#. TRANSLATORS: message letting the user know no device upgrade available due +#. to missing on LVFS +msgid "Devices with no available firmware updates: " +msgstr "Uređaji bez dostupnih nadopuna firmvera: " + +#. TRANSLATORS: message letting the user know no device upgrade available +msgid "Devices with the latest available firmware version:" +msgstr "Uređaji s najnovijom dostupnom inačicom firmvera:" + +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is inactive and not used +msgid "Disabled" +msgstr "Onemogućeno" + msgid "Disabled fwupdate debugging" msgstr "Onemogući fwupdate otklanjanje grešaka" @@ -487,6 +600,11 @@ msgid "Do not write to the history database" msgstr "Ne zapisuj bazu podataka povijesti" +#. TRANSLATORS: should the branch be changed +msgid "Do you understand the consequences of changing the firmware branch?" +msgstr "Razumiješ li posljedice mijenjanja grane firmvera?" + +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Završeno!" @@ -531,6 +649,8 @@ msgid "Enable this remote?" msgstr "Omogući ovu udaljenu lokaciju?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Omogućeno" @@ -549,6 +669,14 @@ msgid "Enabling this remote is done at your own risk." msgstr "Ovu udaljenu lokaciju omogućavate na vlastiti rizik." +#. TRANSLATORS: Suffix: the HSI result +msgid "Encrypted" +msgstr "Šifrirano" + +#. TRANSLATORS: Title: Memory contents are encrypted, e.g. Intel TME +msgid "Encrypted RAM" +msgstr "Šifrirani RAM" + #. TRANSLATORS: command description msgid "Erase all firmware update history" msgstr "Obriši svu povijest nadopune firmvera" @@ -565,14 +693,23 @@ msgid "Exit after the engine has loaded" msgstr "Izađi nakon učitavanja pogona" +#. TRANSLATORS: command description +msgid "Extract a firmware blob to images" +msgstr "Izdvoji blob firmvera u slike" + +#. TRANSLATORS: Suffix: the fallback HSI result +#. TRANSLATORS: The update state of the specific device +msgid "Failed" +msgstr "Neuspjelo" + +#. TRANSLATORS: dbx file failed to be applied as an update +msgid "Failed to apply update" +msgstr "Neuspjela primjena nadopune" + #. TRANSLATORS: we could not talk to the fwupd daemon msgid "Failed to connect to daemon" msgstr "Neuspjelo povezivanje s pozadinskim programom" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "Neuspjelo preuzimanje zbog ograničenja poslužitelja" - #. TRANSLATORS: we could not get the devices to update offline msgid "Failed to get pending devices" msgstr "Neuspjeli prikaz uređaja na čekanju" @@ -581,10 +718,19 @@ msgid "Failed to install firmware update" msgstr "Neuspjela instalacija nadopune firmvera" +#. TRANSLATORS: could not read existing system data +#. TRANSLATORS: could not read file +msgid "Failed to load local dbx" +msgstr "Neuspjelo učitavanje lokalnog dbx-a" + #. TRANSLATORS: quirks are device-specific workarounds msgid "Failed to load quirks" msgstr "Neuspjelo učitavanje okolnosti uređaja" +#. TRANSLATORS: could not read existing system data +msgid "Failed to load system dbx" +msgstr "Neuspjelo učitavanje dbx-a sustava" + #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Neuspjela obrada argumenata" @@ -597,6 +743,10 @@ msgid "Failed to parse flags for --filter" msgstr "Neuspjela obrada oznake za --filter" +#. TRANSLATORS: could not parse file +msgid "Failed to parse local dbx" +msgstr "Neuspjela obrada lokalnog dbx-a" + #. TRANSLATORS: we could not reboot for some reason msgid "Failed to reboot" msgstr "Neuspjelo ponovno pokretanje" @@ -605,21 +755,10 @@ msgid "Failed to set splash mode" msgstr "Neuspjelo postavljanje splash načina" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "Dohvaćanje datoteke" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "Dohvaćanje firmvera" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "Dohvaćanje metapodataka" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "Dohvaćanje potpisa" +#. TRANSLATORS: something with a blocked hash exists +#. * in the users ESP -- which would be bad! +msgid "Failed to validate ESP contents" +msgstr "Neuspjela provjera ESP sadržaja" #. TRANSLATORS: filename of the local file msgid "Filename" @@ -629,6 +768,10 @@ msgid "Filename Signature" msgstr "Potpis naziva datoteke" +#. TRANSLATORS: user did not include a filename parameter +msgid "Filename required" +msgstr "Potreban je naziv datoteke" + #. TRANSLATORS: command line option msgid "Filter with a set of device flags using a ~ prefix to exclude, e.g. 'internal,~needs-reboot'" msgstr "Filter sa skupom oznaka uređaja koji koristi ~ prefiks za izuzimanje, npr. 'internal,~needs-reboot'" @@ -653,6 +796,22 @@ msgid "Firmware Utility" msgstr "Firmver pomagalo" +#. TRANSLATORS: Title: if we can verify the firmware checksums +msgid "Firmware attestation" +msgstr "Frimver provjera" + +#. TRANSLATORS: system is not booted in UEFI mode +msgid "Firmware can not be updated in legacy BIOS mode" +msgstr "Firmver se ne može aktualizirati u starom BIOS modusu" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is already blocked" +msgstr "Firmver je već blokiran" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is not already blocked" +msgstr "Firmver još nije blokiran" + #. TRANSLATORS: the metadata is very out of date; %u is a number > 1 #, c-format msgid "Firmware metadata has not been updated for %u day and may not be up to date." @@ -661,25 +820,47 @@ msgstr[1] "Metapodaci firmvera nisu nadopunjeni %u dana i možda nisu najnoviji." msgstr[2] "Metapodaci firmvera nisu nadopunjeni %u dana i možda nisu najnoviji." +#. TRANSLATORS: Title: if firmware updates are available +msgid "Firmware updates" +msgstr "Nadopune frimvera" + msgid "Firmware updates are not supported on this machine." msgstr "Nadopuna firmvera nije podržana na ovom računalu." msgid "Firmware updates are supported on this machine." msgstr "Nadopuna firmvera je podržana na ovom računalu." +#. TRANSLATORS: user needs to run a command +msgid "Firmware updates disabled; run 'fwupdmgr unlock' to enable" +msgstr "Aktualiziranje firmvera je deaktivirano; aktiviraj ga pomoću „fwupdmgr unlock”" + +#. TRANSLATORS: description of plugin state, e.g. disabled #. TRANSLATORS: release properties msgid "Flags" msgstr "Oznake" +#. TRANSLATORS: command line option +msgid "Force the action by relaxing some runtime checks" +msgstr "Prisili radnju zanemarujući neke provjere vremena pokretanja" + msgid "Force the action ignoring all warnings" -msgstr "Prisili radnju zanemarivanja svih upozorenja" +msgstr "Prisili radnju zanemarujući sva upozorenja" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Pronađeno" #. TRANSLATORS: global ID common to all similar hardware msgid "GUID" msgid_plural "GUIDs" -msgstr[0] "GUID" -msgstr[1] "GUID" -msgstr[2] "GUID" +msgstr[0] "Globalna jedinstvena oznaka" +msgstr[1] "Globalne jedinstvene oznake" +msgstr[2] "Globalne jedinstvene oznake" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgctxt "A single GUID" +msgid "GUID" +msgstr "GUID" #. TRANSLATORS: command description msgid "Get all device flags supported by fwupd" @@ -705,9 +886,17 @@ msgid "Gets the configured remotes" msgstr "Prikazuje udaljena podešavanja" +#. TRANSLATORS: command description +msgid "Gets the host security attributes" +msgstr "Prikaži sigurnosne značajke poslužitelja" + #. TRANSLATORS: firmware approved by the admin -msgid "Gets the list of approved firmware." -msgstr "Preuzima popis odobrenih firmvera." +msgid "Gets the list of approved firmware" +msgstr "Preuzima popis odobrenih firmvera" + +#. TRANSLATORS: command description +msgid "Gets the list of blocked firmware" +msgstr "Preuzima popis blokiranih firmvera." #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" @@ -729,6 +918,15 @@ msgid "High" msgstr "Visoka" +#. TRANSLATORS: this is a string like 'HSI:2-U' +msgid "Host Security ID:" +msgstr "Sigurnosni ID poslužitelja:" + +#. TRANSLATORS: Title: +#. https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit +msgid "IOMMU" +msgstr "IOMMU" + #. TRANSLATORS: daemon is inactive msgid "Idle…" msgstr "Mirovanje..." @@ -737,10 +935,26 @@ msgid "Ignore SSL strict checks when downloading files" msgstr "Zanemari SSL ograničene provjere pri preuzimanju datoteka" +#. TRANSLATORS: command line option +msgid "Ignore firmware checksum failures" +msgstr "Zanemari neuspjele kontrolne zbrojeve firmvera" + +#. TRANSLATORS: command line option +msgid "Ignore firmware hardware mismatch failures" +msgstr "Zanemari neuspjela poklapanja hardvera firmvera" + +#. TRANSLATORS: command line option +msgid "Ignore requirement of external power source" +msgstr "Zanemari zahtjev vanjskog izvora energije" + #. TRANSLATORS: Ignore validation safety checks when flashing this device msgid "Ignore validation safety checks" msgstr "Zanemari provjeru sigurnosti uređaja" +#. TRANSLATORS: try to help +msgid "Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" +msgstr "Zanemaruju se stroge SSL provjere, da bi se to ubuduće automatski desilo izvezi DISABLE_SSL_STRICT u tvom okruženju" + #. TRANSLATORS: length of time the update takes to apply msgid "Install Duration" msgstr "Trajanje instalacije" @@ -785,10 +999,57 @@ msgid "Installing on %s…" msgstr "Instaliram na %s…" +#. TRANSLATORS: Title: BootGuard is a trademark from Intel +msgid "Intel BootGuard" +msgstr "Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * ACM means to verify the integrity of Initial Boot Block +msgid "Intel BootGuard ACM protected" +msgstr "Intel BootGuard ACM zaštićen" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * OTP = one time programmable +msgid "Intel BootGuard OTP fuse" +msgstr "Intel BootGuard OTP osigurač" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * error policy is what to do on failure +msgid "Intel BootGuard error policy" +msgstr "Intel BootGuard pravilo greške" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * verified boot refers to the way the boot process is verified +msgid "Intel BootGuard verified boot" +msgstr "Intel BootGuard provjereno pokretanje" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * active means being used by the OS +msgid "Intel CET Active" +msgstr "Intel CET aktivan" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * enabled means supported by the processor +msgid "Intel CET Enabled" +msgstr "Intel CET omogućen" + +#. TRANSLATORS: Title: Direct Connect Interface (DCI) allows +#. * debugging of Intel processors using the USB3 port +msgid "Intel DCI debugger" +msgstr "Intel DCI otklanatelj grešaka" + +#. TRANSLATORS: Title: SMAP = Supervisor Mode Access Prevention +msgid "Intel SMAP" +msgstr "Intel SMAP" + #. TRANSLATORS: Device cannot be removed easily msgid "Internal device" msgstr "Unutrašnji uređaj" +#. TRANSLATORS: Suffix: the HSI result +msgid "Invalid" +msgstr "Nevaljano" + #. TRANSLATORS: Is currently in bootloader mode msgid "Is in bootloader mode" msgstr "U načinu učitača pokretanja je" @@ -821,6 +1082,22 @@ msgid "Linux Vendor Firmware Service (testing firmware)" msgstr "Firmver Usluga Linux Proizvođača (LVFS) (testni firmver)." +#. TRANSLATORS: Title: if it's tainted or not +msgid "Linux kernel" +msgstr "Linux kernel" + +#. TRANSLATORS: Title: lockdown is a security mode of the kernel +msgid "Linux kernel lockdown" +msgstr "Linux kernel zaključavanje" + +#. TRANSLATORS: Title: swap space or swap partition +msgid "Linux swap" +msgstr "Linux swap" + +#. TRANSLATORS: command line option +msgid "List entries in dbx" +msgstr "Prikaži unose u dbx-u" + #. TRANSLATORS: command line option msgid "List supported firmware updates" msgstr "Prikaži nadopune podržanih firmvera" @@ -829,17 +1106,39 @@ msgid "List the available firmware types" msgstr "Prikaži dostupne vrste firmvera" +#. TRANSLATORS: command description +msgid "Lists files on the ESP" +msgstr "Nabraja datoteke na ESP-u" + #. TRANSLATORS: parsing the firmware information msgid "Loading…" msgstr "Učitavanje..." +#. TRANSLATORS: Suffix: the HSI result +msgid "Locked" +msgstr "Zaključano" + #. TRANSLATORS: the release urgency msgid "Low" msgstr "Niska" +#. TRANSLATORS: Title: MEI = Intel Management Engine +msgid "MEI manufacturing mode" +msgstr "MEI način rada za proizvođače" + +#. TRANSLATORS: Title: MEI = Intel Management Engine, and the +#. * "override" is the physical PIN that can be driven to +#. * logic high -- luckily it is probably not accessible to +#. * end users on consumer boards +msgid "MEI override" +msgstr "MEI zaobilaženje" + +msgid "MEI version" +msgstr "MEI inačica" + #. TRANSLATORS: command line option -msgid "Manually whitelist specific plugins" -msgstr "Ručno dopusti određene priključke" +msgid "Manually enable specific plugins" +msgstr "Ručno omogući određene priključke" #. TRANSLATORS: the release urgency msgid "Medium" @@ -867,8 +1166,8 @@ msgstr "Pozadinski program i klijent se ne podudaraju, umjesto koristite %s" #. TRANSLATORS: sets something in daemon.conf -msgid "Modifies a daemon configuration value." -msgstr "Prilagođava vrijednost podešavanja pozadinskog programa." +msgid "Modifies a daemon configuration value" +msgstr "Mijenja vrijednost konfiguracije demona" #. TRANSLATORS: command description msgid "Modifies a given remote" @@ -884,6 +1183,10 @@ msgid "Monitor the daemon for events" msgstr "Nadgledaj događaje pozadinskim programom" +#. TRANSLATORS: command description +msgid "Mounts the ESP" +msgstr "Montira ESP" + #. TRANSLATORS: Requires a reboot to apply firmware or to reload hardware msgid "Needs a reboot after installation" msgstr "Potrebno je ponovno pokretanje nakon instalacije" @@ -896,6 +1199,7 @@ msgid "New version" msgstr "Nova inačica" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "Nema zadane radnje!" @@ -933,15 +1237,23 @@ msgid "No updates were applied" msgstr "Nema primijenjenih nadopuna" +#. TRANSLATORS: Suffix: the HSI result +msgid "Not found" +msgstr "Nije pronađeno" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Not supported" +msgstr "Nije podržano" + +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "U redu" + #. TRANSLATORS: command line option msgid "Only show single PCR value" msgstr "Prikaži samo jednu PRC vrijednost" #. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Zaobiđi upozorenja priključka" - -#. TRANSLATORS: command line option msgid "Override the default ESP path" msgstr "Zaobiđi zadanu ESP putanju" @@ -953,10 +1265,21 @@ msgid "Parse and show details about a firmware file" msgstr "Analiziraj i prikaži pojedinosti datoteke firmvera" +#. TRANSLATORS: reading new dbx from the update +msgid "Parsing dbx update…" +msgstr "Obrada dbx nadopune…" + +#. TRANSLATORS: reading existing dbx from the system +msgid "Parsing system dbx…" +msgstr "Obrada dbx-a sustava…" + #. TRANSLATORS: remote filename base msgid "Password" msgstr "Lozinka" +msgid "Payload" +msgstr "Sadržaj prijenosa" + #. TRANSLATORS: console message when not using plymouth msgid "Percentage complete" msgstr "Postotak završetka" @@ -966,6 +1289,14 @@ msgid "Please enter a number from 0 to %u: " msgstr "Odaberite broj od 0 do %u: " +#. TRANSLATORS: Failed to open plugin, hey Arch users +msgid "Plugin dependencies missing" +msgstr "Nedostaju ovisnosti dodatka" + +#. TRANSLATORS: Title: DMA as in https://en.wikipedia.org/wiki/DMA_attack +msgid "Pre-boot DMA protection" +msgstr "DMA zaštita predpokretanja" + #. TRANSLATORS: version number of previous firmware msgid "Previous version" msgstr "Prijašnja inačica" @@ -1021,8 +1352,8 @@ msgstr "Osvježi metapodatke s udaljenog poslužitelja" #. TRANSLATORS: command description -msgid "Reinstall current firmware on the device." -msgstr "Ponovno instaliraj trenutni firmver na uređaju." +msgid "Reinstall current firmware on the device" +msgstr "Ponovno instaliraj trenutačni firmver na uređaj" #. TRANSLATORS: command description msgid "Reinstall firmware on a device" @@ -1040,10 +1371,6 @@ msgid "Remote ID" msgstr "Udaljeni ID" -#. TRANSLATORS: this is when a device is hotplugged -msgid "Removed" -msgstr "Uklonjeno" - #. TRANSLATORS: command description msgid "Replace data in an existing firmware file" msgstr "Zamijeni podatke u postojećoj datoteci firmvera" @@ -1056,9 +1383,13 @@ msgid "Reported to remote server" msgstr "Prijavljeno na udaljenom poslužitelju" -#. TRANSLATORS: Must be plugged in to an outlet -msgid "Requires AC power" -msgstr "Zahtijeva AC napajanje" +#. TRANSLATORS: the user is using Gentoo/Arch and has screwed something up +msgid "Required efivarfs filesystem was not found" +msgstr "Potrebni efivarfs datotečni sustav nije pronađen" + +#. TRANSLATORS: not required for this system +msgid "Required hardware was not found" +msgstr "Potrebni uređaj nije proneđen" #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user msgid "Requires a bootloader" @@ -1095,6 +1426,22 @@ msgid "Run the plugin composite prepare routine when using install-blob" msgstr "Pokreni rutinu pripreme sastavljanja priključka kada se koristi install-blob" +#. TRANSLATORS: this is the HSI suffix +msgid "Runtime Suffix" +msgstr "Sufiks vremenskog izvršavanja" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI BIOS region" +msgstr "SPI BIOS područje" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI lock" +msgstr "SPI zaključavanje" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI write" +msgstr "SPI zapisivanje" + #. TRANSLATORS: command line option msgid "Save device state into a JSON file between executions" msgstr "Spremi stanje uređaja u JSON datoteku između izvršavanja" @@ -1107,10 +1454,19 @@ msgid "Scheduling…" msgstr "Zakazivanje..." +#. TRANSLATORS: %s is a link to a website +#, c-format +msgid "See %s for more information." +msgstr "Pročitaj daljnje informacije na %s." + #. TRANSLATORS: Device has been chosen by the daemon for the user msgid "Selected device" msgstr "Odabrani uređaj" +#. TRANSLATORS: Volume has been chosen by the user +msgid "Selected volume" +msgstr "Odabrani uređaj" + #. TRANSLATORS: serial number of hardware msgid "Serial Number" msgstr "Serijski broj" @@ -1119,11 +1475,8 @@ msgid "Set the debugging flag during update" msgstr "Postavi oznaku otklanjanja grešaka tijekom nadopune" -msgid "Sets the list of approved firmware" -msgstr "Postavlja popis odobrenih firmvera" - #. TRANSLATORS: firmware approved by the admin -msgid "Sets the list of approved firmware." +msgid "Sets the list of approved firmware" msgstr "Postavlja popis odobrenih firmvera" #. TRANSLATORS: command description @@ -1131,6 +1484,10 @@ msgstr "Podijeli povijest firmvera sa razvijateljima" #. TRANSLATORS: command line option +msgid "Show all results" +msgstr "Prikaži sve rezultate" + +#. TRANSLATORS: command line option msgid "Show client and daemon versions" msgstr "Prikaži inačicu klijenta i pozadinskog programa" @@ -1163,6 +1520,10 @@ msgstr "Prikaži dodatne informacije priključka" #. TRANSLATORS: command line option +msgid "Show the calculated version of the dbx" +msgstr "Prikaži predviđenu inčicu DBX-a" + +#. TRANSLATORS: command line option msgid "Show the debug log from the last attempted update" msgstr "Prikaži zapis otklanjanja grešaka posljednjeg pokušaja nadopune" @@ -1199,6 +1560,10 @@ msgid "Specify Vendor/Product ID(s) of DFU device" msgstr "Odredi ID-ove Proizvođača/Proizvoda DFU uređaja" +#. TRANSLATORS: command line option +msgid "Specify the dbx database file" +msgstr "Odredi datoteku dbx baze podataka" + msgid "Specify the number of bytes per USB transfer" msgstr "Odredi broj bajtova po USB prijenosu" @@ -1257,10 +1622,42 @@ msgid "Summary" msgstr "Sažetak" +#. TRANSLATORS: Suffix: the HSI result +msgid "Supported" +msgstr "Podržano" + #. TRANSLATORS: Is found in current metadata msgid "Supported on remote server" msgstr "Podržano na udaljenom poslužitelju" +#. TRANSLATORS: Title: a better sleep state +msgid "Suspend-to-idle" +msgstr "Suspendiraju-u-mirovanje" + +#. TRANSLATORS: Title: sleep state +msgid "Suspend-to-ram" +msgstr "Suspendiraju-u-ram" + +#. TRANSLATORS: command description +msgid "Switch the firmware branch on the device" +msgstr "Zamijeni granu firmvera na uređaju" + +#. TRANSLATORS: Must be plugged in to an outlet +msgid "System requires external power source" +msgstr "Sustav zahtijeva vanjski izvor energije" + +#. TRANSLATORS: Title: the PCR is rebuilt from the TPM event log +msgid "TPM PCR0 reconstruction" +msgstr "TPM PCR0 rekonstrukcija" + +#. TRANSLATORS: Title: TPM = Trusted Platform Module +msgid "TPM v2.0" +msgstr "TPM v2.0" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Tainted" +msgstr "Pokvareno" + msgid "Target" msgstr "Odredište" @@ -1268,11 +1665,32 @@ msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "LVFS (Firmver Usluga Linux Proizvođača) je besplatna usluga koja djeluje kao neovisna pravna osoba i nema veze sa $OS_RELEASE:NAME$. Vaš distributer možda nije provjerio nadopune firmvera za kompatibilnost s vašim sustavom ili priključenim uređajima. Svi firmveri su pružani od strane izvornih proizvođača opreme." +#. TRANSLATORS: this is more background on a security measurement problem +msgid "The TPM PCR0 differs from reconstruction." +msgstr "TPM PCR0 razlikuje se od rekonstrukcije." + +#. TRANSLATORS: the user is SOL for support... +msgid "The daemon has loaded 3rd party code and is no longer supported by the upstream developers!" +msgstr "Demon je učitao strani kȏd i više ga ne podržavaju programeri izvorne grane!" + +#. TRANSLATORS: %1 is the firmware vendor, %2 is the device vendor name +#, c-format +msgid "The firmware from %s is not supplied by %s, the hardware vendor." +msgstr "Firmver od %s se ne isporučuje od %s, dobavljač hardvera." + +#. TRANSLATORS: nothing to show +msgid "There are no blocked firmware files" +msgstr "Nema blokiranih firmvera" + #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator msgid "There is no approved firmware." msgstr "Ne postoji odobreni firmver." +#. TRANSLATORS: unsupported build of the package +msgid "This package has not been validated, it may not work properly." +msgstr "Ovaj paket nije provjeren, možda neće ispravno raditi." + #. TRANSLATORS: we're poking around as a power user msgid "This program may only work correctly as root" msgstr "Ovaj program možda radi ispravno samo ako je pokrenut kao korijenski korisnik" @@ -1280,6 +1698,18 @@ msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "Ova udaljena lokacija sadrži firmver koji nije zabranjen, ali se još uvijek testira od strane proizvođača hardvera. Provjerite da imate način na ručno vraćanje starije inačice firmvera ako nadopuna firmvera ne uspije." +#. TRANSLATORS: this is instructions on how to improve the HSI suffix +msgid "This system has HSI runtime issues." +msgstr "Ovaj sustav ima HSI probleme s vremenskim izvršavanjem." + +#. TRANSLATORS: this is instructions on how to improve the HSI security level +msgid "This system has a low HSI security level." +msgstr "Ovaj sustav ima nisku HSI sigurnosnu razinu." + +#. TRANSLATORS: description of dbxtool +msgid "This tool allows an administrator to apply UEFI dbx updates." +msgstr "Ovaj alat omogućuje administratoru primjenu UEFI dbx nadopuna." + #. TRANSLATORS: the user needs to stop playing with stuff msgid "This tool can only be used by the root user" msgstr "Ovaj alat može koristiti samo korijenski korisnik" @@ -1288,10 +1718,42 @@ msgid "Type" msgstr "Vrsta" +#. TRANSLATORS: partition refers to something on disk, again, hey Arch users +msgid "UEFI ESP partition not detected or configured" +msgstr "UEFI ESP particija nije otkrivena ili konfigurirana" + #. TRANSLATORS: program name msgid "UEFI Firmware Utility" msgstr "UEFI firmver pomagalo" +#. TRANSLATORS: program name +msgid "UEFI dbx Utility" +msgstr "UEFI dbx pomagalo" + +#. TRANSLATORS: Title: SB is a way of locking down UEFI +msgid "UEFI secure boot" +msgstr "UEFI sigurno pokretanje (secure boot)" + +#. TRANSLATORS: error message +msgid "Unable to connect to service" +msgstr "Neuspjelo povezivanje s udaljenom uslugom" + +#. TRANSLATORS: command description +msgid "Unbind current driver" +msgstr "Odspoji trenutačni pogon" + +#. TRANSLATORS: we will now offer this firmware to the user +msgid "Unblocking firmware:" +msgstr "Neblokiranje firmvera:" + +#. TRANSLATORS: command description +msgid "Unblocks a specific firmware from being installed" +msgstr "Deblokira instalaciju određenog firmvera" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Unencrypted" +msgstr "Nije šifrirano" + #. TRANSLATORS: current daemon status is unknown #. TRANSLATORS: we don't know the license of the update #. TRANSLATORS: unknown release urgency @@ -1305,10 +1767,18 @@ msgid "Unlock the device to allow access" msgstr "Otključaj uređaj za dopuštenje pristupa" +#. TRANSLATORS: Suffix: the HSI result +msgid "Unlocked" +msgstr "Otključano" + #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "Otključava uređaj za pristup firmveru" +#. TRANSLATORS: command description +msgid "Unmounts the ESP" +msgstr "Demontira ESP" + #. TRANSLATORS: command line option msgid "Unset the debugging flag during update" msgstr "Ukloni oznaku otklanjanja grešaka tijekom nadopune" @@ -1318,6 +1788,10 @@ msgid "Unsupported daemon version %s, client version is %s" msgstr "Nepodržana inačica pozadinskog programa %s, inačica klijenta je %s" +#. TRANSLATORS: Suffix: the HSI result +msgid "Untainted" +msgstr "Ispravno" + #. TRANSLATORS: Device is updatable in this or any other mode msgid "Updatable" msgstr "Nadopunjivo" @@ -1366,6 +1840,9 @@ msgid "Updates all firmware to latest versions available" msgstr "Nadopuni sav firmver na najnovije dostupne inačice" +msgid "Updating" +msgstr "Nadopunjivanje" + #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second and third are #. * version numbers e.g. "1.2.3" @@ -1384,10 +1861,6 @@ msgid "Upgrade available for %s from %s to %s" msgstr "Nadopuna je dostupna za %s sa %s na %s" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Pošalji poruku:" - msgid "Upload report just this one time, but prompt again for future updates" msgid_plural "Upload reports just this one time, but prompt again for future updates" msgstr[0] "Pošalji izvještaj samo ovaj puta, ali upitaj ponovno za buduće nadopune" @@ -1412,6 +1885,14 @@ msgid "Urgency" msgstr "Hitnost" +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdmgr --help for help" +msgstr "Koristite fwupdmgr --help za prikaz pomoći" + +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdtool --help for help" +msgstr "Koristite fwupdtool --help za prikaz pomoći" + #. TRANSLATORS: command line option msgid "Use quirk flags when installing firmware" msgstr "Koristi oznake okolnosti računala tijekom instalacije firmvera" @@ -1424,6 +1905,14 @@ msgid "Username" msgstr "Korisničko ime" +#. TRANSLATORS: Suffix: the HSI result +msgid "Valid" +msgstr "Valjano" + +#. TRANSLATORS: ESP refers to the EFI System Partition +msgid "Validating ESP contents…" +msgstr "Provjera ESP sadržaja…" + #. TRANSLATORS: one line variant of release (e.g. 'Prerelease' or 'China') msgid "Variant" msgstr "Varijanta" @@ -1436,19 +1925,19 @@ msgid "Verifying…" msgstr "Provjeravanje..." -#. TRANSLATORS: try to help -msgid "WARNING: Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" -msgstr "UPOZORENJE: Zanemarivanje SSL ograničenja provjera, kako bi se ovo obavljalo ubuduće automatski postavite DISABLE_SSL_STRICT u vašem radnom okruženju" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Inačica" + +#. TRANSLATORS: this is a prefix on the console +msgid "WARNING:" +msgstr "UPOZORENJE:" #. TRANSLATORS: waiting for device to do something msgid "Waiting…" msgstr "Čekanje…" #. TRANSLATORS: command description -msgid "Watch DFU devices being hotplugged" -msgstr "Nadgledaj odspajanje DFU uređaja" - -#. TRANSLATORS: command description msgid "Watch for hardware changes" msgstr "Nadgledaj promjene hardvera" @@ -1460,6 +1949,10 @@ msgid "Write firmware from file into one partition" msgstr "Zapiši firmver iz datoteke u jednu particiju uređaja" +#. TRANSLATORS: decompressing images from a container firmware +msgid "Writing file:" +msgstr "Zapisivanje datoteke:" + #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Zapisivanje..." @@ -1468,19 +1961,19 @@ msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "Vaš distributer možda nije provjerio nadopune firmvera za kompatibilnost s vašim sustavom ili priključenim uređajima." +#. TRANSLATORS: %1 is the device vendor name +#, c-format +msgid "Your hardware may be damaged using this firmware, and installing this release may void any warranty with %s." +msgstr "Tvoj hardver se može oštetiti upotrebom ovog firmvera. Instaliranjem ovog izdanja možda se poništavaju %s jamstva." + +#. TRANSLATORS: this is the default branch name when unset +msgid "default" +msgstr "standardno" + #. TRANSLATORS: program name msgid "fwupd TPM event log utility" msgstr "fwupd TPM pomagalo zapisa događaja" -#. TRANSLATORS: message letting the user know no device upgrade available due -#. to missing on LVFS -#. * %1 is the device name -#, c-format -msgid "• %s has no available firmware updates" -msgstr "• %s nema dostupnu nadopunu firmvera" - -#. TRANSLATORS: message letting the user know no device upgrade available -#. * %1 is the device name -#, c-format -msgid "• %s has the latest available firmware version" -msgstr "• %s ima najnoviju inačicu firmvera" +#. TRANSLATORS: Title: if the fwupd plugins are all present and correct +msgid "fwupd plugins" +msgstr "fwupd priključci" diff -Nru fwupd-1.4.5/po/hu.po fwupd-1.5.8/po/hu.po --- fwupd-1.4.5/po/hu.po 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/po/hu.po 2021-03-31 20:08:32.000000000 +0000 @@ -3,7 +3,7 @@ # This file is distributed under the same license as the fwupd package. # # Translators: -# Balázs Meskó , 2017-2019 +# Balázs Meskó , 2017-2019 # Balázs Úr, 2015-2018 # Gabor Kelemen , 2016 # kelemeng , 2016 @@ -152,10 +152,6 @@ msgid "Activating firmware update for" msgstr "Firmware frissítés aktiválása ennél:" -#. TRANSLATORS: this is when a device is hotplugged -msgid "Added" -msgstr "Hozzáadva" - #. TRANSLATORS: the age of the metadata msgid "Age" msgstr "Kor" @@ -272,7 +268,6 @@ msgid "Cancelled" msgstr "Megszakítva" -#. TRANSLATORS: this is when a device is hotplugged #. TRANSLATORS: this is when the daemon state changes msgid "Changed" msgstr "Módosítva" @@ -446,6 +441,7 @@ msgid "Do not write to the history database" msgstr "Ne írjon az előzmények adatbázisába" +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Kész!" @@ -490,6 +486,8 @@ msgid "Enable this remote?" msgstr "Engedélyezi ezt a távoli tárolót?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Engedélyezve" @@ -528,10 +526,6 @@ msgid "Failed to connect to daemon" msgstr "A démonhoz kapcsolódás sikertelen" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "A letöltés kiszolgálókorlát miatt meghiúsult" - #. TRANSLATORS: we could not get the devices to update offline msgid "Failed to get pending devices" msgstr "A függőben lévő eszközök lekérése sikertelen" @@ -560,22 +554,6 @@ msgid "Failed to set splash mode" msgstr "Az indítóképernyő módjának beállítása sikertelen" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "Fájl lekérése" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "Firmware lekérése" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "Metaadatok lekérése" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "Aláírás lekérése" - #. TRANSLATORS: filename of the local file msgid "Filename" msgstr "Fájlnév" @@ -621,6 +599,7 @@ msgid "Firmware updates are supported on this machine." msgstr "A firmware frissítések támogatottak ezen a gépen." +#. TRANSLATORS: description of plugin state, e.g. disabled #. TRANSLATORS: release properties msgid "Flags" msgstr "Jelzők" @@ -628,12 +607,21 @@ msgid "Force the action ignoring all warnings" msgstr "A művelet erőltetése, az összes figyelmeztetés mellőzése" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Megtalálva" + #. TRANSLATORS: global ID common to all similar hardware msgid "GUID" msgid_plural "GUIDs" msgstr[0] "GUID" msgstr[1] "GUID-ok" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgctxt "A single GUID" +msgid "GUID" +msgstr "GUID" + #. TRANSLATORS: command description msgid "Get all device flags supported by fwupd" msgstr "Az fwupd által támogatott összes eszközjelző lekérése" @@ -658,10 +646,6 @@ msgid "Gets the configured remotes" msgstr "Lekéri a beállított távoli tárolókat" -#. TRANSLATORS: firmware approved by the admin -msgid "Gets the list of approved firmware." -msgstr "Lekéri a jóváhagyott firmwarek listáját." - #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "A frissítések listáját kéri le a csatlakoztatott hardverhez" @@ -781,10 +765,6 @@ msgid "Loading…" msgstr "Betöltés…" -#. TRANSLATORS: command line option -msgid "Manually whitelist specific plugins" -msgstr "Egyes bővítmények kézi fehérlistára tétele" - #. TRANSLATORS: remote URI msgid "Metadata Signature" msgstr "Metaadatok aláírása" @@ -806,10 +786,6 @@ msgid "Mismatched daemon and client, use %s instead" msgstr "Eltérő démon és kliens, inkább ezt használja: %s" -#. TRANSLATORS: sets something in daemon.conf -msgid "Modifies a daemon configuration value." -msgstr "Módosítja a démon egy konfigurációs értékét." - #. TRANSLATORS: command description msgid "Modifies a given remote" msgstr "A megadott távoli tároló módosítása" @@ -836,6 +812,7 @@ msgid "New version" msgstr "Új verzi" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "Nincs művelet megadva!" @@ -867,9 +844,9 @@ msgid "No updates were applied" msgstr "Nem lett frissítés alkalmazva" -#. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Bővítmény figyelmeztetés felülbírálása" +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "OK" #. TRANSLATORS: command line option msgid "Override the default ESP path" @@ -953,10 +930,6 @@ msgid "Refresh metadata from remote server" msgstr "Metaadatok frissítése a távoli kiszolgálóról" -#. TRANSLATORS: command description -msgid "Reinstall current firmware on the device." -msgstr "Újratelepíti a jelenlegi firmware-t az eszközön." - #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second is a version number #. * e.g. "1.2.3" @@ -969,10 +942,6 @@ msgid "Remote ID" msgstr "Távoli azonosító" -#. TRANSLATORS: this is when a device is hotplugged -msgid "Removed" -msgstr "Eltávolítva" - #. TRANSLATORS: command description msgid "Replace data in an existing firmware file" msgstr "Adatok cseréje egy meglévő firmware fájlban" @@ -985,10 +954,6 @@ msgid "Reported to remote server" msgstr "Jelentve a távoli kiszolgálónak" -#. TRANSLATORS: Must be plugged in to an outlet -msgid "Requires AC power" -msgstr "Hálózati áramforrás szükséges" - #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user msgid "Requires a bootloader" msgstr "Rendszerbetöltő szükséges" @@ -1045,13 +1010,10 @@ msgid "Set the debugging flag during update" msgstr "A hibakeresési jelző beállítása frissítéskor" +#. TRANSLATORS: firmware approved by the admin msgid "Sets the list of approved firmware" msgstr "Beállítja a jóváhagyott firmwarek listáját" -#. TRANSLATORS: firmware approved by the admin -msgid "Sets the list of approved firmware." -msgstr "Beállítja a jóváhagyott firmwarek listáját." - #. TRANSLATORS: command description msgid "Share firmware history with the developers" msgstr "Firmware frissítése előzmények megosztása a fejlesztőkkel" @@ -1309,10 +1271,6 @@ msgid "Upgrade available for %s from %s to %s" msgstr "%s frissítés érhető el, erről: %s, erre: %s" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Feltöltési üzenet:" - msgid "Upload report just this one time, but prompt again for future updates" msgid_plural "Upload reports just this one time, but prompt again for future updates" msgstr[0] "Most töltse fel a jelentést, de kérdezzen rá a jövőben" @@ -1355,19 +1313,15 @@ msgid "Verifying…" msgstr "Ellenőrzés…" -#. TRANSLATORS: try to help -msgid "WARNING: Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" -msgstr "FIGYELMEZTETÉS: A szigorú SSL ellenőrzések mellőzése, ahhoz hogy ezt automatikusan megtegye a jövőben, exportálja a DISABLE_SSL_STRICT változót a környezetében" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Verzió" #. TRANSLATORS: waiting for device to do something msgid "Waiting…" msgstr "Várakozás…" #. TRANSLATORS: command description -msgid "Watch DFU devices being hotplugged" -msgstr "DFU-eszközök menet közbeni csatlakoztatásának figyelése" - -#. TRANSLATORS: command description msgid "Watch for hardware changes" msgstr "Hardverváltozások figyelése" diff -Nru fwupd-1.4.5/po/id.po fwupd-1.5.8/po/id.po --- fwupd-1.4.5/po/id.po 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/po/id.po 2021-03-31 20:08:32.000000000 +0000 @@ -148,10 +148,6 @@ msgid "Activating firmware update for" msgstr "Mengaktifkan pembaruan firmware untuk" -#. TRANSLATORS: this is when a device is hotplugged -msgid "Added" -msgstr "Ditambahkan" - #. TRANSLATORS: the age of the metadata msgid "Age" msgstr "Usia" @@ -267,7 +263,6 @@ msgid "Cancelled" msgstr "Dibatalkan" -#. TRANSLATORS: this is when a device is hotplugged #. TRANSLATORS: this is when the daemon state changes msgid "Changed" msgstr "Diubah" @@ -447,6 +442,7 @@ msgid "Do not write to the history database" msgstr "Jangan menulis ke basis data riwayat" +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Selesai!" @@ -491,6 +487,8 @@ msgid "Enable this remote?" msgstr "Aktifkan remote ini?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Difungsikan" @@ -529,10 +527,6 @@ msgid "Failed to connect to daemon" msgstr "Gagal menyambung ke daemon" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "Gagal mengunduh karena batas server" - #. TRANSLATORS: we could not get the devices to update offline msgid "Failed to get pending devices" msgstr "Gagal mendapatkan perangkat yang tertunda" @@ -565,22 +559,6 @@ msgid "Failed to set splash mode" msgstr "Gagal mengatur mode splash" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "Sedang mengambil berkas" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "Sedang mengambil firmware" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "Sedang mengambil metadata" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "Sedang mengambil tanda tangan" - #. TRANSLATORS: filename of the local file msgid "Filename" msgstr "Nama Berkas" @@ -625,6 +603,7 @@ msgid "Firmware updates are supported on this machine." msgstr "Pembaruan firmware didukung pada mesin ini." +#. TRANSLATORS: description of plugin state, e.g. disabled #. TRANSLATORS: release properties msgid "Flags" msgstr "Flag" @@ -632,11 +611,20 @@ msgid "Force the action ignoring all warnings" msgstr "Paksa tindakan mengabaikan semua peringatan" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Ditemukan" + #. TRANSLATORS: global ID common to all similar hardware msgid "GUID" msgid_plural "GUIDs" msgstr[0] "GUID" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgctxt "A single GUID" +msgid "GUID" +msgstr "GUID" + #. TRANSLATORS: command description msgid "Get all device flags supported by fwupd" msgstr "Dapatkan semua flag perangkat yang didukung oleh fwupd" @@ -661,10 +649,6 @@ msgid "Gets the configured remotes" msgstr "Dapatkan remote-remote yang terkonfigurasi" -#. TRANSLATORS: firmware approved by the admin -msgid "Gets the list of approved firmware." -msgstr "Dapatkan daftar firmware yang disetujui." - #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "Dapatkan daftar pemutakhiran bagi perangkat keras yang tersambung" @@ -783,10 +767,6 @@ msgid "Loading…" msgstr "Memuat…" -#. TRANSLATORS: command line option -msgid "Manually whitelist specific plugins" -msgstr "Secara manual memasukkan daftar putih plugin tertentu" - #. TRANSLATORS: remote URI msgid "Metadata Signature" msgstr "Tanda Tangan Metadata" @@ -808,10 +788,6 @@ msgid "Mismatched daemon and client, use %s instead" msgstr "Daemon dan klien tidak cocok, gunakan %s sebagai gantinya" -#. TRANSLATORS: sets something in daemon.conf -msgid "Modifies a daemon configuration value." -msgstr "Mengubah suatu nilai konfigurasi daemon." - #. TRANSLATORS: command description msgid "Modifies a given remote" msgstr "Mengubah suatu remote yang diberikan" @@ -838,6 +814,7 @@ msgid "New version" msgstr "Versi baru" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "Tidak ada tindakan yang ditentukan!" @@ -875,15 +852,15 @@ msgid "No updates were applied" msgstr "Tidak ada pembaruan yang diterapkan" +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "OK" + #. TRANSLATORS: command line option msgid "Only show single PCR value" msgstr "Hanya tampilkan nilai PCR tunggal" #. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Timpa peringatan plugin" - -#. TRANSLATORS: command line option msgid "Override the default ESP path" msgstr "Timpa path ESP default" @@ -965,10 +942,6 @@ msgid "Refresh metadata from remote server" msgstr "Segarkan metadata dari server remote" -#. TRANSLATORS: command description -msgid "Reinstall current firmware on the device." -msgstr "Menginstal ulang firmware saat ini di perangkat." - #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second is a version number #. * e.g. "1.2.3" @@ -981,10 +954,6 @@ msgid "Remote ID" msgstr "ID Remote" -#. TRANSLATORS: this is when a device is hotplugged -msgid "Removed" -msgstr "Dihapus" - #. TRANSLATORS: command description msgid "Replace data in an existing firmware file" msgstr "Gantikan data dalam suatu berkas firmware yang telah ada" @@ -997,10 +966,6 @@ msgid "Reported to remote server" msgstr "Dilaporkan ke server remote" -#. TRANSLATORS: Must be plugged in to an outlet -msgid "Requires AC power" -msgstr "Membutuhkan daya AC" - #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user msgid "Requires a bootloader" msgstr "Membutuhkan bootloader" @@ -1060,13 +1025,10 @@ msgid "Set the debugging flag during update" msgstr "Atur flag debugging selama pembaruan" +#. TRANSLATORS: firmware approved by the admin msgid "Sets the list of approved firmware" msgstr "Setel daftar firmware yang disetujui" -#. TRANSLATORS: firmware approved by the admin -msgid "Sets the list of approved firmware." -msgstr "Tata daftar firmware yang disetujui." - #. TRANSLATORS: command description msgid "Share firmware history with the developers" msgstr "Membagikan riwayat firmware dengan para pengembang" @@ -1323,10 +1285,6 @@ msgid "Upgrade available for %s from %s to %s" msgstr "Pembaruan tersedia untuk %s dari %s ke %s" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Pesan unggah:" - msgid "Upload report just this one time, but prompt again for future updates" msgid_plural "Upload reports just this one time, but prompt again for future updates" msgstr[0] "Unggah laporan hanya sekali ini saja, tetapi minta lagi untuk pembaruan di masa mendatang" @@ -1367,19 +1325,15 @@ msgid "Verifying…" msgstr "Verifikasi…" -#. TRANSLATORS: try to help -msgid "WARNING: Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" -msgstr "PERINGATAN: Mengabaikan pemeriksaan ketat SSL, untuk melakukan ini secara otomatis di masa mendatang ekspor DISABLE_SSL_STRICT dalam lingkungan Anda" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Versi" #. TRANSLATORS: waiting for device to do something msgid "Waiting…" msgstr "Menunggu…" #. TRANSLATORS: command description -msgid "Watch DFU devices being hotplugged" -msgstr "Amati perangkat DFU yang sedang di-hotplug" - -#. TRANSLATORS: command description msgid "Watch for hardware changes" msgstr "Awasi perubahan perangkat keras" @@ -1402,16 +1356,3 @@ #. TRANSLATORS: program name msgid "fwupd TPM event log utility" msgstr "Utilitas log kejadian TPM fwupd" - -#. TRANSLATORS: message letting the user know no device upgrade available due -#. to missing on LVFS -#. * %1 is the device name -#, c-format -msgid "• %s has no available firmware updates" -msgstr "• %s tidak memiliki pembaruan firmware yang tersedia" - -#. TRANSLATORS: message letting the user know no device upgrade available -#. * %1 is the device name -#, c-format -msgid "• %s has the latest available firmware version" -msgstr "• %s memiliki versi firmware terbaru yang tersedia" diff -Nru fwupd-1.4.5/po/it.po fwupd-1.5.8/po/it.po --- fwupd-1.4.5/po/it.po 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/po/it.po 2021-03-31 20:08:32.000000000 +0000 @@ -4,7 +4,7 @@ # # Translators: # Gianvito Cavasoli , 2016 -# Milo Casagrande , 2017-2020 +# Milo Casagrande , 2017-2021 msgid "" msgstr "" "Project-Id-Version: fwupd\n" @@ -29,6 +29,12 @@ msgid "%s CPU Microcode Update" msgstr "Aggiornamento microcode CPU %s" +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Secure Boot` +#, c-format +msgid "%s Configuration Update" +msgstr "Aggiornamento configurazione %s" + #. TRANSLATORS: ME stands for Management Engine, where #. * the first %s is the device name, e.g. 'ThinkPad P50` #, c-format @@ -92,6 +98,11 @@ msgid "%s and all connected devices may not be usable while updating." msgstr "%s e tutti i dispositivi collegati potrebbero non essere utilizzabili durante l'aggiornamento." +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s manufacturing mode" +msgstr "Modalità costruttore %s" + #. TRANSLATORS: warn the user before updating, %1 is a device name #, c-format msgid "%s must remain connected for the duration of the update to avoid damage." @@ -102,6 +113,21 @@ msgid "%s must remain plugged into a power source for the duration of the update to avoid damage." msgstr "%s deve rimanere collegato alla rete elettrica durante l'aggiornamento per evitare possibili danni." +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s override" +msgstr "Override %s" + +#. TRANSLATORS: Title: %1 is ME kind, e.g. CSME/TXT, %2 is a version number +#, c-format +msgid "%s v%s" +msgstr "%s v%s" + +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s version" +msgstr "Versione %s" + #. TRANSLATORS: duration in days! #, c-format msgid "%u day" @@ -143,6 +169,10 @@ msgstr[0] "%u secondo" msgstr[1] "%u secondi" +#. TRANSLATORS: this is shown as a suffix for obsoleted tests +msgid "(obsoleted)" +msgstr "(obsoleto)" + #. TRANSLATORS: command description msgid "Activate devices" msgstr "Attiva dispositivi" @@ -162,10 +192,6 @@ msgid "Activating firmware update for" msgstr "Attivazione aggiornamento firmware per" -#. TRANSLATORS: this is when a device is hotplugged -msgid "Added" -msgstr "Aggiunto" - #. TRANSLATORS: the age of the metadata msgid "Age" msgstr "Età" @@ -187,6 +213,10 @@ msgid "Allow reinstalling existing firmware versions" msgstr "Consente la re-installazione di versioni esistenti del firmware" +#. TRANSLATORS: command line option +msgid "Allow switching firmware branch" +msgstr "Consente il cambio del ramo firmware" + #. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Per essere completato, un aggiornamento richiede un riavvio." @@ -203,6 +233,18 @@ msgid "Apply firmware updates" msgstr "Applica aggiornamenti firmware" +#. TRANSLATORS: command line option +msgid "Apply update even when not advised" +msgstr "Applica aggiornamento anche se non consigliato" + +#. TRANSLATORS: command line option +msgid "Apply update files" +msgstr "Applica file di aggiornamento" + +#. TRANSLATORS: actually sending the update to the hardware +msgid "Applying update…" +msgstr "Applicazione aggiornamento…" + #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator msgid "Approved firmware:" @@ -210,6 +252,10 @@ msgstr[0] "Firmware approvato:" msgstr[1] "Firmware approvati:" +#. TRANSLATORS: stop nagging the user +msgid "Ask again next time?" +msgstr "Chiedere ancora la prossima volta?" + #. TRANSLATORS: command description msgid "Attach to firmware mode" msgstr "Collega in modalità firmware" @@ -266,14 +312,53 @@ msgid "Automatic Reporting" msgstr "Rapporti automatici" +#. TRANSLATORS: can we JFDI? +msgid "Automatically upload every time?" +msgstr "Caricare automaticamente ogni volta?" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "BUILDER-XML FILENAME-DST" +msgstr "BUILDER-XML NOMEFILE-DST" + +msgid "BYTES" +msgstr "BYTE" + +#. TRANSLATORS: command description +msgid "Bind new kernel driver" +msgstr "Vincola in nuovo driver kernel" + +#. TRANSLATORS: there follows a list of hashes +msgid "Blocked firmware files:" +msgstr "File di firmware bloccati:" + +#. TRANSLATORS: we will not offer this firmware to the user +msgid "Blocking firmware:" +msgstr "Firmware bloccato:" + +#. TRANSLATORS: command description +msgid "Blocks a specific firmware from being installed" +msgstr "Blocca un firmware specifico così da non installarlo" + #. TRANSLATORS: firmware version of bootloader msgid "Bootloader Version" msgstr "Versione bootloader" +#. TRANSLATORS: the stream of firmware, e.g. nonfree or open-source +msgid "Branch" +msgstr "Ramo" + +#. TRANSLATORS: command description +msgid "Build a firmware file" +msgstr "Compila una file firmware" + #. TRANSLATORS: command description msgid "Build firmware using a sandbox" msgstr "Compila il firmware utilizzando una sandbox" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "CHECKSUM1[,CHECKSUM2][,CHECKSUM3]" +msgstr "CHECKSUM1[,CHECKSUM2][,CHECKSUM3]" + #. TRANSLATORS: this is to abort the interactive prompt msgid "Cancel" msgstr "Annulla" @@ -282,7 +367,14 @@ msgid "Cancelled" msgstr "Annullato" -#. TRANSLATORS: this is when a device is hotplugged +#. TRANSLATORS: same or newer update already applied +msgid "Cannot apply as dbx update has already been applied." +msgstr "Impossibile applicare poiché l'aggiornamento dbx è già stato applicato." + +#. TRANSLATORS: the user is using a LiveCD or LiveUSB install disk +msgid "Cannot apply updates on live media" +msgstr "Impossibile applicare gli aggiornamenti su supporti live" + #. TRANSLATORS: this is when the daemon state changes msgid "Changed" msgstr "Modificato" @@ -295,6 +387,11 @@ msgid "Checksum" msgstr "Codice di controllo" +#. TRANSLATORS: get interactive prompt, where branch is the +#. * supplier of the firmware, e.g. "non-free" or "free" +msgid "Choose a branch:" +msgstr "Scegliere un ramo:" + #. TRANSLATORS: get interactive prompt msgid "Choose a device:" msgstr "Scegliere un dispositivo:" @@ -307,6 +404,10 @@ msgid "Choose a release:" msgstr "Scegliere un rilascio:" +#. TRANSLATORS: get interactive prompt +msgid "Choose a volume:" +msgstr "Scegliere un volume:" + #. TRANSLATORS: command description msgid "Clears any updates scheduled to be updated offline" msgstr "Annulla gli aggiornamenti pianificati per essere eseguiti offline" @@ -343,6 +444,10 @@ msgid "Current version" msgstr "Versione attuale" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "DEVICE-ID|GUID" +msgstr "ID-DISPOSITIVO|GUID" + #. TRANSLATORS: DFU stands for device firmware update msgid "DFU Utility" msgstr "Strumento DFU" @@ -411,10 +516,18 @@ msgid "Device stages updates" msgstr "Il dispositivo applica gli aggiornamenti a fasi" +#. TRANSLATORS: there is more than one supplier of the firmware +msgid "Device supports switching to a different branch of firmware" +msgstr "Il dispositivo supporta il passaggio a un ramo diverso del firmware" + #. TRANSLATORS: Device update needs to be separately activated msgid "Device update needs activation" msgstr "L'aggiornamento del dispositivo richiede l'attivazione" +#. TRANSLATORS: save the old firmware to disk before installing the new one +msgid "Device will backup firmware before installing" +msgstr "Il dispositivo eseguirà un backup del firmware prima dell'installazione" + #. TRANSLATORS: Device will not return after update completes msgid "Device will not re-appear after update completes" msgstr "Il dispositivo non comparirà nuovamente dopo l'aggiornamento" @@ -427,6 +540,20 @@ msgid "Devices that were not updated correctly:" msgstr "Dispositivi non aggiornati correttamente:" +#. TRANSLATORS: message letting the user know no device upgrade available due +#. to missing on LVFS +msgid "Devices with no available firmware updates: " +msgstr "Dispositivi senza aggiornamenti firmware:" + +#. TRANSLATORS: message letting the user know no device upgrade available +msgid "Devices with the latest available firmware version:" +msgstr "Dispositivi con l'ultima versione disponibile del firmware:" + +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is inactive and not used +msgid "Disabled" +msgstr "Disabilitato" + msgid "Disabled fwupdate debugging" msgstr "Debug fwupdate disabilitato" @@ -450,6 +577,10 @@ msgid "Do not check for unreported history" msgstr "Non controlla la cronologia non segnalata " +#. TRANSLATORS: command line option +msgid "Do not check if download remotes should be enabled" +msgstr "Non controlla se lo scaricamento dai remoti deve essere abilitato" + #. TRANSLATORS: turn on all debugging msgid "Do not include log domain prefix" msgstr "Non include il prefisso del dominio" @@ -476,6 +607,11 @@ msgid "Do not write to the history database" msgstr "Non scrive la cronologia" +#. TRANSLATORS: should the branch be changed +msgid "Do you understand the consequences of changing the firmware branch?" +msgstr "Le conseguenze del cambio di ramo del firmware sono state comprese?" + +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Fatto." @@ -520,6 +656,8 @@ msgid "Enable this remote?" msgstr "Abilitare questo remoto?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Abilitato" @@ -538,6 +676,14 @@ msgid "Enabling this remote is done at your own risk." msgstr "Abilitare questo remoto a proprio rischio." +#. TRANSLATORS: Suffix: the HSI result +msgid "Encrypted" +msgstr "Cifrato" + +#. TRANSLATORS: Title: Memory contents are encrypted, e.g. Intel TME +msgid "Encrypted RAM" +msgstr "RAM cifrata" + #. TRANSLATORS: command description msgid "Erase all firmware update history" msgstr "Elimina tutta la cronologia degli aggiornamenti firmware" @@ -554,14 +700,63 @@ msgid "Exit after the engine has loaded" msgstr "Esce dopo che il motore è stato caricato" +#. TRANSLATORS: command description +msgid "Extract a firmware blob to images" +msgstr "Estrae un blob firmware in immagini" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILE" +msgstr "FILE" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILE [DEVICE-ID|GUID]" +msgstr "FILE [ID-DISPOSITIVO|GUID]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILE-IN FILE-OUT [SCRIPT] [OUTPUT]" +msgstr "FILE-IN FILE-OUT [SCRIPT] [OUTPUT]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME" +msgstr "NOMEFILE" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME DEVICE-ALT-NAME|DEVICE-ALT-ID" +msgstr "NOMEFILE NOME-ALT-DISPOSITIVO|ID-ALT-DISPOSITIVO" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME DEVICE-ALT-NAME|DEVICE-ALT-ID [IMAGE-ALT-NAME|IMAGE-ALT-ID]" +msgstr "NOMEFILE NOME-ALT-DISPOSITIVO|ID-ALT-DISPOSITIVO [NOME-ALT-IMMAGINE|ID-ALT-IMMAGINE]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME DEVICE-ID" +msgstr "NOMEFILE ID-DISPOSITIVO" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME [DEVICE-ID|GUID]" +msgstr "NOMEFILE [ID-DISPOSITIVO|GUID]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME [FIRMWARE-TYPE]" +msgstr "NOMEFILE [TIPO-FIRMWARE]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "FILENAME-SRC FILENAME-DST [FIRMWARE-TYPE-SRC] [FIRMWARE-TYPE-DST]" +msgstr "NOMEFILE-SRC NOMEFILE-DST [TIPO-FIRMWARE-SRC] [TIPO-FIRMWARE-DST]" + +#. TRANSLATORS: Suffix: the fallback HSI result +#. TRANSLATORS: The update state of the specific device +msgid "Failed" +msgstr "Non riuscito" + +#. TRANSLATORS: dbx file failed to be applied as an update +msgid "Failed to apply update" +msgstr "Applicazione aggiornamento non riuscita" + #. TRANSLATORS: we could not talk to the fwupd daemon msgid "Failed to connect to daemon" msgstr "Connessione al demone non riuscita" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "Scaricamento non riuscito a causa di un limite sul server" - #. TRANSLATORS: we could not get the devices to update offline msgid "Failed to get pending devices" msgstr "Recupero dei dispositivi in attesa non riuscito" @@ -570,10 +765,19 @@ msgid "Failed to install firmware update" msgstr "Installazione aggiornamento firmware non riuscita" +#. TRANSLATORS: could not read existing system data +#. TRANSLATORS: could not read file +msgid "Failed to load local dbx" +msgstr "Caricamento dbx locale non riuscito" + #. TRANSLATORS: quirks are device-specific workarounds msgid "Failed to load quirks" msgstr "Caricamento stranezze non riuscito" +#. TRANSLATORS: could not read existing system data +msgid "Failed to load system dbx" +msgstr "Caricamento dbx di sistema non riuscito" + #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Analisi degli argomenti non riuscita" @@ -586,6 +790,10 @@ msgid "Failed to parse flags for --filter" msgstr "Analisi del flag --filter non riuscita" +#. TRANSLATORS: could not parse file +msgid "Failed to parse local dbx" +msgstr "Lettura dbx locale non riuscita" + #. TRANSLATORS: we could not reboot for some reason msgid "Failed to reboot" msgstr "Riavvio non riuscito" @@ -594,21 +802,10 @@ msgid "Failed to set splash mode" msgstr "Impostazione della modalità splash non riuscita" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "Recupero file" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "Recupero firmware" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "Recupero metadati" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "Recupero firma" +#. TRANSLATORS: something with a blocked hash exists +#. * in the users ESP -- which would be bad! +msgid "Failed to validate ESP contents" +msgstr "Verifica contenuti ESP non riuscita" #. TRANSLATORS: filename of the local file msgid "Filename" @@ -618,6 +815,10 @@ msgid "Filename Signature" msgstr "Firma nome file" +#. TRANSLATORS: user did not include a filename parameter +msgid "Filename required" +msgstr "Nome file richiesto" + #. TRANSLATORS: command line option msgid "Filter with a set of device flags using a ~ prefix to exclude, e.g. 'internal,~needs-reboot'" msgstr "Filtra tramite un insieme di flag utilizzando ~ per escludere, per esempio «internal, ~needs-reboot»" @@ -642,6 +843,22 @@ msgid "Firmware Utility" msgstr "Strumento gestione firmware" +#. TRANSLATORS: Title: if we can verify the firmware checksums +msgid "Firmware attestation" +msgstr "Convalida firmware" + +#. TRANSLATORS: system is not booted in UEFI mode +msgid "Firmware can not be updated in legacy BIOS mode" +msgstr "Impossibile aggiornare il firmware in modalità BIOS legacy" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is already blocked" +msgstr "Il firmware è già bloccato" + +#. TRANSLATORS: user selected something not possible +msgid "Firmware is not already blocked" +msgstr "Il firmware non è bloccato" + #. TRANSLATORS: the metadata is very out of date; %u is a number > 1 #, c-format msgid "Firmware metadata has not been updated for %u day and may not be up to date." @@ -649,25 +866,47 @@ msgstr[0] "I metadati del firmware non sono stati controllati per %u giorno e potrebbero non essere aggiornati." msgstr[1] "I metadati del firmware non sono stati controllati per %u giorni e potrebbero non essere aggiornati." +#. TRANSLATORS: Title: if firmware updates are available +msgid "Firmware updates" +msgstr "Aggiornamenti firmware" + msgid "Firmware updates are not supported on this machine." msgstr "Gli aggiornamenti firmware non sono supportati su questo dispositivo." msgid "Firmware updates are supported on this machine." msgstr "Gli aggiornamenti firmware sono supportati su questo dispositivo." +#. TRANSLATORS: user needs to run a command +msgid "Firmware updates disabled; run 'fwupdmgr unlock' to enable" +msgstr "Aggiornamenti firmware disabilitati; eseguire «fwupdmgr unlock» per abilitarli" + +#. TRANSLATORS: description of plugin state, e.g. disabled #. TRANSLATORS: release properties msgid "Flags" msgstr "Flag" +#. TRANSLATORS: command line option +msgid "Force the action by relaxing some runtime checks" +msgstr "Forza l'azione riducendo alcuni controlli runtime" + msgid "Force the action ignoring all warnings" msgstr "Forza l'azione ignorando gli avvisi" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Trovato" + #. TRANSLATORS: global ID common to all similar hardware msgid "GUID" msgid_plural "GUIDs" msgstr[0] "GUID" msgstr[1] "GUID" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgctxt "A single GUID" +msgid "GUID" +msgstr "GUID" + #. TRANSLATORS: command description msgid "Get all device flags supported by fwupd" msgstr "Ottiene tutti i flag dispositivo supportati da fwupd" @@ -692,9 +931,17 @@ msgid "Gets the configured remotes" msgstr "Ottiene i remoti configurati" +#. TRANSLATORS: command description +msgid "Gets the host security attributes" +msgstr "Recupera gli attributi di sicurezza dell'host" + #. TRANSLATORS: firmware approved by the admin -msgid "Gets the list of approved firmware." -msgstr "Recupera l'elenco dei firmware approvati." +msgid "Gets the list of approved firmware" +msgstr "Recupera l'elenco dei firmware approvati" + +#. TRANSLATORS: command description +msgid "Gets the list of blocked firmware" +msgstr "Recupera l'elenco del firmware bloccato" #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" @@ -708,6 +955,10 @@ msgid "Gets the results from the last update" msgstr "Ottiene i risultati dell'ultimo aggiornamento" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "HWIDS-FILE" +msgstr "FILE-HWIDS" + #. TRANSLATORS: The hardware is waiting to be replugged msgid "Hardware is waiting to be replugged" msgstr "L'hardware è in attesa di essere ricollegato" @@ -716,6 +967,15 @@ msgid "High" msgstr "Elevata" +#. TRANSLATORS: this is a string like 'HSI:2-U' +msgid "Host Security ID:" +msgstr "ID sicurezza host:" + +#. TRANSLATORS: Title: +#. https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit +msgid "IOMMU" +msgstr "IOMMU" + #. TRANSLATORS: daemon is inactive msgid "Idle…" msgstr "Inattivo…" @@ -724,10 +984,26 @@ msgid "Ignore SSL strict checks when downloading files" msgstr "Ignora controlli SSL nello scaricare i file" +#. TRANSLATORS: command line option +msgid "Ignore firmware checksum failures" +msgstr "Ignora i checksum del firmware non riusciti" + +#. TRANSLATORS: command line option +msgid "Ignore firmware hardware mismatch failures" +msgstr "Ignora corrispondenze errate firmware hardware" + +#. TRANSLATORS: command line option +msgid "Ignore requirement of external power source" +msgstr "Ignora richiesta di sorgente elettrica esterna" + #. TRANSLATORS: Ignore validation safety checks when flashing this device msgid "Ignore validation safety checks" msgstr "Ignora i controlli di sicurezza di validazione" +#. TRANSLATORS: try to help +msgid "Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" +msgstr "Controlli SSL ignorati, per fare ciò automaticamente in futuro, esportare DISABLE_SSL_STRICT nel proprio ambiente" + #. TRANSLATORS: length of time the update takes to apply msgid "Install Duration" msgstr "Tempo di installazione" @@ -772,10 +1048,57 @@ msgid "Installing on %s…" msgstr "Installazione su %s…" +#. TRANSLATORS: Title: BootGuard is a trademark from Intel +msgid "Intel BootGuard" +msgstr "Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * ACM means to verify the integrity of Initial Boot Block +msgid "Intel BootGuard ACM protected" +msgstr "ACM protetto da Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * OTP = one time programmable +msgid "Intel BootGuard OTP fuse" +msgstr "Fusibile OTP Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * error policy is what to do on failure +msgid "Intel BootGuard error policy" +msgstr "Regole di errore Intel BootGuard" + +#. TRANSLATORS: Title: BootGuard is a trademark from Intel, +#. * verified boot refers to the way the boot process is verified +msgid "Intel BootGuard verified boot" +msgstr "Avvio verificato da Intel BootGuard" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * active means being used by the OS +msgid "Intel CET Active" +msgstr "Intel CET attivo" + +#. TRANSLATORS: Title: CET = Control-flow Enforcement Technology, +#. * enabled means supported by the processor +msgid "Intel CET Enabled" +msgstr "Intel CET abilitato" + +#. TRANSLATORS: Title: Direct Connect Interface (DCI) allows +#. * debugging of Intel processors using the USB3 port +msgid "Intel DCI debugger" +msgstr "Debugger Intel DCI" + +#. TRANSLATORS: Title: SMAP = Supervisor Mode Access Prevention +msgid "Intel SMAP" +msgstr "Intel SMAP" + #. TRANSLATORS: Device cannot be removed easily msgid "Internal device" msgstr "Dispositivo interno" +#. TRANSLATORS: Suffix: the HSI result +msgid "Invalid" +msgstr "Non valido" + #. TRANSLATORS: Is currently in bootloader mode msgid "Is in bootloader mode" msgstr "È in modalità bootloader" @@ -786,6 +1109,10 @@ msgstr[0] "Problema" msgstr[1] "Problemi" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "KEY,VALUE" +msgstr "CHIAVE,VALORE" + msgid "Keyring" msgstr "Portachiavi" @@ -807,6 +1134,22 @@ msgid "Linux Vendor Firmware Service (testing firmware)" msgstr "Linux Vendor Firmware Service (firmware in prova)" +#. TRANSLATORS: Title: if it's tainted or not +msgid "Linux kernel" +msgstr "Kernel Linux" + +#. TRANSLATORS: Title: lockdown is a security mode of the kernel +msgid "Linux kernel lockdown" +msgstr "Lockdown kernel Linux" + +#. TRANSLATORS: Title: swap space or swap partition +msgid "Linux swap" +msgstr "Swap Linux" + +#. TRANSLATORS: command line option +msgid "List entries in dbx" +msgstr "Elenca le voci nel dbx" + #. TRANSLATORS: command line option msgid "List supported firmware updates" msgstr "Elenca gli aggiornamenti firmware supportati" @@ -815,17 +1158,39 @@ msgid "List the available firmware types" msgstr "Elenca tutti i tipi di firmware disponibili" +#. TRANSLATORS: command description +msgid "Lists files on the ESP" +msgstr "Elenca i file nell'ESP" + #. TRANSLATORS: parsing the firmware information msgid "Loading…" msgstr "Caricamento…" +#. TRANSLATORS: Suffix: the HSI result +msgid "Locked" +msgstr "Bloccato" + #. TRANSLATORS: the release urgency msgid "Low" msgstr "Bassa" +#. TRANSLATORS: Title: MEI = Intel Management Engine +msgid "MEI manufacturing mode" +msgstr "Modalità costruttore MEI" + +#. TRANSLATORS: Title: MEI = Intel Management Engine, and the +#. * "override" is the physical PIN that can be driven to +#. * logic high -- luckily it is probably not accessible to +#. * end users on consumer boards +msgid "MEI override" +msgstr "Override MEI" + +msgid "MEI version" +msgstr "Versione MEI" + #. TRANSLATORS: command line option -msgid "Manually whitelist specific plugins" -msgstr "Abilita manualmente plugin specifici" +msgid "Manually enable specific plugins" +msgstr "Abilita manualmente i plugin selezionati" #. TRANSLATORS: the release urgency msgid "Medium" @@ -853,7 +1218,7 @@ msgstr "Versioni di demone e client non corrispondenti, usare %s" #. TRANSLATORS: sets something in daemon.conf -msgid "Modifies a daemon configuration value." +msgid "Modifies a daemon configuration value" msgstr "Modifica il valore della configurazione del demone" #. TRANSLATORS: command description @@ -870,10 +1235,18 @@ msgid "Monitor the daemon for events" msgstr "Controlla il demone per gli eventi" +#. TRANSLATORS: command description +msgid "Mounts the ESP" +msgstr "Monta l'ESP" + #. TRANSLATORS: Requires a reboot to apply firmware or to reload hardware msgid "Needs a reboot after installation" msgstr "Necessita un riavvio dopo l'installazione" +#. TRANSLATORS: The update state of the specific device +msgid "Needs reboot" +msgstr "Richiesto riavvio" + #. TRANSLATORS: Requires system shutdown to apply firmware msgid "Needs shutdown after installation" msgstr "Necessita l'arresto dopo l'installazione" @@ -882,6 +1255,7 @@ msgid "New version" msgstr "Nuova versione" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "Nessuna azione specificata." @@ -919,13 +1293,25 @@ msgid "No updates were applied" msgstr "Non è stato applicato alcun aggiornamento" +#. TRANSLATORS: Suffix: the HSI result +msgid "Not found" +msgstr "Non trovato" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Not supported" +msgstr "Non supportato" + +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "Fatto" + #. TRANSLATORS: command line option msgid "Only show single PCR value" msgstr "Mostra solo il valore PCR" #. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Scavalca l'avviso sul plugin" +msgid "Only use IPFS when downloading files" +msgstr "Usa IPFS solo quando si scaricano file" #. TRANSLATORS: command line option msgid "Override the default ESP path" @@ -935,10 +1321,22 @@ msgid "Override warnings and force the action" msgstr "Scavalca gli avvisi e forza l'azione" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "PATH" +msgstr "PERCORSO" + #. TRANSLATORS: command description msgid "Parse and show details about a firmware file" msgstr "Legge e mostra i dettagli riguardo a un file firmware" +#. TRANSLATORS: reading new dbx from the update +msgid "Parsing dbx update…" +msgstr "Lettura aggiornamento dbx…" + +#. TRANSLATORS: reading existing dbx from the system +msgid "Parsing system dbx…" +msgstr "Lettura dbx di sistema…" + #. TRANSLATORS: remote filename base msgid "Password" msgstr "Password" @@ -946,6 +1344,10 @@ msgid "Payload" msgstr "Carico" +#. TRANSLATORS: The update state of the specific device +msgid "Pending" +msgstr "In attesa" + #. TRANSLATORS: console message when not using plymouth msgid "Percentage complete" msgstr "Percentuale completamento" @@ -955,6 +1357,14 @@ msgid "Please enter a number from 0 to %u: " msgstr "Inserire un numero tra 0 e %u:" +#. TRANSLATORS: Failed to open plugin, hey Arch users +msgid "Plugin dependencies missing" +msgstr "Dipendenze plugin mancanti" + +#. TRANSLATORS: Title: DMA as in https://en.wikipedia.org/wiki/DMA_attack +msgid "Pre-boot DMA protection" +msgstr "Protezione DMA pre-boot" + #. TRANSLATORS: version number of previous firmware msgid "Previous version" msgstr "Versione precedente" @@ -980,6 +1390,14 @@ msgid "Query for firmware update support" msgstr "Interroga il supporto per gli aggiornamenti firmware" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "REMOTE-ID" +msgstr "ID-REMOTO" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "REMOTE-ID KEY VALUE" +msgstr "ID-REMOTO CHIAVE VALORE" + #. TRANSLATORS: command description msgid "Read a firmware blob from a device" msgstr "Legge un blob firmware da un dispositivo" @@ -1010,7 +1428,7 @@ msgstr "Ricarica i metadati dal server remoto" #. TRANSLATORS: command description -msgid "Reinstall current firmware on the device." +msgid "Reinstall current firmware on the device" msgstr "Installa nuovamente il firmware attuale sul dispositivo" #. TRANSLATORS: command description @@ -1024,15 +1442,15 @@ msgid "Reinstalling %s with %s... " msgstr "Reinstallazione di %s con %s..." +#. TRANSLATORS: the stream of firmware, e.g. nonfree or open-source +msgid "Release Branch" +msgstr "Ramo di rilascio" + #. TRANSLATORS: the server the file is coming from #. TRANSLATORS: remote identifier, e.g. lvfs-testing msgid "Remote ID" msgstr "ID remoto" -#. TRANSLATORS: this is when a device is hotplugged -msgid "Removed" -msgstr "Rimosso" - #. TRANSLATORS: command description msgid "Replace data in an existing firmware file" msgstr "Sostituisce i dati su un file di firmware esistente" @@ -1045,9 +1463,13 @@ msgid "Reported to remote server" msgstr "Segnalato al server remoto" -#. TRANSLATORS: Must be plugged in to an outlet -msgid "Requires AC power" -msgstr "Richiede corrente elettrica" +#. TRANSLATORS: the user is using Gentoo/Arch and has screwed something up +msgid "Required efivarfs filesystem was not found" +msgstr "Il file system richiesto efivarfs non è stato trovato" + +#. TRANSLATORS: not required for this system +msgid "Required hardware was not found" +msgstr "L'hardware richiesto non è stato trovato" #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user msgid "Requires a bootloader" @@ -1084,6 +1506,30 @@ msgid "Run the plugin composite prepare routine when using install-blob" msgstr "Esegue la procedura di preparazione del plugin quando si utilizza install-blob" +#. TRANSLATORS: this is the HSI suffix +msgid "Runtime Suffix" +msgstr "Suffisso di runtime" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI BIOS region" +msgstr "Regione BIOS SPI" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI lock" +msgstr "Blocco SPI" + +#. TRANSLATORS: Title: SPI refers to the flash chip in the computer +msgid "SPI write" +msgstr "Scrittura SPI" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "SUBSYSTEM DRIVER [DEVICE-ID|GUID]" +msgstr "SOTTOSISTEMA DRIVER [ID-DISPOSITIVO|GUID]" + +#. TRANSLATORS: command description +msgid "Save a file that allows generation of hardware IDs" +msgstr "Salva una file che consente di generare ID hardware" + #. TRANSLATORS: command line option msgid "Save device state into a JSON file between executions" msgstr "Salva lo stato del dispositivo tra le esecuzioni su un file JSON" @@ -1096,10 +1542,19 @@ msgid "Scheduling…" msgstr "Pianificazione…" +#. TRANSLATORS: %s is a link to a website +#, c-format +msgid "See %s for more information." +msgstr "Per maggiori informazioni, consultare %s." + #. TRANSLATORS: Device has been chosen by the daemon for the user msgid "Selected device" msgstr "Dispositivo selezionato" +#. TRANSLATORS: Volume has been chosen by the user +msgid "Selected volume" +msgstr "Volume selezionato" + #. TRANSLATORS: serial number of hardware msgid "Serial Number" msgstr "Numero di serie" @@ -1108,18 +1563,19 @@ msgid "Set the debugging flag during update" msgstr "Imposta il flag di debug durante l'aggiornamento" +#. TRANSLATORS: firmware approved by the admin msgid "Sets the list of approved firmware" msgstr "Imposta l'elenco dei firmware approvati" -#. TRANSLATORS: firmware approved by the admin -msgid "Sets the list of approved firmware." -msgstr "Imposta l'elenco dei firmware approvati." - #. TRANSLATORS: command description msgid "Share firmware history with the developers" msgstr "Condivide la cronologia del firmware con gli sviluppatori" #. TRANSLATORS: command line option +msgid "Show all results" +msgstr "Mostra tutti i risultati" + +#. TRANSLATORS: command line option msgid "Show client and daemon versions" msgstr "Mostra la versione del client e del demone" @@ -1152,6 +1608,10 @@ msgstr "Mostra informazioni dettagliate del plugin" #. TRANSLATORS: command line option +msgid "Show the calculated version of the dbx" +msgstr "Mostra la versione calcolata del dbx" + +#. TRANSLATORS: command line option msgid "Show the debug log from the last attempted update" msgstr "Mostra debug dell'ultimo tentativo di aggiornamento" @@ -1188,9 +1648,17 @@ msgid "Specify Vendor/Product ID(s) of DFU device" msgstr "Specifica vendor/ID prodotto di un dispositivo DFU" +#. TRANSLATORS: command line option +msgid "Specify the dbx database file" +msgstr "Indica il file del database dbx" + msgid "Specify the number of bytes per USB transfer" msgstr "Specifica il numero di byte per trasferimento USB" +#. TRANSLATORS: The update state of the specific device +msgid "Success" +msgstr "Completato" + #. TRANSLATORS: success message -- where activation is making the new #. * firmware take effect, usually after updating offline msgid "Successfully activated all devices" @@ -1245,10 +1713,46 @@ msgid "Summary" msgstr "Riepilogo" +#. TRANSLATORS: Suffix: the HSI result +msgid "Supported" +msgstr "Supportato" + #. TRANSLATORS: Is found in current metadata msgid "Supported on remote server" msgstr "Supportato sul server remoto" +#. TRANSLATORS: Title: a better sleep state +msgid "Suspend-to-idle" +msgstr "Suspend-to-idle" + +#. TRANSLATORS: Title: sleep state +msgid "Suspend-to-ram" +msgstr "Suspend-to-ram" + +#. TRANSLATORS: command description +msgid "Switch the firmware branch on the device" +msgstr "Cambia il ramo del firmware sul dispositivo" + +#. TRANSLATORS: Must be plugged in to an outlet +msgid "System requires external power source" +msgstr "Il sistema richiede una sorgente elettrica esterna" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "TEXT" +msgstr "TESTO" + +#. TRANSLATORS: Title: the PCR is rebuilt from the TPM event log +msgid "TPM PCR0 reconstruction" +msgstr "Ricostruzione PCR0 TPM" + +#. TRANSLATORS: Title: TPM = Trusted Platform Module +msgid "TPM v2.0" +msgstr "TPM v2.0" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Tainted" +msgstr "Non integro" + msgid "Target" msgstr "Obiettivo" @@ -1256,11 +1760,36 @@ msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "LVFS è un servizio gratuito che opera come entità legale indipendente e non ha alcun legame con $OS_RELEASE:NAME$. Il distributore potrebbe non aver verificato la compatibilità degli aggiornamenti firmware col proprio sistema o con i propri dispositivi collegati. Il firmware viene fornito solamente dall'OEM." +#. TRANSLATORS: this is more background on a security measurement problem +msgid "The TPM PCR0 differs from reconstruction." +msgstr "TPM PCR0 è diverso dalla ricostruzione." + +#. TRANSLATORS: the user is SOL for support... +msgid "The daemon has loaded 3rd party code and is no longer supported by the upstream developers!" +msgstr "Il demone ha caricato codice di terze parti e non è più supportato dagli sviluppatori." + +#. TRANSLATORS: %1 is the firmware vendor, %2 is the device vendor name +#, c-format +msgid "The firmware from %s is not supplied by %s, the hardware vendor." +msgstr "Il firmware su %s non è fornito da %s, il fornitore dell'hardware." + +#. TRANSLATORS: try to help +msgid "The system clock has not been set correctly and downloading files may fail." +msgstr "L'orologio di sistema non è stato impostato correttamente e lo scaricamento di file potrebbe non riuscire." + +#. TRANSLATORS: nothing to show +msgid "There are no blocked firmware files" +msgstr "Non ci sono file di firmware bloccati" + #. TRANSLATORS: approved firmware has been checked by #. * the domain administrator msgid "There is no approved firmware." msgstr "Non ci sono firmware approvati." +#. TRANSLATORS: unsupported build of the package +msgid "This package has not been validated, it may not work properly." +msgstr "Questo pacchetto non è stato verificato, potrebbe non funzionare correttamente." + #. TRANSLATORS: we're poking around as a power user msgid "This program may only work correctly as root" msgstr "Questo programma può funzionare correttamente solo come utente root" @@ -1268,18 +1797,98 @@ msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "Questo remoto contiene firmware che non è bloccato, ma è ancora in fase di verifica dal produttore hardware. Assicurarsi di poter ripristinare, manualmente o con altre procedure, il vecchio firmware nel caso in cui l'aggiornamento non riuscisse." +#. TRANSLATORS: this is instructions on how to improve the HSI suffix +msgid "This system has HSI runtime issues." +msgstr "Questo sistema presenta dei problemi di runtime HSI." + +#. TRANSLATORS: this is instructions on how to improve the HSI security level +msgid "This system has a low HSI security level." +msgstr "Questo sistema ha un livello di sicurezza HSI basso." + +#. TRANSLATORS: description of dbxtool +msgid "This tool allows an administrator to apply UEFI dbx updates." +msgstr "Questo strumento consente a un amministratore di applicare aggiornamenti UEFI dbx." + +#. TRANSLATORS: CLI description +msgid "This tool allows an administrator to debug UpdateCapsule operation." +msgstr "Questo strumento consente a un amministratore di eseguire debug sulle operazioni UpdateCapsule." + +#. TRANSLATORS: CLI description +msgid "This tool allows an administrator to query and control the fwupd daemon, allowing them to perform actions such as installing or downgrading firmware." +msgstr "Questo strumento consente a un amministratore di inviare richieste e controllare il demone fwupd per eseguire azioni come l'installazione o la retrocessione del firmware." + +#. TRANSLATORS: CLI description +msgid "This tool allows an administrator to use the fwupd plugins without being installed on the host system." +msgstr "Questo strumento consente a un amministratore di utilizzare i plugin fwupd senza che siano installati sul sistema host." + +#. TRANSLATORS: CLI description +msgid "This tool can be used from other tools and from shell scripts." +msgstr "Questo strumento può essere utilizzato da altri strumenti o da script shell." + #. TRANSLATORS: the user needs to stop playing with stuff msgid "This tool can only be used by the root user" msgstr "Questo strumento può essere usato solamente dall'utente root" +#. TRANSLATORS: CLI description +msgid "This tool will read and parse the TPM event log from the system firmware." +msgstr "Questo strumento legge e analizza il registro eventi TPM dal firmware di sistema." + +#. TRANSLATORS: command line option +msgid "Timeout in milliseconds for each parse" +msgstr "Tempo massimo in millisecondi per ogni analisi" + +#. TRANSLATORS: The update state of the specific device +msgid "Transient failure" +msgstr "Errore transitorio" + #. TRANSLATORS: remote type, e.g. remote or local msgid "Type" msgstr "Tipo" +#. TRANSLATORS: partition refers to something on disk, again, hey Arch users +msgid "UEFI ESP partition not detected or configured" +msgstr "Partizione ESP UEFI non rilavata o non configurata" + #. TRANSLATORS: program name msgid "UEFI Firmware Utility" msgstr "Strumento firmware UEFI" +#. TRANSLATORS: capsule updates are an optional BIOS feature +msgid "UEFI capsule updates not available or enabled in firmware setup" +msgstr "Aggiornamenti capsula UEFI non disponibili o non abilitati nella configurazione firmware" + +#. TRANSLATORS: program name +msgid "UEFI dbx Utility" +msgstr "Strumento EUFI dbx" + +#. TRANSLATORS: Title: PK is the 'platform key' for the machine +msgid "UEFI platform key" +msgstr "Chiave piattaforma UEFI" + +#. TRANSLATORS: Title: SB is a way of locking down UEFI +msgid "UEFI secure boot" +msgstr "Avvio sicuro UEFI" + +#. TRANSLATORS: error message +msgid "Unable to connect to service" +msgstr "Impossibile collegarsi al servizio" + +#. TRANSLATORS: command description +msgid "Unbind current driver" +msgstr "Svincola il driver attuale" + +#. TRANSLATORS: we will now offer this firmware to the user +msgid "Unblocking firmware:" +msgstr "Sblocco del firmware:" + +#. TRANSLATORS: command description +msgid "Unblocks a specific firmware from being installed" +msgstr "Sblocca un firmware specifico dal non essere installato" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Unencrypted" +msgstr "Non cifrato" + #. TRANSLATORS: current daemon status is unknown #. TRANSLATORS: we don't know the license of the update #. TRANSLATORS: unknown release urgency @@ -1293,10 +1902,18 @@ msgid "Unlock the device to allow access" msgstr "Sblocco del dispositivo per consentire l'accesso" +#. TRANSLATORS: Suffix: the HSI result +msgid "Unlocked" +msgstr "Sbloccato" + #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "Sblocca il dispositivo per accedere al firmware" +#. TRANSLATORS: command description +msgid "Unmounts the ESP" +msgstr "Smonta l'ESP" + #. TRANSLATORS: command line option msgid "Unset the debugging flag during update" msgstr "Ripristina il flag di debug durante l'aggiornamento" @@ -1306,6 +1923,10 @@ msgid "Unsupported daemon version %s, client version is %s" msgstr "Demone versione %s non supportato, la versione del client è %s" +#. TRANSLATORS: Suffix: the HSI result +msgid "Untainted" +msgstr "Integro" + #. TRANSLATORS: Device is updatable in this or any other mode msgid "Updatable" msgstr "Aggiornabile" @@ -1354,6 +1975,9 @@ msgid "Updates all firmware to latest versions available" msgstr "Aggiorna tutti i firmware all'ultima versione disponibile" +msgid "Updating" +msgstr "Aggiornamento in corso" + #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second and third are #. * version numbers e.g. "1.2.3" @@ -1372,10 +1996,6 @@ msgid "Upgrade available for %s from %s to %s" msgstr "Aggiornamento disponibile per %s da %s a %s" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Messaggio di caricamento:" - msgid "Upload report just this one time, but prompt again for future updates" msgid_plural "Upload reports just this one time, but prompt again for future updates" msgstr[0] "Caricare il rapporto ora e chiedere nuovamente con i prossimi aggiornamenti" @@ -1398,6 +2018,14 @@ msgid "Urgency" msgstr "Urgenza" +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdmgr --help for help" +msgstr "Usare «fwupdmgr --help» per maggiori informazioni" + +#. TRANSLATORS: error message explaining command to run to how to get help +msgid "Use fwupdtool --help for help" +msgstr "Usare «fwupdtool --help» per maggiori informazioni" + #. TRANSLATORS: command line option msgid "Use quirk flags when installing firmware" msgstr "Usa flag quirk nell'installare il firmware" @@ -1410,6 +2038,17 @@ msgid "Username" msgstr "Nome utente" +msgid "VID:PID" +msgstr "VID:PID" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Valid" +msgstr "Valido" + +#. TRANSLATORS: ESP refers to the EFI System Partition +msgid "Validating ESP contents…" +msgstr "Verifica contenuti ESP…" + #. TRANSLATORS: one line variant of release (e.g. 'Prerelease' or 'China') msgid "Variant" msgstr "Variante" @@ -1422,19 +2061,19 @@ msgid "Verifying…" msgstr "Verifica…" -#. TRANSLATORS: try to help -msgid "WARNING: Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" -msgstr "Attenzione: controlli SSL ignorati, per fare ciò automaticamente in futuro, esportare DISABLE_SSL_STRICT nel proprio ambiente" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Versione" + +#. TRANSLATORS: this is a prefix on the console +msgid "WARNING:" +msgstr "Attenzione:" #. TRANSLATORS: waiting for device to do something msgid "Waiting…" msgstr "Attesa…" #. TRANSLATORS: command description -msgid "Watch DFU devices being hotplugged" -msgstr "Controlla i dispositivi DFU che sono collegati a caldo" - -#. TRANSLATORS: command description msgid "Watch for hardware changes" msgstr "Controlla le modifiche hardware" @@ -1446,6 +2085,10 @@ msgid "Write firmware from file into one partition" msgstr "Scrive il firmware dal file in una partizione" +#. TRANSLATORS: decompressing images from a container firmware +msgid "Writing file:" +msgstr "Scrittura file:" + #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Scrittura…" @@ -1454,19 +2097,39 @@ msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "La propria distribuzione potrebbe non aver verificato la compatibilità degli aggiornamenti firmware col proprio sistema o col dispositivo collegato." +#. TRANSLATORS: %1 is the device vendor name +#, c-format +msgid "Your hardware may be damaged using this firmware, and installing this release may void any warranty with %s." +msgstr "Utilizzando questo firmware, l'hardware potrebbe danneggiarsi; inoltre, l'installazione di questa versione potrebbe annullare la garanzia con %s." + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "[CHECKSUM]" +msgstr "[CHECKSUM]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "[DEVICE-ID|GUID]" +msgstr "[ID-DISPOSITIVO|GUID]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "[DEVICE-ID|GUID] [BRANCH]" +msgstr "[ID-DISPOSITIVO|GUID] [BRANCH]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "[FILE FILE_SIG REMOTE-ID]" +msgstr "[FILE SIG_FILE ID-REMOTO]" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "[SMBIOS-FILE|HWIDS-FILE]" +msgstr "[FILE-SMBIOS|FILE-HWIDS]" + +#. TRANSLATORS: this is the default branch name when unset +msgid "default" +msgstr "predefinito" + #. TRANSLATORS: program name msgid "fwupd TPM event log utility" msgstr "Strumento registro eventi TPM fwupd" -#. TRANSLATORS: message letting the user know no device upgrade available due -#. to missing on LVFS -#. * %1 is the device name -#, c-format -msgid "• %s has no available firmware updates" -msgstr "• %s non ha alcun aggiornamento firmware disponibile" - -#. TRANSLATORS: message letting the user know no device upgrade available -#. * %1 is the device name -#, c-format -msgid "• %s has the latest available firmware version" -msgstr "• %s ha la versione più recente del firmware" +#. TRANSLATORS: Title: if the fwupd plugins are all present and correct +msgid "fwupd plugins" +msgstr "Plugin fwupd" diff -Nru fwupd-1.4.5/po/ko.po fwupd-1.5.8/po/ko.po --- fwupd-1.4.5/po/ko.po 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/po/ko.po 2021-03-31 20:08:32.000000000 +0000 @@ -22,6 +22,12 @@ msgid_plural "%.0f minutes remaining" msgstr[0] "%.0f분 남음" +#. TRANSLATORS: the CPU microcode is firmware loaded onto the CPU +#. * at system bootup +#, c-format +msgid "%s CPU Microcode Update" +msgstr "%s CPU 마이크로코드 업데이트" + #. TRANSLATORS: ME stands for Management Engine, where #. * the first %s is the device name, e.g. 'ThinkPad P50` #, c-format @@ -149,10 +155,6 @@ msgid "Activating firmware update for" msgstr "다음 장치의 펌웨어 업데이트 활성화 중:" -#. TRANSLATORS: this is when a device is hotplugged -msgid "Added" -msgstr "추가함" - #. TRANSLATORS: the age of the metadata msgid "Age" msgstr "경과 기간" @@ -268,7 +270,6 @@ msgid "Cancelled" msgstr "취소함" -#. TRANSLATORS: this is when a device is hotplugged #. TRANSLATORS: this is when the daemon state changes msgid "Changed" msgstr "바뀜" @@ -309,6 +310,18 @@ msgid "Continue with update?" msgstr "업데이트를 계속 진행하시겠습니까?" +#. TRANSLATORS: command description +msgid "Convert a firmware file" +msgstr "펌웨어 파일을 변환합니다" + +#. TRANSLATORS: when the update was built +msgid "Created" +msgstr "생성됨" + +#. TRANSLATORS: the release urgency +msgid "Critical" +msgstr "매우 높음" + #. TRANSLATORS: Device supports some form of checksum verification msgid "Cryptographic hash verification is available" msgstr "암호화 해시 검사 사용 가능" @@ -448,6 +461,7 @@ msgid "Do not write to the history database" msgstr "과거 기록 데이터베이스에 기록하지 않기" +#. TRANSLATORS: success #. success msgid "Done!" msgstr "완료!" @@ -492,6 +506,8 @@ msgid "Enable this remote?" msgstr "이 원격 설정을 활성화하시겠습니까?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "활성화 여부" @@ -530,10 +546,6 @@ msgid "Failed to connect to daemon" msgstr "데몬에 연결할 수 없음" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "서버 제한으로 파일을 다운로드할 수 없음" - #. TRANSLATORS: we could not get the devices to update offline msgid "Failed to get pending devices" msgstr "대기 중인 장치를 가져올 수 없음" @@ -566,22 +578,6 @@ msgid "Failed to set splash mode" msgstr "스플래시 모드를 설정할 수 없음" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "파일 가져오는 중" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "펌웨어 가져오는 중" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "메타데이터 가져오는 중" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "서명 가져오는 중" - #. TRANSLATORS: filename of the local file msgid "Filename" msgstr "파일 이름" @@ -626,6 +622,7 @@ msgid "Firmware updates are supported on this machine." msgstr "이 머신에서 펌웨어 업데이트를 지원합니다." +#. TRANSLATORS: description of plugin state, e.g. disabled #. TRANSLATORS: release properties msgid "Flags" msgstr "플래그" @@ -633,11 +630,20 @@ msgid "Force the action ignoring all warnings" msgstr "모든 경고를 무시하고 작업 강제 진행" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "감지 장치" + #. TRANSLATORS: global ID common to all similar hardware msgid "GUID" msgid_plural "GUIDs" msgstr[0] "GUID" +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgctxt "A single GUID" +msgid "GUID" +msgstr "GUID" + #. TRANSLATORS: command description msgid "Get all device flags supported by fwupd" msgstr "fwupd를 지원하는 모든 장치 정보를 가져옵니다" @@ -662,10 +668,6 @@ msgid "Gets the configured remotes" msgstr "원격 설정 정보를 가져옵니다" -#. TRANSLATORS: firmware approved by the admin -msgid "Gets the list of approved firmware." -msgstr "허용된 펌웨어 목록을 가져옵니다." - #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "연결한 하드웨어의 업데이트 목록을 가져옵니다" @@ -682,6 +684,10 @@ msgid "Hardware is waiting to be replugged" msgstr "하드웨어를 다시 연결해야 함" +#. TRANSLATORS: the release urgency +msgid "High" +msgstr "높음" + #. TRANSLATORS: daemon is inactive msgid "Idle…" msgstr "대기 중…" @@ -784,9 +790,13 @@ msgid "Loading…" msgstr "불러오는 중…" -#. TRANSLATORS: command line option -msgid "Manually whitelist specific plugins" -msgstr "지정한 플러그인을 수동으로 허용 목록에 추가" +#. TRANSLATORS: the release urgency +msgid "Low" +msgstr "낮음" + +#. TRANSLATORS: the release urgency +msgid "Medium" +msgstr "중간" #. TRANSLATORS: remote URI msgid "Metadata Signature" @@ -809,10 +819,6 @@ msgid "Mismatched daemon and client, use %s instead" msgstr "데몬과 클라이언트가 일치하지 않음, %s을(를) 대신 사용함" -#. TRANSLATORS: sets something in daemon.conf -msgid "Modifies a daemon configuration value." -msgstr "데몬 설정값을 변경합니다." - #. TRANSLATORS: command description msgid "Modifies a given remote" msgstr "지정한 원격 정보를 수정합니다" @@ -839,6 +845,7 @@ msgid "New version" msgstr "새 버전" +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "동작을 지정하지 않았습니다!" @@ -876,15 +883,15 @@ msgid "No updates were applied" msgstr "적용된 업데이트 없음" +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "확인" + #. TRANSLATORS: command line option msgid "Only show single PCR value" msgstr "단일 PCR 값만 표시" #. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "플러그인 경고 무시" - -#. TRANSLATORS: command line option msgid "Override the default ESP path" msgstr "기본 ESP 경로 재정의" @@ -967,8 +974,8 @@ msgstr "원격 서버의 메타데이터를 새로 고칩니다" #. TRANSLATORS: command description -msgid "Reinstall current firmware on the device." -msgstr "장치에 현재 펌웨어를 다시 설치합니다." +msgid "Reinstall firmware on a device" +msgstr "장치에 펌웨어를 다시 설치합니다" #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second is a version number @@ -982,10 +989,6 @@ msgid "Remote ID" msgstr "원격 ID" -#. TRANSLATORS: this is when a device is hotplugged -msgid "Removed" -msgstr "제거함" - #. TRANSLATORS: command description msgid "Replace data in an existing firmware file" msgstr "기존 펌웨어 파일의 데이터 교체" @@ -998,10 +1001,6 @@ msgid "Reported to remote server" msgstr "원격 서버에 보고됨" -#. TRANSLATORS: Must be plugged in to an outlet -msgid "Requires AC power" -msgstr "AC 전원 필요함" - #. TRANSLATORS: Requires a bootloader mode to be manually enabled by the user msgid "Requires a bootloader" msgstr "부트로더 모드 진입 필요함" @@ -1061,13 +1060,10 @@ msgid "Set the debugging flag during update" msgstr "업데이트 중 디버깅 플래그 설정" +#. TRANSLATORS: firmware approved by the admin msgid "Sets the list of approved firmware" msgstr "허용된 펌웨어 목록 설정" -#. TRANSLATORS: firmware approved by the admin -msgid "Sets the list of approved firmware." -msgstr "허용된 펌웨어 목록을 설정합니다." - #. TRANSLATORS: command description msgid "Share firmware history with the developers" msgstr "개발사와 펌웨어 업데이트 기록 공유하기" @@ -1324,10 +1320,6 @@ msgid "Upgrade available for %s from %s to %s" msgstr "%s 업그레이드 사용 가능: %s에서 %s(으)로" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "업로드 메시지:" - msgid "Upload report just this one time, but prompt again for future updates" msgid_plural "Upload reports just this one time, but prompt again for future updates" msgstr[0] "이번 한 번만 보고서를 업로드하고 다음에 업데이트할 때 묻기" @@ -1344,6 +1336,10 @@ msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." msgstr "펌웨어 보고서를 업로드하면 하드웨어 제작사에서 실제 장치에 업데이트를 적용했을 때 성공 및 실패 여부를 빠르게 알 수 있습니다." +#. TRANSLATORS: how important the release is +msgid "Urgency" +msgstr "중요도" + #. TRANSLATORS: command line option msgid "Use quirk flags when installing firmware" msgstr "펌웨어를 설치할 때 quirk 플래그 사용" @@ -1368,19 +1364,15 @@ msgid "Verifying…" msgstr "검증 중…" -#. TRANSLATORS: try to help -msgid "WARNING: Ignoring SSL strict checks, to do this automatically in the future export DISABLE_SSL_STRICT in your environment" -msgstr "경고: SSL 엄격 검사를 건너뜁니다. 이 옵션을 자동으로 지정하려면 DISABLE_SSL_STRICT 환경 변수를 지정하십시오" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "버전" #. TRANSLATORS: waiting for device to do something msgid "Waiting…" msgstr "기다리는 중…" #. TRANSLATORS: command description -msgid "Watch DFU devices being hotplugged" -msgstr "DFU 핫 플러그 장치 보기" - -#. TRANSLATORS: command description msgid "Watch for hardware changes" msgstr "하드웨어 변경 사항 감시" @@ -1399,3 +1391,7 @@ #. TRANSLATORS: show the user a warning msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "배포판 개발사에서 펌웨어 업데이트와 시스템 및 연결된 장치간의 호환성을 검증한다는 보장이 없습니다." + +#. TRANSLATORS: program name +msgid "fwupd TPM event log utility" +msgstr "fwupd TPM 이벤트 로그 유틸리티" diff -Nru fwupd-1.4.5/po/LINGUAS fwupd-1.5.8/po/LINGUAS --- fwupd-1.4.5/po/LINGUAS 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/po/LINGUAS 2021-03-31 20:08:32.000000000 +0000 @@ -10,6 +10,7 @@ fi fr fur +gl he hi hr diff -Nru fwupd-1.4.5/po/lt.po fwupd-1.5.8/po/lt.po --- fwupd-1.4.5/po/lt.po 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/po/lt.po 2021-03-31 20:08:32.000000000 +0000 @@ -4,6 +4,7 @@ # # Translators: # Moo, 2019 +# Moo, 2020-2021 msgid "" msgstr "" "Project-Id-Version: fwupd\n" @@ -54,6 +55,11 @@ msgid "%s Update" msgstr "%s atnaujinimas" +#. TRANSLATORS: Title: %s is ME kind, e.g. CSME/TXT +#, c-format +msgid "%s version" +msgstr "%s versija" + #. TRANSLATORS: command description msgid "Activate devices" msgstr "Aktyvuoti įrenginius" @@ -73,10 +79,6 @@ msgid "Activating firmware update for" msgstr "Aktyvuojama programinė aparatinė įranga, skirta" -#. TRANSLATORS: this is when a device is hotplugged -msgid "Added" -msgstr "Pridėtas" - #. TRANSLATORS: the age of the metadata msgid "Age" msgstr "Amžius" @@ -94,6 +96,10 @@ msgid "Allow downgrading firmware versions" msgstr "Leisti sendinti programinės aparatinės įrangos versijas" +#. TRANSLATORS: command line option +msgid "Allow reinstalling existing firmware versions" +msgstr "Leisti iš naujo įdiegti esamas programinės aparatinės įrangos versijas" + #. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Atnaujinimo užbaigimui, reikia paleisti sistemą iš naujo." @@ -110,6 +116,14 @@ msgid "Apply firmware updates" msgstr "Taikyti programinės aparatinės įrangos atnaujinimus" +#. TRANSLATORS: command line option +msgid "Apply update files" +msgstr "Taikyti atnaujinimo failus" + +#. TRANSLATORS: actually sending the update to the hardware +msgid "Applying update…" +msgstr "Taikomas atnaujinimas…" + #. TRANSLATORS: command description msgid "Attach to firmware mode" msgstr "Pridėti į programinės aparatinės įrangos veikseną" @@ -131,6 +145,10 @@ msgstr "Norint modifikuoti programinės aparatinės įrangos atnaujinimams naudojamą sukonfigūruotą saugyklą, reikalingas tapatybės nustatymas" #. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify daemon configuration" +msgstr "Norint modifikuoti tarnybos konfigūraciją, reikalingas tapatybės nustatymas" + +#. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to set the list of approved firmware" msgstr "Norint nustatyti patvirtintos programinės aparatinės įrangos sąrašą, reikalingas tapatybės nustatymas" @@ -170,7 +188,6 @@ msgid "Cancelled" msgstr "Atsisakyta" -#. TRANSLATORS: this is when a device is hotplugged #. TRANSLATORS: this is when the daemon state changes msgid "Changed" msgstr "Pakeistas" @@ -199,6 +216,14 @@ msgid "Command not found" msgstr "Komanda nerasta" +#. TRANSLATORS: when the update was built +msgid "Created" +msgstr "Sukurtas" + +#. TRANSLATORS: version number of current firmware +msgid "Current version" +msgstr "Dabartinė versija" + #. TRANSLATORS: DFU stands for device firmware update msgid "DFU Utility" msgstr "ĮPAĮA paslaugų programa" @@ -219,6 +244,10 @@ msgid "Detach to bootloader mode" msgstr "Atskirti į pradinio įkėliklio veikseną" +#. TRANSLATORS: description of device ability +msgid "Device Flags" +msgstr "Įrenginio vėliavėlės" + #. TRANSLATORS: ID for hardware, typically a SHA1 sum msgid "Device ID" msgstr "Įrenginio ID" @@ -231,6 +260,10 @@ msgid "Device changed:" msgstr "Pakeistas įrenginys:" +#. TRANSLATORS: Is locked and can be unlocked +msgid "Device is locked" +msgstr "Įrenginys yra užrakintas" + #. TRANSLATORS: this is when a device is hotplugged msgid "Device removed:" msgstr "Pašalintas įrenginys:" @@ -243,6 +276,11 @@ msgid "Devices that were not updated correctly:" msgstr "Įrenginiai, kurie nebuvo teisingai atnaujinti:" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is inactive and not used +msgid "Disabled" +msgstr "Išjungtas" + msgid "Disabled fwupdate debugging" msgstr "Išjungtas fwupdate derinimas" @@ -270,6 +308,7 @@ msgid "Do not write to the history database" msgstr "Nerašyti į istorijos duomenų bazę" +#. TRANSLATORS: success #. success msgid "Done!" msgstr "Atlikta!" @@ -298,6 +337,10 @@ msgid "Dump SMBIOS data from a file" msgstr "Iškloti SMBIOS duomenis iš failo" +#. TRANSLATORS: length of time the update takes to apply +msgid "Duration" +msgstr "Trukmė" + #. TRANSLATORS: ESP is EFI System Partition msgid "ESP specified was not valid" msgstr "Nurodytas ESS (angl. ESP) nebuvo teisingas" @@ -310,6 +353,8 @@ msgid "Enable this remote?" msgstr "Įjungti šią nuotolinę saugyklą?" +#. TRANSLATORS: Suffix: the HSI result +#. TRANSLATORS: Plugin is active and in use #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Įjungta" @@ -325,6 +370,10 @@ msgid "Enabling this remote is done at your own risk." msgstr "Šios nuotolinės saugyklos įjungimas yra jūsų pačių rizika." +#. TRANSLATORS: Suffix: the HSI result +msgid "Encrypted" +msgstr "Šifruotas" + #. TRANSLATORS: command description msgid "Erase all firmware update history" msgstr "Ištrinti visą programinės aparatinės įrangos atnaujinimų istoriją" @@ -341,14 +390,19 @@ msgid "Exit after the engine has loaded" msgstr "Išeiti, įkėlus modulį" +#. TRANSLATORS: Suffix: the fallback HSI result +#. TRANSLATORS: The update state of the specific device +msgid "Failed" +msgstr "Patyrė nesėkmę" + +#. TRANSLATORS: dbx file failed to be applied as an update +msgid "Failed to apply update" +msgstr "Nepavyko pritaikyti atnaujinimo" + #. TRANSLATORS: we could not talk to the fwupd daemon msgid "Failed to connect to daemon" msgstr "Nepavyko prisijungti prie tarnybos" -#. TRANSLATORS: the server is rate-limiting downloads -msgid "Failed to download due to server limit" -msgstr "Nepavyko atsisiųsti dėl serverio apribojimo" - #. TRANSLATORS: we could not get the devices to update offline msgid "Failed to get pending devices" msgstr "Nepavyko gauti laukiančių įrenginių" @@ -365,6 +419,10 @@ msgid "Failed to parse arguments" msgstr "Nepavyko išanalizuoti argumentų" +#. TRANSLATORS: failed to read measurements file +msgid "Failed to parse file" +msgstr "Nepavyko išanalizuoti failo" + #. TRANSLATORS: we could not reboot for some reason msgid "Failed to reboot" msgstr "Nepavyko paleisti iš naujo" @@ -373,22 +431,6 @@ msgid "Failed to set splash mode" msgstr "Nepavyko nustatyti prisistatymo lango veikseną" -#. TRANSLATORS: downloading unknown file -msgid "Fetching file" -msgstr "Gaunamas failas" - -#. TRANSLATORS: downloading new firmware file -msgid "Fetching firmware" -msgstr "Gaunama programinė aparatinė įranga" - -#. TRANSLATORS: downloading new metadata file -msgid "Fetching metadata" -msgstr "Gaunami metaduomenys" - -#. TRANSLATORS: downloading new signing file -msgid "Fetching signature" -msgstr "Gaunamas parašas" - #. TRANSLATORS: filename of the local file msgid "Filename" msgstr "Failo pavadinimas" @@ -397,6 +439,10 @@ msgid "Filename Signature" msgstr "Failo pavadinimo parašas" +#. TRANSLATORS: user did not include a filename parameter +msgid "Filename required" +msgstr "Reikalingas failo pavadinimas" + #. TRANSLATORS: program name msgid "Firmware Agent" msgstr "Programinės aparatinės įrangos agentas" @@ -417,12 +463,17 @@ msgid "Firmware Utility" msgstr "Programinės aparatinės įrangos paslaugų programa" +#. TRANSLATORS: Title: if firmware updates are available +msgid "Firmware updates" +msgstr "Programinės aparatinės įrangos atnaujinimai" + msgid "Firmware updates are not supported on this machine." msgstr "Šiame kompiuteryje programinės aparatinės įrangos atnaujinimai yra neprieinami." msgid "Firmware updates are supported on this machine." msgstr "Šiame kompiuteryje yra prieinami programinės aparatinės įrangos atnaujinimai." +#. TRANSLATORS: description of plugin state, e.g. disabled #. TRANSLATORS: release properties msgid "Flags" msgstr "Vėliavėlės" @@ -430,6 +481,15 @@ msgid "Force the action ignoring all warnings" msgstr "Priverstinai atlikti veiksmą nepaisant visų įspėjimų" +#. TRANSLATORS: Suffix: the HSI result +msgid "Found" +msgstr "Rastas" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgctxt "A single GUID" +msgid "GUID" +msgstr "GUID" + #. TRANSLATORS: command description msgid "Get all devices and possible releases" msgstr "Gauti visus įrenginius ir galimas laidas" @@ -450,10 +510,6 @@ msgid "Gets the configured remotes" msgstr "Gauna sukonfigūruotas nuotolines saugyklas" -#. TRANSLATORS: firmware approved by the admin -msgid "Gets the list of approved firmware." -msgstr "Gauna patvirtintos programinės aparatinės įrangos sąrašą." - #. TRANSLATORS: command description msgid "Gets the list of updates for connected hardware" msgstr "Gauna atnaujinimų sąrašą prijungtai aparatinei įrangai" @@ -470,6 +526,10 @@ msgid "Idle…" msgstr "Neveiklus…" +#. TRANSLATORS: length of time the update takes to apply +msgid "Install Duration" +msgstr "Įdiegimo trukmė" + #. TRANSLATORS: command description msgid "Install a firmware blob on a device" msgstr "Įdiegti įrenginyje programinės aparatinės įrangos dvejetainį išplėstinį objektą" @@ -506,6 +566,10 @@ msgid "Installing on %s…" msgstr "Įdiegiama ties %s…" +#. TRANSLATORS: Device cannot be removed easily +msgid "Internal device" +msgstr "Vidinis įrenginys" + msgid "Keyring" msgstr "Raktinė" @@ -513,12 +577,20 @@ msgid "Less than one minute remaining" msgstr "Liko mažiau kaip viena minutė" +#. TRANSLATORS: e.g. GPLv2+, Proprietary etc +msgid "License" +msgstr "Licencija" + msgid "Linux Vendor Firmware Service (stable firmware)" msgstr "Linux tiekėjų programinės aparatinės įrangos paslauga (stabili programinė aparatinė įranga)" msgid "Linux Vendor Firmware Service (testing firmware)" msgstr "Linux tiekėjų programinės aparatinės įrangos paslauga (testuojama programinė aparatinė įranga)" +#. TRANSLATORS: Title: if it's tainted or not +msgid "Linux kernel" +msgstr "Linux branduolys" + #. TRANSLATORS: command line option msgid "List supported firmware updates" msgstr "Išvardyti prieinamus programinės aparatinės įrangos atnaujinimus" @@ -527,9 +599,13 @@ msgid "Loading…" msgstr "Įkeliama…" -#. TRANSLATORS: command line option -msgid "Manually whitelist specific plugins" -msgstr "Rankiniu būdu įtraukti tam tikrus įskiepius į baltąjį sąrašą" +#. TRANSLATORS: Suffix: the HSI result +msgid "Locked" +msgstr "Užrakintas" + +#. TRANSLATORS: remote URI +msgid "Metadata Signature" +msgstr "Metaduomenų parašas" #. TRANSLATORS: remote URI msgid "Metadata URI" @@ -546,10 +622,18 @@ msgid "Modify a configured remote" msgstr "Modifikuoti sukonfigūruotą nuotolinę saugyklą" +msgid "Modify daemon configuration" +msgstr "Modifikuoti tarnybos konfigūraciją" + #. TRANSLATORS: command description msgid "Monitor the daemon for events" msgstr "Stebėti tarnybą, ar yra įvykių" +#. TRANSLATORS: version number of new firmware +msgid "New version" +msgstr "Nauja versija" + +#. TRANSLATORS: user did not tell the tool what to do msgid "No action specified!" msgstr "Nenurodytas joks veiksmas!" @@ -569,9 +653,17 @@ msgid "No updates were applied" msgstr "Nebuvo pritaikyti jokie atnaujinimai" -#. TRANSLATORS: command line option -msgid "Override plugin warning" -msgstr "Nustelbti įskiepio įspėjimą" +#. TRANSLATORS: Suffix: the HSI result +msgid "Not found" +msgstr "Nerastas" + +#. TRANSLATORS: Suffix: the HSI result +msgid "Not supported" +msgstr "Nepalaikomas" + +#. TRANSLATORS: Suffix: the HSI result +msgid "OK" +msgstr "Gerai" #. TRANSLATORS: command line option msgid "Override the default ESP path" @@ -593,6 +685,10 @@ msgid "Please enter a number from 0 to %u: " msgstr "Įveskite skaičių nuo 0 iki %u: " +#. TRANSLATORS: version number of previous firmware +msgid "Previous version" +msgstr "Ankstesnė versija" + msgid "Print the version number" msgstr "Parodyti versijos numerį" @@ -606,6 +702,10 @@ msgid "Proceed with upload?" msgstr "Tęsti išsiuntimą?" +#. TRANSLATORS: a non-free software license +msgid "Proprietary" +msgstr "Nuosavybinė" + #. TRANSLATORS: command line option msgid "Query for firmware update support" msgstr "Užklausti programinės aparatinės įrangos atnaujinimų palaikymo" @@ -618,6 +718,11 @@ msgid "Read firmware from one partition into a file" msgstr "Skaityti programinę aparatinę įrangą iš vieno skaidinio į failą" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Reading from %s…" +msgstr "Skaitoma iš %s…" + #. TRANSLATORS: reading from the flash chips msgid "Reading…" msgstr "Skaitoma…" @@ -642,10 +747,6 @@ msgid "Remote ID" msgstr "Nuotolinės saugyklos ID" -#. TRANSLATORS: this is when a device is hotplugged -msgid "Removed" -msgstr "Pašalintas" - #. TRANSLATORS: command description msgid "Replace data in an existing firmware file" msgstr "Pakeisti duomenis esamame programinės aparatinės įrangos faile" @@ -690,22 +791,32 @@ msgid "Scheduling…" msgstr "Suplanuojama…" +#. TRANSLATORS: %s is a link to a website +#, c-format +msgid "See %s for more information." +msgstr "Išsamesnei informacijai, žiūrėkite %s" + +#. TRANSLATORS: Device has been chosen by the daemon for the user +msgid "Selected device" +msgstr "Pasirinktas įrenginys" + #. TRANSLATORS: command line option msgid "Set the debugging flag during update" msgstr "Atnaujinimo metu nustatyti derinimo vėliavėlę" +#. TRANSLATORS: firmware approved by the admin msgid "Sets the list of approved firmware" msgstr "Nustato patvirtintą programinės aparatinės įrangos sąrašą" -#. TRANSLATORS: firmware approved by the admin -msgid "Sets the list of approved firmware." -msgstr "Nustato patvirtintos programinės aparatinės įrangos sąrašą." - #. TRANSLATORS: command description msgid "Share firmware history with the developers" msgstr "Bendrinti programinės aparatinės įrangos istoriją su plėtotojais" #. TRANSLATORS: command line option +msgid "Show all results" +msgstr "Rodyti visus rezultatus" + +#. TRANSLATORS: command line option msgid "Show client and daemon versions" msgstr "Rodyti kliento ir tarnybos versijas" @@ -755,6 +866,10 @@ msgid "Signature" msgstr "Parašas" +#. TRANSLATORS: file size of the download +msgid "Size" +msgstr "Dydis" + msgid "Specify Vendor/Product ID(s) of DFU device" msgstr "Nurodyti ĮPAĮA įrenginio tiekėją/produkto ID" @@ -765,6 +880,22 @@ msgid "Summary" msgstr "Santrauka" +#. TRANSLATORS: Suffix: the HSI result +msgid "Supported" +msgstr "Palaikomas" + +#. TRANSLATORS: Is found in current metadata +msgid "Supported on remote server" +msgstr "Palaikomas nuotoliniame serveryje" + +#. TRANSLATORS: Must be plugged in to an outlet +msgid "System requires external power source" +msgstr "Sistema reikalauja išorinio maitinimo šaltinio" + +#. TRANSLATORS: command argument: uppercase, spaces->dashes +msgid "TEXT" +msgstr "TEKSTAS" + msgid "Target" msgstr "Paskirtis" @@ -789,15 +920,27 @@ msgid "UEFI Firmware Utility" msgstr "UEFI programinės aparatinės įrangos paslaugų programa" +#. TRANSLATORS: Suffix: the HSI result +msgid "Unencrypted" +msgstr "Nešifruotas" + #. TRANSLATORS: current daemon status is unknown #. TRANSLATORS: we don't know the license of the update #. TRANSLATORS: unknown release urgency msgid "Unknown" msgstr "Nežinoma" +#. TRANSLATORS: Name of hardware +msgid "Unknown Device" +msgstr "Nežinomas įrenginys" + msgid "Unlock the device to allow access" msgstr "Atrakinti įrenginį, kad būtų leista prieiga" +#. TRANSLATORS: Suffix: the HSI result +msgid "Unlocked" +msgstr "Atrakintas" + #. TRANSLATORS: command description msgid "Unlocks the device for firmware access" msgstr "Atrakina įrenginį programinės aparatinės įrangos prieigai" @@ -806,6 +949,23 @@ msgid "Unset the debugging flag during update" msgstr "Atnaujinimo metu panaikinti derinimo vėliavėlės nustatymą" +#. TRANSLATORS: Device is updatable in this or any other mode +msgid "Updatable" +msgstr "Galimas atnaujinti" + +#. TRANSLATORS: error message from last update attempt +msgid "Update Error" +msgstr "Atnaujinimo klaida" + +#. TRANSLATORS: helpful messages from last update +#. TRANSLATORS: helpful messages for the update +msgid "Update Message" +msgstr "Atnaujinimo pranešimas" + +#. TRANSLATORS: hardware state, e.g. "pending" +msgid "Update State" +msgstr "Atnaujinimo būsena" + #. TRANSLATORS: command description msgid "Update all devices that match local metadata" msgstr "Atnaujinti visus įrenginius, kurie atitinka vietinius metaduomenis" @@ -818,6 +978,10 @@ msgid "Update now?" msgstr "Atnaujinti dabar?" +#. TRANSLATORS: Update can only be done from offline mode +msgid "Update requires a reboot" +msgstr "Atnaujinimas reikalauja paleidimo iš naujo" + msgid "Update the stored device verification information" msgstr "Atnaujinti saugomo įrenginio patikrinimo informaciją" @@ -841,10 +1005,6 @@ msgid "Updating %s…" msgstr "Atnaujinama %s…" -#. TRANSLATORS: the server sent the user a small message -msgid "Upload message:" -msgstr "Išsiuntimo žinutė:" - #. TRANSLATORS: ask the user to upload msgid "Upload report now?" msgstr "Išsiųsti ataskaitą dabar?" @@ -857,19 +1017,27 @@ msgid "Username" msgstr "Naudotojo vardas" +#. TRANSLATORS: one line variant of release (e.g. 'Prerelease' or 'China') +msgid "Variant" +msgstr "Variantas" + #. TRANSLATORS: verifying we wrote the firmware correctly msgid "Verifying…" msgstr "Patikrinama…" +#. TRANSLATORS: the detected version number of the dbx +msgid "Version" +msgstr "Versija" + +#. TRANSLATORS: this is a prefix on the console +msgid "WARNING:" +msgstr "ĮSPĖJIMAS:" + #. TRANSLATORS: waiting for device to do something msgid "Waiting…" msgstr "Laukiama…" #. TRANSLATORS: command description -msgid "Watch DFU devices being hotplugged" -msgstr "Stebėti ĮPAĮA įrenginius, kurie atnaujinami nepaleidžiant iš naujo" - -#. TRANSLATORS: command description msgid "Watch for hardware changes" msgstr "Stebėti aparatinės įrangos pakeitimus" @@ -888,3 +1056,7 @@ #. TRANSLATORS: show the user a warning msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "Gali būti, kad jūsų platintojas, suderinamumui su jūsų sistema ar prijungtais įrenginiais, nėra patvirtinęs jokių programinės aparatinės įrangos atnaujinimų." + +#. TRANSLATORS: Title: if the fwupd plugins are all present and correct +msgid "fwupd plugins" +msgstr "fwupd įskiepiai" diff -Nru fwupd-1.4.5/po/make-images fwupd-1.5.8/po/make-images --- fwupd-1.4.5/po/make-images 2021-01-26 16:06:40.000000000 +0000 +++ fwupd-1.5.8/po/make-images 1970-01-01 00:00:00.000000000 +0000 @@ -1,183 +0,0 @@ -#!/usr/bin/python3 -""" This thing rasterizes text for use later """ - -# pylint: disable=wrong-import-position,too-many-locals,unused-argument -# pylint: disable=invalid-name,too-many-instance-attributes - -""" -SPDX-License-Identifier: LGPL-2.1+ -""" - - -import os -import sys -import gettext -import math -import cairo -import gi -gi.require_version('Pango', '1.0') -gi.require_version('PangoCairo', '1.0') -from gi.repository import Pango, PangoCairo -from PIL import Image - -def usage(return_code): - """ print usage and exit with the supplied return code """ - if return_code == 0: - out = sys.stdout - else: - out = sys.stderr - out.write("usage: make-images