flashrom: Use libflashrom

This also means we now include a flashrom subproject as no distro currently has
a flashrom new enough to build the plugin.

Signed-off-by: Richard Hughes <richard@hughsie.com>
Signed-off-by: Artur Raglis <artur.raglis@3mdeb.com>
Signed-off-by: Maciej Pijanowski <maciej.pijanowski@3mdeb.com>
This commit is contained in:
Artur Raglis 2019-06-25 14:48:06 +02:00 committed by Richard Hughes
parent 749b50f3d1
commit 13fd21d806
15 changed files with 201 additions and 87 deletions

View File

@ -14,8 +14,10 @@ extraction:
- "wget -O libxmlb.zip https://github.com/hughsie/libxmlb/archive/0.1.7.zip" - "wget -O libxmlb.zip https://github.com/hughsie/libxmlb/archive/0.1.7.zip"
- "mkdir -p subprojects/libxmlb" - "mkdir -p subprojects/libxmlb"
- "bsdtar --strip-components=1 -xvf libxmlb.zip -C 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: index:
build_command: build_command:
- "meson setup build" - "meson setup build"
- "ninja -C build" - "ninja -C build"

View File

@ -17,7 +17,7 @@ makedepends=('meson' 'valgrind' 'gobject-introspection' 'gtk-doc' 'python-pillow
build() { build() {
cd ${pkgname} cd ${pkgname}
if [ -n "$CI" ]; then if [ -n "$CI" ]; then
export CI="--werror" export CI="--werror --wrap-mode=default"
fi fi
arch-meson -D b_lto=false $CI ../build arch-meson -D b_lto=false $CI ../build

View File

@ -16,6 +16,7 @@ cd build
meson .. \ meson .. \
--cross-file s390x_cross.txt \ --cross-file s390x_cross.txt \
--werror \ --werror \
-Dplugin_flashrom=false \
-Dplugin_uefi=false \ -Dplugin_uefi=false \
-Dplugin_dell=false \ -Dplugin_dell=false \
-Dplugin_modem_manager=false \ -Dplugin_modem_manager=false \

View File

@ -142,6 +142,42 @@
<package variant="x86_64" /> <package variant="x86_64" />
</distro> </distro>
</dependency> </dependency>
<dependency type="build" id="libftdi1-dev">
<distro id="arch">
<package>libftdi</package>
</distro>
<distro id="centos">
<package>libftdi-devel</package>
</distro>
<distro id="fedora">
<package>libftdi-devel</package>
</distro>
<distro id="debian">
<package variant="x86_64" />
<package variant="i386" />
</distro>
<distro id="ubuntu">
<package variant="x86_64" />
</distro>
</dependency>
<dependency type="build" id="libpci-dev">
<distro id="arch">
<package>pciutils</package>
</distro>
<distro id="centos">
<package>pciutils-devel</package>
</distro>
<distro id="fedora">
<package>pciutils-devel</package>
</distro>
<distro id="debian">
<package variant="x86_64" />
<package variant="i386" />
</distro>
<distro id="ubuntu">
<package variant="x86_64" />
</distro>
</dependency>
<dependency type="build" id="fonts-noto"> <dependency type="build" id="fonts-noto">
<distro id="arch"> <distro id="arch">
<package>noto-fonts</package> <package>noto-fonts</package>

View File

@ -11,7 +11,7 @@ ifeq "$(DEB_HOST_ARCH_BITS)" "32"
endif endif
ifneq ($(CI),) ifneq ($(CI),)
export CI=--werror export CI=--werror --wrap-mode=default
endif endif
SB_STYLE := debian SB_STYLE := debian
@ -58,6 +58,9 @@ override_dh_install:
if [ -n "$CI" ] && [ -f debian/tmp/usr/lib/xb-tool ]; then \ if [ -n "$CI" ] && [ -f debian/tmp/usr/lib/xb-tool ]; then \
dh_install -pfwupd usr/lib/xb-tool ;\ dh_install -pfwupd usr/lib/xb-tool ;\
fi fi
if [ -n "$CI" ] && [ -f debian/tmp/usr/sbin/flashrom ]; then \
dh_install -pfwupd usr/sbin/flashrom ;\
fi
dh_missing -a --fail-missing dh_missing -a --fail-missing
#this is placed in fwupd-tests #this is placed in fwupd-tests

View File

@ -10,6 +10,7 @@
%global enable_ci 0 %global enable_ci 0
%global enable_tests 1 %global enable_tests 1
%global enable_dummy 1 %global enable_dummy 1
%global __meson_wrap_mode default
# fwupd.efi is only available on these arches # fwupd.efi is only available on these arches
%ifarch x86_64 aarch64 %ifarch x86_64 aarch64
@ -151,6 +152,7 @@ Data files for installed tests.
%else %else
-Dplugin_dummy=false \ -Dplugin_dummy=false \
%endif %endif
-Dplugin_flashrom=true \
-Dplugin_thunderbolt=true \ -Dplugin_thunderbolt=true \
%if 0%{?have_redfish} %if 0%{?have_redfish}
-Dplugin_redfish=true \ -Dplugin_redfish=true \
@ -202,6 +204,12 @@ Data files for installed tests.
mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg 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} %find_lang %{name}
%post %post
@ -327,6 +335,9 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg
%{_datadir}/locale/*/LC_IMAGES/fwupd* %{_datadir}/locale/*/LC_IMAGES/fwupd*
%endif %endif
# eww, but just until the Fedora package ships these...
%{_libdir}/libflashrom.so.1*
%files devel %files devel
%{_datadir}/gir-1.0/Fwupd-2.0.gir %{_datadir}/gir-1.0/Fwupd-2.0.gir
%{_datadir}/gtk-doc/html/libfwupd %{_datadir}/gtk-doc/html/libfwupd

View File

@ -278,6 +278,10 @@ if get_option('plugin_thunderbolt')
conf.set('HAVE_THUNDERBOLT', '1') conf.set('HAVE_THUNDERBOLT', '1')
endif endif
if get_option('plugin_flashrom')
libflashrom = dependency('flashrom', fallback : ['flashrom', 'flashrom_dep'])
endif
if get_option('systemd') if get_option('systemd')
systemd = dependency('systemd', version : '>= 211') systemd = dependency('systemd', version : '>= 211')
conf.set('HAVE_SYSTEMD' , '1') conf.set('HAVE_SYSTEMD' , '1')

View File

@ -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_uefi', type : 'boolean', value : true, description : 'enable UEFI support')
option('plugin_nvme', type : 'boolean', value : true, description : 'enable NVMe 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_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('systemd', type : 'boolean', value : true, description : 'enable systemd support')
option('systemdunitdir', type: 'string', value: '', description: 'Directory for systemd units') option('systemdunitdir', type: 'string', value: '', description: 'Directory for systemd units')
option('elogind', type : 'boolean', value : false, description : 'enable elogind support') option('elogind', type : 'boolean', value : false, description : 'enable elogind support')

View File

@ -1,3 +1,8 @@
# Purism # Purism
[HwId=a0ce5085-2dea-5086-ae72-45810a186ad0] [HwId=a0ce5085-2dea-5086-ae72-45810a186ad0]
DeviceId=librem15v3 DeviceId=librem15v3
# Libretrend
[HwId=52b68c34-6b31-5ecc-8a5c-de37e666ccd5]
DeviceId=LT1000
VersionFormat=quad

View File

@ -24,9 +24,15 @@
#include <string.h> #include <string.h>
#include "fu-plugin-vfuncs.h" #include "fu-plugin-vfuncs.h"
#include "libflashrom.h"
#define SELFCHECK_TRUE 1
struct FuPluginData { struct FuPluginData {
gchar *flashrom_fn; gsize flash_size;
struct flashrom_flashctx *flashctx;
struct flashrom_layout *layout;
struct flashrom_programmer *flashprog;
}; };
void void
@ -41,21 +47,72 @@ void
fu_plugin_destroy (FuPlugin *plugin) fu_plugin_destroy (FuPlugin *plugin)
{ {
FuPluginData *data = fu_plugin_get_data (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 gboolean
fu_plugin_startup (FuPlugin *plugin, GError **error) fu_plugin_startup (FuPlugin *plugin, GError **error)
{ {
FuPluginData *data = fu_plugin_get_data (plugin); FuPluginData *data = fu_plugin_get_data (plugin);
GPtrArray *hwids;
g_autoptr(GError) error_local = NULL;
/* we need flashrom from the host system */ /* probe hardware */
data->flashrom_fn = fu_common_find_program_in_path ("flashrom", &error_local); 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 */ gboolean
hwids = fu_plugin_get_hwids (plugin); fu_plugin_coldplug (FuPlugin *plugin, GError **error)
{
GPtrArray *hwids = fu_plugin_get_hwids (plugin);
for (guint i = 0; i < hwids->len; i++) { for (guint i = 0; i < hwids->len; i++) {
const gchar *guid = g_ptr_array_index (hwids, i); const gchar *guid = g_ptr_array_index (hwids, i);
const gchar *quirk_str; 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_id (dev, device_id);
fu_device_set_quirks (dev, fu_plugin_get_quirks (plugin)); fu_device_set_quirks (dev, fu_plugin_get_quirks (plugin));
fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_INTERNAL); fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_INTERNAL);
if (data->flashrom_fn != NULL) {
fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE);
} else {
fu_device_set_update_error (dev, error_local->message);
}
fu_device_add_guid (dev, guid); 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_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_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; 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 gboolean
fu_plugin_update_prepare (FuPlugin *plugin, fu_plugin_update_prepare (FuPlugin *plugin,
FwupdInstallFlags flags, FwupdInstallFlags flags,
@ -148,17 +163,20 @@ fu_plugin_update_prepare (FuPlugin *plugin,
if (!fu_common_mkdir_parent (firmware_orig, error)) if (!fu_common_mkdir_parent (firmware_orig, error))
return FALSE; return FALSE;
if (!g_file_test (firmware_orig, G_FILE_TEST_EXISTS)) { if (!g_file_test (firmware_orig, G_FILE_TEST_EXISTS)) {
const gchar *argv[] = { g_autofree guint8 *newcontents = g_malloc0 (data->flash_size);
data->flashrom_fn, g_autoptr(GBytes) buf = NULL;
"--programmer", "internal:laptop=force_I_want_a_brick",
"--read", firmware_orig, fu_device_set_status (device, FWUPD_STATUS_DEVICE_READ);
"--verbose", NULL }; if (flashrom_image_read (data->flashctx, newcontents, data->flash_size)) {
if (!fu_common_spawn_sync ((const gchar * const *) argv, g_set_error_literal (error,
fu_plugin_flashrom_read_cb, device, FWUPD_ERROR,
0, NULL, error)) { FWUPD_ERROR_READ,
g_prefix_error (error, "failed to get original firmware: "); "failed to back up original firmware");
return FALSE; 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; return TRUE;
@ -172,34 +190,56 @@ fu_plugin_update (FuPlugin *plugin,
GError **error) GError **error)
{ {
FuPluginData *data = fu_plugin_get_data (plugin); FuPluginData *data = fu_plugin_get_data (plugin);
g_autofree gchar *firmware_fn = NULL; gsize sz = 0;
g_autofree gchar *tmpdir = NULL; gint rc;
const gchar *argv[] = { const guint8 *buf = g_bytes_get_data (blob_fw, &sz);
data->flashrom_fn,
"--programmer", "internal:laptop=force_I_want_a_brick",
"--write", "xxx",
"--verbose", NULL };
/* write blob to temp location */ if (flashrom_layout_read_from_ifd (&data->layout, data->flashctx, NULL, 0)) {
tmpdir = g_dir_make_tmp ("fwupd-XXXXXX", error); g_set_error_literal (error,
if (tmpdir == NULL) FWUPD_ERROR,
return FALSE; FWUPD_ERROR_READ,
firmware_fn = g_build_filename (tmpdir, "flashrom-firmware.bin", NULL); "failed to read layout from Intel ICH descriptor");
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: ");
return FALSE; return FALSE;
} }
/* delete temp location */ /* include bios region for safety reasons */
if (!fu_common_rmtree (tmpdir, error)) if (flashrom_layout_include_region (data->layout, "bios")) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"invalid region name");
return FALSE; 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 */ /* success */
return TRUE; return TRUE;

View File

@ -25,5 +25,6 @@ shared_module('fu_plugin_flashrom',
], ],
dependencies : [ dependencies : [
plugin_deps, plugin_deps,
libflashrom,
], ],
) )

View File

@ -3,7 +3,6 @@ subdir('dfu')
subdir('colorhug') subdir('colorhug')
subdir('ebitdo') subdir('ebitdo')
subdir('fastboot') subdir('fastboot')
subdir('flashrom')
subdir('steelseries') subdir('steelseries')
subdir('dell-dock') subdir('dell-dock')
subdir('nitrokey') subdir('nitrokey')
@ -58,3 +57,7 @@ endif
if get_option('plugin_uefi') if get_option('plugin_uefi')
subdir('uefi') subdir('uefi')
endif endif
if get_option('plugin_flashrom')
subdir('flashrom')
endif

View File

@ -264,11 +264,13 @@ parts:
- libarchive-dev - libarchive-dev
- libcairo-dev - libcairo-dev
- libelf-dev - libelf-dev
- libftdi1-dev
- libgcab-dev - libgcab-dev
- libglib2.0-dev - libglib2.0-dev
- libgpgme11-dev - libgpgme11-dev
- libjson-glib-dev - libjson-glib-dev
- libpango1.0-dev - libpango1.0-dev
- libpci-dev
- libpolkit-gobject-1-dev - libpolkit-gobject-1-dev
- libsoup2.4-dev - libsoup2.4-dev
- libsqlite3-dev - libsqlite3-dev

View File

@ -1 +1,2 @@
flashrom
libxmlb libxmlb

View File

@ -0,0 +1,4 @@
[wrap-git]
directory = flashrom
url = https://github.com/hughsie/flashrom.git
revision = wip/hughsie/fwupd