[arch-projects] [mkinitcpio] [PATCH] Add 'microcode' hooks

Weng Xuetian wengxt at gmail.com
Sun Nov 2 07:18:00 UTC 2014


Add early microcode support with early cpio. All files added under
/early_root will be created as a separate cpio prepend to original one.
Add a early_cpio file to early cpio to detect whether cpio contains
early cpio, thus we can have lsinitcpio work normally like old one.
---
 .gitignore        |   1 +
 Makefile          |   9 +++-
 install/microcode |  24 +++++++++++
 lsinitcpio        |  35 +++++++++++++---
 mkinitcpio        |  13 +++++-
 skipcpio.c        | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 198 insertions(+), 7 deletions(-)
 create mode 100644 install/microcode
 create mode 100644 skipcpio.c

diff --git a/.gitignore b/.gitignore
index a814a0f..1e501f0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,4 @@ lsinitcpio.1
 *~
 *.bak
 mkinitcpio-*.tar.gz
+skipcpio
diff --git a/Makefile b/Makefile
index 5af0eb2..a3a3591 100644
--- a/Makefile
+++ b/Makefile
@@ -20,7 +20,10 @@ DIRS = \
 	/usr/lib/systemd/system/shutdown.target.wants \
 	/usr/lib/tmpfiles.d
 
-all: doc
+all: doc skipcpio
+
+skipcpio: skipcpio.c
+	$(CC) skipcpio.c -o skipcpio
 
 MANPAGES = \
 	man/mkinitcpio.8 \
@@ -40,6 +43,7 @@ install: all
 	    < mkinitcpio > $(DESTDIR)/usr/bin/mkinitcpio
 
 	sed -e 's|\(^_f_functions\)=.*|\1=/usr/lib/initcpio/functions|' \
+	    -e 's|\(^_f_skipcpio\)=.*|\1=/usr/lib/initcpio/skipcpio|' \
 	    -e 's|%VERSION%|$(VERSION)|g' \
 	    < lsinitcpio > $(DESTDIR)/usr/bin/lsinitcpio
 
@@ -67,6 +71,8 @@ install: all
 	ln -s mkinitcpio $(DESTDIR)/usr/share/bash-completion/completions/lsinitcpio
 	install -m644 shell/zsh-completion $(DESTDIR)/usr/share/zsh/site-functions/_mkinitcpio
 
+	install -m755 skipcpio $(DESTDIR)/usr/lib/initcpio/skipcpio
+
 doc: $(MANPAGES)
 man/%: man/%.txt Makefile
 	a2x -d manpage \
@@ -76,6 +82,7 @@ man/%: man/%.txt Makefile
 
 clean:
 	$(RM) mkinitcpio-${VERSION}.tar.gz $(MANPAGES)
+	$(RM) skipcpio
 
 dist: doc
 	echo $(VERSION) > VERSION
diff --git a/install/microcode b/install/microcode
new file mode 100644
index 0000000..4dfd69e
--- /dev/null
+++ b/install/microcode
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+build() {
+    ucode_dir=(amd-ucode intel-ucode)
+    ucode_dest=(AuthenticAMD.bin GenuineIntel.bin)
+
+    for idx in 0 1; do
+        fw=${ucode_dir[$idx]}
+        for fwpath in "${_d_firmware[@]}"; do
+            if [[ -d $fwpath/$fw ]]; then
+                add_dir '/early_root/kernel/x86/microcode'
+                cat $fwpath/$fw/* > $BUILDROOT/early_root/kernel/x86/microcode/${ucode_dest[$idx]}
+            fi
+        done
+    done
+}
+
+help() {
+    cat <<HELPEOF
+This hook generate early ucode update
+HELPEOF
+}
+
+# vim: set ft=sh ts=4 sw=4 et:
diff --git a/lsinitcpio b/lsinitcpio
index 9567b79..902bfe2 100755
--- a/lsinitcpio
+++ b/lsinitcpio
@@ -6,8 +6,10 @@
 shopt -s extglob
 
 _list='--list'
-_optcolor=1 _optverbose=
+_optcolor=1 _optverbose= _optnoearly=1
 _f_functions=functions
+_f_skipcpio=./skipcpio
+_tmp_files=()
 
 usage() {
     cat<<USAGE
@@ -21,6 +23,7 @@ usage: ${0##*/} [action] [options] <initramfs>
    -x, --extract        extract image to disk
 
   Options:
