diff --git a/.lgtm.yml b/.lgtm.yml index 3cf702194..a817b260a 100644 --- a/.lgtm.yml +++ b/.lgtm.yml @@ -14,8 +14,10 @@ extraction: - "wget -O libxmlb.zip https://github.com/hughsie/libxmlb/archive/0.1.7.zip" - "mkdir -p subprojects/libxmlb" - "bsdtar --strip-components=1 -xvf libxmlb.zip -C subprojects/libxmlb" + - "wget -O flashrom.zip https://github.com/hughsie/flashrom/archive/wip/hughsie/fwupd.zip" + - "mkdir -p subprojects/flashrom" + - "bsdtar --strip-components=1 -xvf flashrom.zip -C subprojects/flashrom" index: build_command: - "meson setup build" - "ninja -C build" - diff --git a/contrib/PKGBUILD b/contrib/PKGBUILD index 1de05f373..359ea8dd1 100644 --- a/contrib/PKGBUILD +++ b/contrib/PKGBUILD @@ -17,7 +17,7 @@ makedepends=('meson' 'valgrind' 'gobject-introspection' 'gtk-doc' 'python-pillow build() { cd ${pkgname} if [ -n "$CI" ]; then - export CI="--werror" + export CI="--werror --wrap-mode=default" fi arch-meson -D b_lto=false $CI ../build diff --git a/contrib/ci/debian_s390x.sh b/contrib/ci/debian_s390x.sh index c2ff250fa..9b277ff5f 100755 --- a/contrib/ci/debian_s390x.sh +++ b/contrib/ci/debian_s390x.sh @@ -16,6 +16,7 @@ cd build meson .. \ --cross-file s390x_cross.txt \ --werror \ + -Dplugin_flashrom=false \ -Dplugin_uefi=false \ -Dplugin_dell=false \ -Dplugin_modem_manager=false \ diff --git a/contrib/ci/dependencies.xml b/contrib/ci/dependencies.xml index 463aaaedf..047f51810 100644 --- a/contrib/ci/dependencies.xml +++ b/contrib/ci/dependencies.xml @@ -142,6 +142,42 @@ + + + libftdi + + + libftdi-devel + + + libftdi-devel + + + + + + + + + + + + pciutils + + + pciutils-devel + + + pciutils-devel + + + + + + + + + noto-fonts diff --git a/contrib/debian/rules b/contrib/debian/rules index 2232148d3..52f315227 100755 --- a/contrib/debian/rules +++ b/contrib/debian/rules @@ -11,7 +11,7 @@ ifeq "$(DEB_HOST_ARCH_BITS)" "32" endif ifneq ($(CI),) - export CI=--werror + export CI=--werror --wrap-mode=default endif SB_STYLE := debian @@ -58,6 +58,9 @@ override_dh_install: if [ -n "$CI" ] && [ -f debian/tmp/usr/lib/xb-tool ]; then \ dh_install -pfwupd usr/lib/xb-tool ;\ fi + if [ -n "$CI" ] && [ -f debian/tmp/usr/sbin/flashrom ]; then \ + dh_install -pfwupd usr/sbin/flashrom ;\ + fi dh_missing -a --fail-missing #this is placed in fwupd-tests diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index e47b0e059..ec48ddfb3 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -10,6 +10,7 @@ %global enable_ci 0 %global enable_tests 1 %global enable_dummy 1 +%global __meson_wrap_mode default # fwupd.efi is only available on these arches %ifarch x86_64 aarch64 @@ -151,6 +152,7 @@ Data files for installed tests. %else -Dplugin_dummy=false \ %endif + -Dplugin_flashrom=true \ -Dplugin_thunderbolt=true \ %if 0%{?have_redfish} -Dplugin_redfish=true \ @@ -202,6 +204,12 @@ Data files for installed tests. mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg +# delete most files from the subproject +rm ${RPM_BUILD_ROOT}%{_includedir}/libflashrom.h +rm ${RPM_BUILD_ROOT}%{_libdir}/libflashrom.so +rm ${RPM_BUILD_ROOT}%{_libdir}/pkgconfig/libflashrom.pc +rm ${RPM_BUILD_ROOT}%{_sbindir}/flashrom + %find_lang %{name} %post @@ -327,6 +335,9 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %{_datadir}/locale/*/LC_IMAGES/fwupd* %endif +# eww, but just until the Fedora package ships these... +%{_libdir}/libflashrom.so.1* + %files devel %{_datadir}/gir-1.0/Fwupd-2.0.gir %{_datadir}/gtk-doc/html/libfwupd diff --git a/meson.build b/meson.build index b9aea3d74..1364e3b0b 100644 --- a/meson.build +++ b/meson.build @@ -278,6 +278,10 @@ if get_option('plugin_thunderbolt') conf.set('HAVE_THUNDERBOLT', '1') endif +if get_option('plugin_flashrom') + libflashrom = dependency('flashrom', fallback : ['flashrom', 'flashrom_dep']) +endif + if get_option('systemd') systemd = dependency('systemd', version : '>= 211') conf.set('HAVE_SYSTEMD' , '1') diff --git a/meson_options.txt b/meson_options.txt index 5d4163e85..d6520cf39 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -18,6 +18,7 @@ option('plugin_redfish', type : 'boolean', value : true, description : 'enable R option('plugin_uefi', type : 'boolean', value : true, description : 'enable UEFI 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_flashrom', type : 'boolean', value : true, description : 'enable libflashrom support') option('systemd', type : 'boolean', value : true, description : 'enable systemd support') option('systemdunitdir', type: 'string', value: '', description: 'Directory for systemd units') option('elogind', type : 'boolean', value : false, description : 'enable elogind support') diff --git a/plugins/flashrom/flashrom.quirk b/plugins/flashrom/flashrom.quirk index a5d833f49..aeb0d0e68 100644 --- a/plugins/flashrom/flashrom.quirk +++ b/plugins/flashrom/flashrom.quirk @@ -1,3 +1,8 @@ # Purism [HwId=a0ce5085-2dea-5086-ae72-45810a186ad0] DeviceId=librem15v3 + +# Libretrend +[HwId=52b68c34-6b31-5ecc-8a5c-de37e666ccd5] +DeviceId=LT1000 +VersionFormat=quad diff --git a/plugins/flashrom/fu-plugin-flashrom.c b/plugins/flashrom/fu-plugin-flashrom.c index adf41e3ca..3a1241a45 100644 --- a/plugins/flashrom/fu-plugin-flashrom.c +++ b/plugins/flashrom/fu-plugin-flashrom.c @@ -24,9 +24,15 @@ #include #include "fu-plugin-vfuncs.h" +#include "libflashrom.h" + +#define SELFCHECK_TRUE 1 struct FuPluginData { - gchar *flashrom_fn; + gsize flash_size; + struct flashrom_flashctx *flashctx; + struct flashrom_layout *layout; + struct flashrom_programmer *flashprog; }; void @@ -41,21 +47,72 @@ void fu_plugin_destroy (FuPlugin *plugin) { FuPluginData *data = fu_plugin_get_data (plugin); - g_free (data->flashrom_fn); + flashrom_layout_release (data->layout); + flashrom_programmer_shutdown (data->flashprog); + flashrom_flash_release (data->flashctx); +} + +static int +fu_plugin_flashrom_debug_cb (enum flashrom_log_level lvl, const char *fmt, va_list args) +{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wformat-nonliteral" + g_autofree gchar *tmp = g_strdup_vprintf (fmt, args); +#pragma clang diagnostic pop + switch (lvl) { + case FLASHROM_MSG_ERROR: + case FLASHROM_MSG_WARN: + g_warning ("%s", tmp); + break; + case FLASHROM_MSG_INFO: + case FLASHROM_MSG_DEBUG: + case FLASHROM_MSG_DEBUG2: + g_debug ("%s", tmp); + break; + case FLASHROM_MSG_SPEW: + break; + default: + break; + } + return 0; } gboolean fu_plugin_startup (FuPlugin *plugin, GError **error) { FuPluginData *data = fu_plugin_get_data (plugin); - GPtrArray *hwids; - g_autoptr(GError) error_local = NULL; - /* we need flashrom from the host system */ - data->flashrom_fn = fu_common_find_program_in_path ("flashrom", &error_local); + /* probe hardware */ + if (flashrom_init (SELFCHECK_TRUE)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "flashrom initialization error"); + return FALSE; + } + flashrom_set_log_callback (fu_plugin_flashrom_debug_cb); + if (flashrom_programmer_init (&data->flashprog, "internal", NULL)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "programmer initialization failed"); + return FALSE; + } + if (flashrom_flash_probe (&data->flashctx, data->flashprog, NULL)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "flash probe failed"); + return FALSE; + } + data->flash_size = flashrom_flash_getsize (data->flashctx); + return TRUE; +} - /* search for devices */ - hwids = fu_plugin_get_hwids (plugin); +gboolean +fu_plugin_coldplug (FuPlugin *plugin, GError **error) +{ + GPtrArray *hwids = fu_plugin_get_hwids (plugin); for (guint i = 0; i < hwids->len; i++) { const gchar *guid = g_ptr_array_index (hwids, i); const gchar *quirk_str; @@ -70,11 +127,7 @@ fu_plugin_startup (FuPlugin *plugin, GError **error) fu_device_set_id (dev, device_id); fu_device_set_quirks (dev, fu_plugin_get_quirks (plugin)); fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_INTERNAL); - if (data->flashrom_fn != NULL) { - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); - } else { - fu_device_set_update_error (dev, error_local->message); - } + fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_add_guid (dev, guid); 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)); @@ -89,44 +142,6 @@ fu_plugin_startup (FuPlugin *plugin, GError **error) return TRUE; } -static guint -fu_plugin_flashrom_parse_percentage (const gchar *lines_verbose) -{ - const guint64 addr_highest = 0x800000; - guint64 addr_best = 0x0; - g_auto(GStrv) chunks = NULL; - - /* parse 0x000000-0x000fff:S, 0x001000-0x001fff:S */ - chunks = g_strsplit_set (lines_verbose, "x-:S, \n\r", -1); - for (guint i = 0; chunks[i] != NULL; i++) { - guint64 addr_tmp; - if (strlen (chunks[i]) != 6) - continue; - addr_tmp = g_ascii_strtoull (chunks[i], NULL, 16); - if (addr_tmp > addr_best) - addr_best = addr_tmp; - } - return (addr_best * 100) / addr_highest; -} - -static void -fu_plugin_flashrom_read_cb (const gchar *line, gpointer user_data) -{ - FuDevice *device = FU_DEVICE (user_data); - if (g_strcmp0 (line, "Reading flash...") == 0) - fu_device_set_status (device, FWUPD_STATUS_DEVICE_VERIFY); - fu_device_set_progress (device, fu_plugin_flashrom_parse_percentage (line)); -} - -static void -fu_plugin_flashrom_write_cb (const gchar *line, gpointer user_data) -{ - FuDevice *device = FU_DEVICE (user_data); - if (g_strcmp0 (line, "Writing flash...") == 0) - fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); - fu_device_set_progress (device, fu_plugin_flashrom_parse_percentage (line)); -} - gboolean fu_plugin_update_prepare (FuPlugin *plugin, FwupdInstallFlags flags, @@ -148,17 +163,20 @@ fu_plugin_update_prepare (FuPlugin *plugin, if (!fu_common_mkdir_parent (firmware_orig, error)) return FALSE; if (!g_file_test (firmware_orig, G_FILE_TEST_EXISTS)) { - const gchar *argv[] = { - data->flashrom_fn, - "--programmer", "internal:laptop=force_I_want_a_brick", - "--read", firmware_orig, - "--verbose", NULL }; - if (!fu_common_spawn_sync ((const gchar * const *) argv, - fu_plugin_flashrom_read_cb, device, - 0, NULL, error)) { - g_prefix_error (error, "failed to get original firmware: "); + g_autofree guint8 *newcontents = g_malloc0 (data->flash_size); + g_autoptr(GBytes) buf = NULL; + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_READ); + if (flashrom_image_read (data->flashctx, newcontents, data->flash_size)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "failed to back up original firmware"); return FALSE; } + buf = g_bytes_new_static (newcontents, data->flash_size); + if (!fu_common_set_contents_bytes (firmware_orig, buf, error)) + return FALSE; } return TRUE; @@ -172,34 +190,56 @@ fu_plugin_update (FuPlugin *plugin, GError **error) { FuPluginData *data = fu_plugin_get_data (plugin); - g_autofree gchar *firmware_fn = NULL; - g_autofree gchar *tmpdir = NULL; - const gchar *argv[] = { - data->flashrom_fn, - "--programmer", "internal:laptop=force_I_want_a_brick", - "--write", "xxx", - "--verbose", NULL }; + gsize sz = 0; + gint rc; + const guint8 *buf = g_bytes_get_data (blob_fw, &sz); - /* write blob to temp location */ - tmpdir = g_dir_make_tmp ("fwupd-XXXXXX", error); - if (tmpdir == NULL) - return FALSE; - firmware_fn = g_build_filename (tmpdir, "flashrom-firmware.bin", NULL); - if (!fu_common_set_contents_bytes (firmware_fn, blob_fw, error)) - return FALSE; - - /* use flashrom to write image */ - argv[4] = firmware_fn; - if (!fu_common_spawn_sync ((const gchar * const *) argv, - fu_plugin_flashrom_write_cb, device, - 0, NULL, error)) { - g_prefix_error (error, "failed to write firmware: "); + if (flashrom_layout_read_from_ifd (&data->layout, data->flashctx, NULL, 0)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "failed to read layout from Intel ICH descriptor"); return FALSE; } - /* delete temp location */ - if (!fu_common_rmtree (tmpdir, error)) + /* include bios region for safety reasons */ + if (flashrom_layout_include_region (data->layout, "bios")) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid region name"); return FALSE; + } + + /* write region */ + flashrom_layout_set (data->flashctx, data->layout); + if (sz != data->flash_size) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid image size 0x%x, expected 0x%x", + (guint) sz, (guint) data->flash_size); + return FALSE; + } + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + rc = flashrom_image_write (data->flashctx, (void *) buf, sz, NULL /* refbuffer */); + if (rc != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "image write failed, err=%i", rc); + return FALSE; + } + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_VERIFY); + if (flashrom_image_verify (data->flashctx, (void *) buf, sz)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "image verify failed"); + return FALSE; + } /* success */ return TRUE; diff --git a/plugins/flashrom/meson.build b/plugins/flashrom/meson.build index 222b5f88f..1e5a60647 100644 --- a/plugins/flashrom/meson.build +++ b/plugins/flashrom/meson.build @@ -25,5 +25,6 @@ shared_module('fu_plugin_flashrom', ], dependencies : [ plugin_deps, + libflashrom, ], ) diff --git a/plugins/meson.build b/plugins/meson.build index 80b4f9ba3..b45621f1f 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -3,7 +3,6 @@ subdir('dfu') subdir('colorhug') subdir('ebitdo') subdir('fastboot') -subdir('flashrom') subdir('steelseries') subdir('dell-dock') subdir('nitrokey') @@ -58,3 +57,7 @@ endif if get_option('plugin_uefi') subdir('uefi') endif + +if get_option('plugin_flashrom') +subdir('flashrom') +endif diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 701a26ee6..047383101 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -264,11 +264,13 @@ parts: - libarchive-dev - libcairo-dev - libelf-dev + - libftdi1-dev - libgcab-dev - libglib2.0-dev - libgpgme11-dev - libjson-glib-dev - libpango1.0-dev + - libpci-dev - libpolkit-gobject-1-dev - libsoup2.4-dev - libsqlite3-dev diff --git a/subprojects/.gitignore b/subprojects/.gitignore index d8d6c81a5..99292448a 100644 --- a/subprojects/.gitignore +++ b/subprojects/.gitignore @@ -1 +1,2 @@ +flashrom libxmlb diff --git a/subprojects/flashrom.wrap b/subprojects/flashrom.wrap new file mode 100644 index 000000000..1039a40ff --- /dev/null +++ b/subprojects/flashrom.wrap @@ -0,0 +1,4 @@ +[wrap-git] +directory = flashrom +url = https://github.com/hughsie/flashrom.git +revision = wip/hughsie/fwupd