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"
- "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"

View File

@ -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

View File

@ -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 \

View File

@ -142,6 +142,42 @@
<package variant="x86_64" />
</distro>
</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">
<distro id="arch">
<package>noto-fonts</package>

View File

@ -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

View File

@ -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

View File

@ -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')

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_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')

View File

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

View File

@ -24,9 +24,15 @@
#include <string.h>
#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;

View File

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

View File

@ -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

View File

@ -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

View File

@ -1 +1,2 @@
flashrom
libxmlb

View File

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