+   -e, --early          display early cpio if possible
    -h, --help           display this help
    -n, --nocolor        disable colorized output
    -V, --version        display version information
@@ -131,7 +134,8 @@ analyze_image() {
     local kernver ratio columns=$(tput cols) image=$1
 
     workdir=$(mktemp -d --tmpdir lsinitcpio.XXXXXX)
-    trap 'rm -rf "$workdir"' EXIT
+    _tmp_files+=("$workdir")
+    trap 'rm -rf "${_tmp_files[@]}"' EXIT
 
     # fallback in case tput failed us
     columns=${columns:-80}
@@ -174,7 +178,7 @@ analyze_image() {
     explicitmod=($MODULES)
 
     # print results
-    imagename=$_image
+    imagename=$_origimage
     [[ -L $_image ]] && imagename+=" -> $(readlink -e "$_image")"
     msg 'Image: %s %s' "$imagename"
     [[ $version ]] && msg 'Created with mkinitcpio %s' "$version"
@@ -225,10 +229,18 @@ analyze_image() {
         printf '  %s\n' $CLEANUPHOOKS
         printf '\n'
     fi
+
+    msg 'Contains early CPIO:'
+    if (( _hasearly )); then
+        printf '  yes\n'
+    else
+        printf '  no\n'
+    fi
+    printf '\n'
 }
 
-_opt_short='achlnVvx'
-_opt_long=('analyze' 'config' 'help' 'list' 'nocolor' 'version' 'verbose' 'extract')
+_opt_short='achlenVvx'
+_opt_long=('analyze' 'config' 'help' 'list' 'early' 'nocolor' 'version' 'verbose' 'extract')
 
 parseopts "$_opt_short" "${_opt_long[@]}" -- "$@" || exit
 set -- "${OPTRET[@]}"
@@ -245,6 +257,8 @@ while :; do
             exit 0 ;;
         -l|--list)
             _optlistcontents=1 ;;
+        -e|--early)
+            _optnoearly=0 ;;
         -n|--nocolor)
             _optcolor=0 ;;
         -V|--version)
@@ -262,6 +276,8 @@ while :; do
 done
 
 _image=$1
+_origimage=$1
+_hasearly=0
 
 if [[ -t 1 ]] && (( _optcolor )); then
     try_enable_color
@@ -281,6 +297,15 @@ esac
 # read compression type
 _compress=$(detect_filetype "$_image") || exit
 
+if (( _optnoearly )) && decomp "$_image" | bsdcpio -i --quiet --list | grep -q '^early_cpio'; then
+    _hasearly=1
+    _tmp_image=$(mktemp --tmpdir lsinitcpio.XXXXXX)
+    _tmp_files+=("$_tmp_image")
+    trap 'rm -rf "${_tmp_files[@]}"' EXIT
+    $_f_skipcpio $_image > $_tmp_image
+    _image=$_tmp_image
+fi
+
 if (( _optanalyze )); then
     analyze_image "$_image"
 elif (( _optshowconfig )); then
