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