From patchwork Fri Jun 6 01:47:22 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mike Frysinger X-Patchwork-Id: 356650 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id E4F2A14009E for ; Fri, 6 Jun 2014 11:47:45 +1000 (EST) Received: from localhost ([::1]:44656 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WsjFv-0003vs-N9 for incoming@patchwork.ozlabs.org; Thu, 05 Jun 2014 21:47:43 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:57997) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WsjFc-0003f7-5B for qemu-devel@nongnu.org; Thu, 05 Jun 2014 21:47:25 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1WsjFa-0003X7-6f for qemu-devel@nongnu.org; Thu, 05 Jun 2014 21:47:24 -0400 Received: from woodpecker.gentoo.org ([2001:470:ea4a:1:214:c2ff:fe64:b2d3]:37404 helo=smtp.gentoo.org) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WsjFZ-0003W3-Sm for qemu-devel@nongnu.org; Thu, 05 Jun 2014 21:47:22 -0400 Received: from localhost.localdomain (localhost [127.0.0.1]) by smtp.gentoo.org (Postfix) with ESMTP id E66B633FE0A for ; Fri, 6 Jun 2014 01:47:18 +0000 (UTC) From: Mike Frysinger To: qemu-devel@nongnu.org Date: Thu, 5 Jun 2014 21:47:22 -0400 Message-Id: <1402019242-15521-1-git-send-email-vapier@gentoo.org> X-Mailer: git-send-email 2.0.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 2001:470:ea4a:1:214:c2ff:fe64:b2d3 Subject: [Qemu-devel] [PATCH] scripts/qemu-binfmt-conf.sh: rewrite to make user friendly & easier to maintain X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org The current script isn't terribly friendly -- you basically get one chance to run it per boot w/out manually recovering the system state. It also doesn't lend itself to being made into an init script w/out a lot of manual editing. Rewrite the sucker with proper functions so that people can easily run it and integrate into their system, and make it easier for CPU maintainers to add new targets. There's also a few fixes smattered about, but considering the whole file has been written from scratch, not sure they need splitting out. Signed-off-by: Mike Frysinger --- scripts/qemu-binfmt-conf.sh | 306 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 240 insertions(+), 66 deletions(-) mode change 100644 => 100755 scripts/qemu-binfmt-conf.sh diff --git a/scripts/qemu-binfmt-conf.sh b/scripts/qemu-binfmt-conf.sh old mode 100644 new mode 100755 index 289b1a3..59de1d2 --- a/scripts/qemu-binfmt-conf.sh +++ b/scripts/qemu-binfmt-conf.sh @@ -1,72 +1,246 @@ #!/bin/sh -# enable automatic i386/ARM/M68K/MIPS/SPARC/PPC/s390 program execution by the kernel - -# load the binfmt_misc module -if [ ! -d /proc/sys/fs/binfmt_misc ]; then - /sbin/modprobe binfmt_misc -fi -if [ ! -f /proc/sys/fs/binfmt_misc/register ]; then - mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc -fi - -# probe cpu type -cpu=`uname -m` -case "$cpu" in - i386|i486|i586|i686|i86pc|BePC|x86_64) +# Enable automatic execution of non-native ELFs by the kernel. + +set -e + +usage() { + local ret="${1:-0}" + [ ${ret} -eq 0 ] || exec 1>&2 + cat <<-EOF +Usage: $0 [options] [targets to process] + +Enable automatic execution of non-native ELFs by the kernel by +initializing the binfmt_misc filesystem. + +Options: + -r Register qemu targets [default] + -u Unregister qemu targets + -n Dry run mode; don't actually try to do stuff + -h This screen +EOF + exit ${ret} +} + +# Usage: error +error() { + echo "ERROR: $*" >&2 +} + +# Usage: die +die() { + error "$*" + exit 1 +} + +# Usage: decho +# Output this message when in dryrun mode. +decho() { + if ${dryrun}; then + echo "DRY-RUN: $*" + fi +} + +# Usage: has +# See if can be found in . +has() { + local needle="$1" + shift + case " $* " in + *" ${needle} "*) return 0;; + esac + return 1 +} + +# Make sure the binfmt_misc filesystem is ready for us to use. +BINFMT_MISC="/proc/sys/fs/binfmt_misc" +binfmt_init() { + if ${dryrun}; then + return 0 + fi + if [ ! -d ${BINFMT_MISC} ]; then + modprobe binfmt_misc + fi + if [ ! -f ${BINFMT_MISC}/register ]; then + mount binfmt_misc -t binfmt_misc ${BINFMT_MISC} + fi +} + +# Figure out what CPU we're running on right now. +probe_cpu() { + local cpu=$(uname -m) + + # See if we need to normalize the value. + # Only needed when $cpu isn't already what we want. + case ${cpu} in + armv[4-9]*) + cpu="arm" + ;; + i?86|i86pc|BePC) cpu="i386" - ;; - m68k) - cpu="m68k" - ;; + ;; mips*) cpu="mips" - ;; + ;; "Power Macintosh"|ppc|ppc64) cpu="ppc" - ;; - armv[4-9]*) - cpu="arm" - ;; -esac - -# register the interpreter for each cpu except for the native one -if [ $cpu != "i386" ] ; then - echo ':i386:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register - echo ':i486:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register -fi -if [ $cpu != "alpha" ] ; then - echo ':alpha:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x26\x90:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-alpha:' > /proc/sys/fs/binfmt_misc/register -fi -if [ $cpu != "arm" ] ; then - echo ':arm:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-arm:' > /proc/sys/fs/binfmt_misc/register - echo ':armeb:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-armeb:' > /proc/sys/fs/binfmt_misc/register -fi -if [ $cpu != "aarch64" ] ; then - echo ':aarch64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-aarch64:' > /proc/sys/fs/binfmt_misc/register -fi -if [ $cpu != "sparc" ] ; then - echo ':sparc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-sparc:' > /proc/sys/fs/binfmt_misc/register -fi -if [ $cpu != "ppc" ] ; then - echo ':ppc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x14:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-ppc:' > /proc/sys/fs/binfmt_misc/register -fi -if [ $cpu != "m68k" ] ; then - echo 'Please check cpu value and header information for m68k!' - echo ':m68k:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x04:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-m68k:' > /proc/sys/fs/binfmt_misc/register -fi -if [ $cpu != "mips" ] ; then - # FIXME: We could use the other endianness on a MIPS host. - echo ':mips:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-mips:' > /proc/sys/fs/binfmt_misc/register - echo ':mipsel:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-mipsel:' > /proc/sys/fs/binfmt_misc/register - echo ':mipsn32:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-mipsn32:' > /proc/sys/fs/binfmt_misc/register - echo ':mipsn32el:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-mipsn32el:' > /proc/sys/fs/binfmt_misc/register - echo ':mips64:M::\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-mips64:' > /proc/sys/fs/binfmt_misc/register - echo ':mips64el:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-mips64el:' > /proc/sys/fs/binfmt_misc/register -fi -if [ $cpu != "sh" ] ; then - echo ':sh4:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a\x00:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-sh4:' > /proc/sys/fs/binfmt_misc/register - echo ':sh4eb:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-sh4eb:' > /proc/sys/fs/binfmt_misc/register -fi -if [ $cpu != "s390x" ] ; then - echo ':s390x:M::\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x16:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-s390x:' > /proc/sys/fs/binfmt_misc/register -fi + ;; + sparc*) + cpu="sparc" + ;; + esac + + echo "${cpu}" +} + +host_cpu_compat() { + has "${host_cpu}" "$@" +} + +# Unregister the specified arch. +unregister() { + local fmt="$1" + local arch="$2" + local bfile="${BINFMT_MISC}/${arch}" + + if [ -e "${bfile}" ]; then + decho "${arch}: would unregister" + decho "${arch}: echo -1 > ${bfile}" + if ! ${dryrun}; then + if ! echo -1 > "${bfile}"; then + die "${arch}: unregistering failed" + fi + fi + fi +} + +# Try and locate a suitable qemu binary for the userland arch. +find_qemu() { + local arch="$1" + local qemu="qemu-${arch}" + local path + + for path in \ + $(which ${qemu} 2>/dev/null) \ + "$(dirname "$(realpath "$0")")/../${arch}-linux-user/${qemu}" \ + /usr/local/bin/${qemu} + do + if [ -x "${path}" ]; then + echo "${path}" + return 0 + fi + done + + return 1 +} + +# Register the specified magic. +register() { + local fmt="$1" + local arch="$2" + local path="$(find_qemu "${arch}")" + local magic=":${arch}:${fmt}:${path}:" + + unregister "$@" + + if [ -z "${path}" ]; then + echo "${arch}: Could not locate a qemu binary" + else + decho "${arch}: would register using ${path}" + decho "${arch}: echo '${magic}' > ${BINFMT_MISC}/register" + if ! ${dryrun}; then + if ! echo "${magic}" > ${BINFMT_MISC}/register; then + die "could not register ${arch}" + fi + fi + fi +} + +# Manage the binfmt registration for this target. +# Usage: process +process() { + if ${register}; then + register "$@" + else + unregister "$@" + fi +} + +# Keep the process funcs sorted by $cpu name. +process_aarch64() { + process 'M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff' aarch64 +} +process_alpha() { + process 'M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x26\x90:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff' alpha +} +process_arm() { + host_cpu_compat aarch64 && return 0 + process 'M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff' arm + process 'M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff' armeb +} +process_i386() { + host_cpu_compat x86_64 && return 0 + process 'M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff' i386 + process 'M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff' i386 +} +process_m68k() { + process 'M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x04:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff' m68k +} +process_mips() { + # FIXME: We could use the other endianness on a MIPS host. + process 'M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff' mips + process 'M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff' mipsel + process 'M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff' mipsn32 + process 'M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff' mipsn32el + process 'M::\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff' mips64 + process 'M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff' mips64el +} +process_ppc() { + process 'M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x14:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff' ppc +} +process_sparc() { + host_cpu_compat sparc64 && return 0 + process 'M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff' sparc +} +process_s390x() { + process 'M::\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x16:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff' s390x +} +process_sh4() { + process 'M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a\x00:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff' sh4 + process 'M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff' sh4eb +} + +# The main execution point! +main() { + local dryrun=false + local register=true + local opt + while getopts hnur opt; do + case ${opt} in + h) usage;; + n) dryrun=true;; + r) register=true;; + u) register=false;; + *) usage 1;; + esac + done + shift $((OPTIND - 1)) + + binfmt_init + + # Probe all the available register funcs and run through them. + local all_cpus host_cpu cpu + host_cpu=$(probe_cpu) + all_cpus=$(sed -n '/^process_.*() {/{s:^[^_]*_::;s:().*::;p}' "$0") + for cpu in ${all_cpus}; do + # Do not register the ELF format if it's the native one. + host_cpu_compat ${cpu} && continue + + # See if the user only wants to process a subset. + if [ $# -gt 0 ]; then + has "${cpu}" "$@" || continue + fi + + process_${cpu} + done +} +main "$@"