diff --git a/mkinitcpio b/mkinitcpio
index 01fe8ba..cfe5747 100755
--- a/mkinitcpio
+++ b/mkinitcpio
@@ -221,10 +221,21 @@ build_image() {
         cpio_opts+=('-R' '0:0')
     fi
 
+    echo -n > "$out"
+    if [[ -d "$BUILDROOT/early_root" ]]; then
+        pushd "$BUILDROOT/early_root" >/dev/null
+        touch "$BUILDROOT/early_root/early_cpio"
+        find . -mindepth 1 -printf "%P\0" |
+                LANG=C bsdcpio "${cpio_opts[@]}" >> "$out"
+        popd >/dev/null
+
+        rm -rf "$BUILDROOT/early_root"
+    fi
+
     pushd "$BUILDROOT" >/dev/null
     find . -print0 |
             LANG=C bsdcpio "${cpio_opts[@]}" |
-            $compress $COMPRESSION_OPTIONS > "$out"
+            $compress $COMPRESSION_OPTIONS >> "$out"
     pipesave=("${PIPESTATUS[@]}") # save immediately
     popd >/dev/null
 
diff --git a/skipcpio.c b/skipcpio.c
new file mode 100644
index 0000000..445d7f6
--- /dev/null
+++ b/skipcpio.c
@@ -0,0 +1,123 @@
+/* dracut-install.c  -- install files and executables
+
+   Copyright (C) 2012 Harald Hoyer
+   Copyright (C) 2012 Red Hat, Inc.  All rights reserved.
+
+   This program is free software: you can redistribute it and/or modify
+   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 program 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
+   Lesser 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 <http://www.gnu.org/licenses/>.
+*/
+
+#define PROGRAM_VERSION_STRING "1"
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#define CPIO_END "TRAILER!!!"
+#define CPIO_ENDLEN (sizeof(CPIO_END)-1)
+
+static char buf[CPIO_ENDLEN * 2 + 1];
+
+int main(int argc, char **argv)
+{
+        FILE *f;
+        size_t s;
+
+        if (argc != 2) {
+                fprintf(stderr, "Usage: %s <file>\n", argv[0]);
+                exit(1);
+        }
+
+        f = fopen(argv[1], "r");
+
+        if (f == NULL) {
+                fprintf(stderr, "Cannot open file '%s'\n", argv[1]);
+                exit(1);
+        }
+
+        s = fread(buf, 6, 1, f);
+        if (s <= 0) {
+                fprintf(stderr, "Read error from file '%s'\n", argv[1]);
+                fclose(f);
+                exit(1);
+        }
+        fseek(f, 0, SEEK_SET);
+
+        /* check, if this is a cpio archive */
+        if ((buf[0] == 0x71 && buf[1] == 0xc7)
+            || (buf[0] == '0' && buf[1] == '7' && buf[2] == '0' && buf[3] == '7' && buf[4] == '0' && buf[5] == '1')) {
+                long pos = 0;
+
+                /* Search for CPIO_END */
+                do {
+                        char *h;
+                        fseek(f, pos, SEEK_SET);
+                        buf[sizeof(buf) - 1] = 0;
+                        s = fread(buf, CPIO_ENDLEN, 2, f);
+                        if (s <= 0)
+                                break;
+
+                        h = strstr(buf, CPIO_END);
+                        if (h) {
+                                pos = (h - buf) + pos + CPIO_ENDLEN;
+                                fseek(f, pos, SEEK_SET);
+                                break;
+                        }
+                        pos += CPIO_ENDLEN;
+                } while (!feof(f));
+
+                if (feof(f)) {
+                        /* CPIO_END not found, just cat the whole file */
+                        fseek(f, 0, SEEK_SET);
+                } else {
+                        /* skip zeros */
+                        while (!feof(f)) {
+                                size_t i;
+
+                                buf[sizeof(buf) - 1] = 0;
+                                s = fread(buf, 1, sizeof(buf) - 1, f);
+                                if (s <= 0)
+                                        break;
+
+                                for (i = 0; (i < s) && (buf[i] == 0); i++) ;
+
+                                if (buf[i] != 0) {
+                                        pos += i;
+                                        fseek(f, pos, SEEK_SET);
+                                        break;
+                                }
+
+                                pos += s;
+                        }
+                }
+        }
+        /* cat out the rest */
+        while (!feof(f)) {
+                s = fread(buf, 1, sizeof(buf), f);
+                if (s <= 0)
+                        break;
+
+                s = fwrite(buf, 1, s, stdout);
+                if (s <= 0)
+                        break;
+        }
+        fclose(f);
+
+        return EXIT_SUCCESS;
+}
-- 
2.0.2


More information about the arch-projects mailing list