diff --git a/.gitignore b/.gitignore index aa8d011..4114f43 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -SOURCES/eppic_030413.tar.gz -SOURCES/kdump-anaconda-addon-003-11-g7f70211.tar.gz +SOURCES/eppic_050615.tar.gz +SOURCES/kdump-anaconda-addon-003-19-gda64a86.tar.gz SOURCES/kexec-tools-2.0.7.tar.xz SOURCES/makedumpfile-1.5.7.tar.gz diff --git a/.kexec-tools.metadata b/.kexec-tools.metadata index 5ea0345..9edc81a 100644 --- a/.kexec-tools.metadata +++ b/.kexec-tools.metadata @@ -1,4 +1,4 @@ -dcdb6d2488c8a31ae95563e2113860ae16256c8f SOURCES/eppic_030413.tar.gz -41895bf0a59e7359a12d7973a0171337fb69edb0 SOURCES/kdump-anaconda-addon-003-11-g7f70211.tar.gz +a096c8e0892b559f40b01916aae240652f75b68a SOURCES/eppic_050615.tar.gz +35161100add54ace94d0966fe45a9e3d5755114c SOURCES/kdump-anaconda-addon-003-19-gda64a86.tar.gz 56f3c4c829d0078bb705f980e1d9ba22eb9a6246 SOURCES/kexec-tools-2.0.7.tar.xz 16427d952ce7d0426c8b4aecc92f2960cf7926d3 SOURCES/makedumpfile-1.5.7.tar.gz diff --git a/SOURCES/dracut-kdump.sh b/SOURCES/dracut-kdump.sh index dc948d1..4aab205 100755 --- a/SOURCES/dracut-kdump.sh +++ b/SOURCES/dracut-kdump.sh @@ -121,9 +121,9 @@ get_host_ip() then kdumpnic=$(getarg kdumpnic=) [ -z "$kdumpnic" ] && echo "kdump: failed to get kdumpnic!" && return 1 - _host=`ip addr show dev $kdumpnic|grep 'inet '` + _host=`ip addr show dev $kdumpnic|grep '[ ]*inet'` [ $? -ne 0 ] && echo "kdump: wrong kdumpnic: $kdumpnic" && return 1 - _host="${_host##*inet }" + _host=`echo $_host | head -n 1 | cut -d' ' -f2` _host="${_host%%/*}" [ -z "$_host" ] && echo "kdump: wrong kdumpnic: $kdumpnic" && return 1 HOST_IP=$_host diff --git a/SOURCES/dracut-module-setup.sh b/SOURCES/dracut-module-setup.sh index eeb348c..5a11a42 100755 --- a/SOURCES/dracut-module-setup.sh +++ b/SOURCES/dracut-module-setup.sh @@ -64,29 +64,64 @@ kdump_is_vlan() { # $1: netdev name kdump_setup_dns() { - _dnsfile=${initdir}/etc/cmdline.d/42dns.conf + local _nameserver _dns + local _dnsfile=${initdir}/etc/cmdline.d/42dns.conf . /etc/sysconfig/network-scripts/ifcfg-$1 + [ -n "$DNS1" ] && echo "nameserver=$DNS1" > "$_dnsfile" [ -n "$DNS2" ] && echo "nameserver=$DNS2" >> "$_dnsfile" + + while read content; + do + _nameserver=$(echo $content | grep ^nameserver) + [ -z "$_nameserver" ] && continue + + _dns=$(echo $_nameserver | cut -d' ' -f2) + [ -z "$_dns" ] && continue + + if [ ! -f $_dnsfile ] || [ ! $(cat $_dnsfile | grep -q $_dns) ]; then + echo "nameserver=$_dns" >> "$_dnsfile" + fi + done < "/etc/resolv.conf" } #$1: netdev name #$2: srcaddr #if it use static ip echo it, or echo null kdump_static_ip() { - local _netmask _gateway - local _netdev="$1" _srcaddr="$2" - local _ipaddr=$(ip addr show dev $_netdev permanent | \ - awk "/ $_srcaddr\/.* $_netdev\$/{print \$2}") + local _netdev="$1" _srcaddr="$2" _ipv6_flag + local _netmask _gateway _ipaddr _target _nexthop + + _ipaddr=$(ip addr show dev $_netdev permanent | awk "/ $_srcaddr\/.* /{print \$2}") + + if is_ipv6_address $_srcaddr; then + _ipv6_flag="-6" + fi + if [ -n "$_ipaddr" ]; then - _netmask=$(ipcalc -m $_ipaddr | cut -d'=' -f2) - _gateway=$(ip route list dev $_netdev | awk '/^default /{print $3}') - echo -n "${_srcaddr}::${_gateway}:${_netmask}::" + _gateway=$(ip $_ipv6_flag route list dev $_netdev | \ + awk '/^default /{print $3}' | head -n 1) + + if [ "x" != "x"$_ipv6_flag ]; then + # _ipaddr="2002::56ff:feb6:56d5/64", _netmask is the number after "/" + _netmask=${_ipaddr#*\/} + _srcaddr="[$_srcaddr]" + _gateway="[$_gateway]" + else + _netmask=$(ipcalc -m $_ipaddr | cut -d'=' -f2) + fi + echo -n "${_srcaddr}::${_gateway}:${_netmask}::" fi - /sbin/ip route show | grep -v default | grep "^[[:digit:]].*via.* $_netdev " |\ - while read line; do - echo $line | awk '{printf("rd.route=%s:%s:%s\n", $1, $3, $5)}' + /sbin/ip $_ipv6_flag route show | grep -v default | grep ".*via.* $_netdev " |\ + while read _route; do + _target=`echo $_route | cut -d ' ' -f1` + _nexthop=`echo $_route | cut -d ' ' -f3` + if [ "x" != "x"$_ipv6_flag ]; then + _target="[$_target]" + _nexthop="[$_nexthop]" + fi + echo "rd.route=$_target:$_nexthop:$_netdev" done >> ${initdir}/etc/cmdline.d/45route-static.conf } @@ -261,32 +296,36 @@ kdump_setup_netdev() { kdump_setup_dns "$_netdev" } +get_ip_route_field() +{ + if `echo $1 | grep -q $2`; then + echo ${1##*$2} | cut -d ' ' -f1 + fi +} + #Function:kdump_install_net #$1: config values of net line in kdump.conf #$2: srcaddr of network device kdump_install_net() { - local _server _netdev _srcaddr + local _server _netdev _srcaddr _route _serv_tmp local config_val="$1" - _server=`echo $config_val | sed 's/.*@//' | cut -d':' -f1` + _server=$(get_remote_host $config_val) - _need_dns=`echo $_server|grep "[a-zA-Z]"` - [ -n "$_need_dns" ] && _server=`getent hosts $_server|cut -d' ' -f1` + if is_hostname $_server; then + _serv_tmp=`getent ahosts $_server | grep -v : | head -n 1` + if [ -z "$_serv_tmp" ]; then + _serv_tmp=`getent ahosts $_server | head -n 1` + fi + _server=`echo $_serv_tmp | cut -d' ' -f1` + fi - _netdev=`/sbin/ip route get to $_server 2>&1` + _route=`/sbin/ip -o route get to $_server 2>&1` [ $? != 0 ] && echo "Bad kdump location: $config_val" && exit 1 #the field in the ip output changes if we go to another subnet - if [ -n "`echo $_netdev | grep via`" ] - then - # we are going to a different subnet - _srcaddr=`echo $_netdev|awk '{print $7}'|head -n 1` - _netdev=`echo $_netdev|awk '{print $5;}'|head -n 1` - else - # we are on the same subnet - _srcaddr=`echo $_netdev|awk '{print $5}'|head -n 1` - _netdev=`echo $_netdev|awk '{print $3}'|head -n 1` - fi + _srcaddr=$(get_ip_route_field "$_route" "src") + _netdev=$(get_ip_route_field "$_route" "dev") kdump_setup_netdev "${_netdev}" "${_srcaddr}" @@ -504,10 +543,12 @@ kdump_setup_iscsi_device() { kdump_setup_netdev $netdev $srcaddr # prepare netroot= command line - # FIXME: IPV6 addresses require explicit [] around $tgt_ipaddr # FIXME: Do we need to parse and set other parameters like protocol, port # iscsi_iface_name, netdev_name, LUN etc. + if is_ipv6_address $tgt_ipaddr; then + tgt_ipaddr="[$tgt_ipaddr]" + fi netroot_str="netroot=iscsi:${userpwd_str}${userpwd_in_str}@$tgt_ipaddr::::$tgt_name" [[ -f $netroot_conf ]] || touch $netroot_conf @@ -628,10 +669,28 @@ kdump_install_random_seed() { bs=$poolsize count=1 2> /dev/null } +remove_cpu_online_rule() { + local file=${initdir}/usr/lib/udev/rules.d/40-redhat.rules + + sed -i '/SUBSYSTEM=="cpu"/d' $file +} + install() { + local arch + kdump_install_conf remove_sysctl_conf + # Onlining secondary cpus breaks kdump completely on KVM on Power hosts + # Though we use maxcpus=1 by default but 40-redhat.rules will bring up all + # possible cpus by default. (rhbz1270174 rhbz1266322) + # Thus before we get the kernel fix and the systemd rule fix let's remove + # the cpu online rule in kdump initramfs. + arch=$(uname -m) + if [[ "$arch" = "ppc64le" ]] || [[ "$arch" = "ppc64" ]]; then + remove_cpu_online_rule + fi + if is_ssh_dump_target; then kdump_install_random_seed fi @@ -643,6 +702,7 @@ install() { inst "/bin/date" "/bin/date" inst "/bin/sync" "/bin/sync" inst "/bin/cut" "/bin/cut" + inst "/bin/head" "/bin/head" inst "/sbin/makedumpfile" "/sbin/makedumpfile" inst "/sbin/vmcore-dmesg" "/sbin/vmcore-dmesg" inst "/lib/kdump/kdump-lib.sh" "/lib/kdump-lib.sh" @@ -666,7 +726,8 @@ install() { installkernel() { wdt=$(lsmod|cut -f1 -d' '|grep "wdt$") if [ -n "$wdt" ]; then - [ "$wdt" = "iTCO_wdt" ] && instmods lpc_ich + [ "$wdt" = "iTCO_wdt" ] && instmods lpc_ich && + echo "rd.driver.pre=lpc_ich,iTCO_wdt " >> ${initdir}/etc/cmdline.d/00-wdt.conf instmods $wdt fi } diff --git a/SOURCES/kdump-lib-initramfs.sh b/SOURCES/kdump-lib-initramfs.sh index 57b8304..68a94e8 100755 --- a/SOURCES/kdump-lib-initramfs.sh +++ b/SOURCES/kdump-lib-initramfs.sh @@ -7,7 +7,7 @@ CORE_COLLECTOR="" DEFAULT_CORE_COLLECTOR="makedumpfile -l --message-level 1 -d 31" DMESG_COLLECTOR="/sbin/vmcore-dmesg" DEFAULT_ACTION="reboot" -DATEDIR=`date +%Y.%m.%d-%T` +DATEDIR=`date +%Y-%m-%d-%T` HOST_IP='127.0.0.1' DUMP_INSTRUCTION="" SSH_KEY_LOCATION="/root/.ssh/kdump_id_rsa" diff --git a/SOURCES/kdump-lib.sh b/SOURCES/kdump-lib.sh index ef8417a..89dce8d 100755 --- a/SOURCES/kdump-lib.sh +++ b/SOURCES/kdump-lib.sh @@ -201,3 +201,32 @@ is_atomic() { grep -q "ostree" /proc/cmdline } + +is_ipv6_address() +{ + echo $1 | grep -q ":" +} + +# get ip address or hostname from nfs/ssh config value +get_remote_host() +{ + local _config_val=$1 + + # ipv6 address in kdump.conf is around with "[]", + # factor out the ipv6 address + _config_val=${_config_val#*@} + _config_val=${_config_val%:/*} + _config_val=${_config_val#[} + _config_val=${_config_val%]} + echo $_config_val +} + +is_hostname() +{ + local _hostname=`echo $1 | grep ":"` + + if [ -n "$_hostname" ]; then + return 1 + fi + echo $1 | grep -q "[a-zA-Z]" +} diff --git a/SOURCES/kdump.service b/SOURCES/kdump.service index 24c1386..5144597 100644 --- a/SOURCES/kdump.service +++ b/SOURCES/kdump.service @@ -1,6 +1,7 @@ [Unit] Description=Crash recovery kernel arming -After=network.target network-online.target remote-fs.target +After=network.target network-online.target remote-fs.target basic.target +DefaultDependencies=no [Service] Type=oneshot diff --git a/SOURCES/kdump.sysconfig.aarch64 b/SOURCES/kdump.sysconfig.aarch64 new file mode 100644 index 0000000..78b00bb --- /dev/null +++ b/SOURCES/kdump.sysconfig.aarch64 @@ -0,0 +1,28 @@ +# Kernel Version string for the -kdump kernel, such as 2.6.13-1544.FC5kdump +# If no version is specified, then the init script will try to find a +# kdump kernel with the same version number as the running kernel. +KDUMP_KERNELVER="" + +# The kdump commandline is the command line that needs to be passed off to +# the kdump kernel. This will likely match the contents of the grub kernel +# line. For example: +# KDUMP_COMMANDLINE="ro root=LABEL=/" +# Dracut depends on proper root= options, so please make sure that appropriate +# root= options are copied from /proc/cmdline. In general it is best to append +# command line options using "KDUMP_COMMANDLINE_APPEND=". +# If a command line is not specified, the default will be taken from +# /proc/cmdline +KDUMP_COMMANDLINE="" + +# This variable lets us append arguments to the current kdump commandline +# As taken from either KDUMP_COMMANDLINE above, or from /proc/cmdline +KDUMP_COMMANDLINE_APPEND="irqpoll maxcpus=1 reset_devices cgroup_disable=memory udev.children-max=2 panic=10 rootflags=nofail" + +# Any additional kexec arguments required. In most situations, this should +# be left empty +# +# Example: +# KEXEC_ARGS="--elf32-core-headers" + +KDUMP_BOOTDIR="/boot" +KDUMP_IMG="vmlinuz" diff --git a/SOURCES/kdump.sysconfig.i386 b/SOURCES/kdump.sysconfig.i386 index 84b2447..bb7a6e5 100644 --- a/SOURCES/kdump.sysconfig.i386 +++ b/SOURCES/kdump.sysconfig.i386 @@ -16,7 +16,7 @@ KDUMP_COMMANDLINE="" # This variable lets us append arguments to the current kdump commandline # As taken from either KDUMP_COMMANDLINE above, or from /proc/cmdline -KDUMP_COMMANDLINE_APPEND="irqpoll nr_cpus=1 reset_devices numa=off udev.children-max=2 panic=10 rootflags=nofail" +KDUMP_COMMANDLINE_APPEND="irqpoll nr_cpus=1 reset_devices numa=off udev.children-max=2 panic=10 rootflags=nofail transparent_hugepage=never" # Any additional kexec arguments required. In most situations, this should # be left empty diff --git a/SOURCES/kdump.sysconfig.ppc64 b/SOURCES/kdump.sysconfig.ppc64 index 5295626..dd09598 100644 --- a/SOURCES/kdump.sysconfig.ppc64 +++ b/SOURCES/kdump.sysconfig.ppc64 @@ -16,7 +16,7 @@ KDUMP_COMMANDLINE="" # This variable lets us append arguments to the current kdump commandline # As taken from either KDUMP_COMMANDLINE above, or from /proc/cmdline -KDUMP_COMMANDLINE_APPEND="irqpoll maxcpus=1 noirqdistrib reset_devices cgroup_disable=memory numa=off udev.children-max=2 ehea.use_mcs=0 panic=10 rootflags=nofail kvm_cma_resv_ratio=0" +KDUMP_COMMANDLINE_APPEND="irqpoll maxcpus=1 noirqdistrib reset_devices cgroup_disable=memory numa=off udev.children-max=2 ehea.use_mcs=0 panic=10 rootflags=nofail kvm_cma_resv_ratio=0 transparent_hugepage=never" # Any additional kexec arguments required. In most situations, this should # be left empty diff --git a/SOURCES/kdump.sysconfig.ppc64le b/SOURCES/kdump.sysconfig.ppc64le index 5295626..dd09598 100644 --- a/SOURCES/kdump.sysconfig.ppc64le +++ b/SOURCES/kdump.sysconfig.ppc64le @@ -16,7 +16,7 @@ KDUMP_COMMANDLINE="" # This variable lets us append arguments to the current kdump commandline # As taken from either KDUMP_COMMANDLINE above, or from /proc/cmdline -KDUMP_COMMANDLINE_APPEND="irqpoll maxcpus=1 noirqdistrib reset_devices cgroup_disable=memory numa=off udev.children-max=2 ehea.use_mcs=0 panic=10 rootflags=nofail kvm_cma_resv_ratio=0" +KDUMP_COMMANDLINE_APPEND="irqpoll maxcpus=1 noirqdistrib reset_devices cgroup_disable=memory numa=off udev.children-max=2 ehea.use_mcs=0 panic=10 rootflags=nofail kvm_cma_resv_ratio=0 transparent_hugepage=never" # Any additional kexec arguments required. In most situations, this should # be left empty diff --git a/SOURCES/kdump.sysconfig.s390x b/SOURCES/kdump.sysconfig.s390x index 745dd27..b103a88 100644 --- a/SOURCES/kdump.sysconfig.s390x +++ b/SOURCES/kdump.sysconfig.s390x @@ -16,7 +16,7 @@ KDUMP_COMMANDLINE="" # This variable lets us append arguments to the current kdump commandline # As taken from either KDUMP_COMMANDLINE above, or from /proc/cmdline -KDUMP_COMMANDLINE_APPEND="nr_cpus=1 cgroup_disable=memory numa=off udev.children-max=2 panic=10 rootflags=nofail" +KDUMP_COMMANDLINE_APPEND="nr_cpus=1 cgroup_disable=memory numa=off udev.children-max=2 panic=10 rootflags=nofail transparent_hugepage=never" # Any additional /sbin/mkdumprd arguments required. MKDUMPRD_ARGS="" diff --git a/SOURCES/kdump.sysconfig.x86_64 b/SOURCES/kdump.sysconfig.x86_64 index d9ad9b5..7991d68 100644 --- a/SOURCES/kdump.sysconfig.x86_64 +++ b/SOURCES/kdump.sysconfig.x86_64 @@ -16,7 +16,7 @@ KDUMP_COMMANDLINE="" # This variable lets us append arguments to the current kdump commandline # As taken from either KDUMP_COMMANDLINE above, or from /proc/cmdline -KDUMP_COMMANDLINE_APPEND="irqpoll nr_cpus=1 reset_devices cgroup_disable=memory mce=off numa=off udev.children-max=2 panic=10 rootflags=nofail acpi_no_memhotplug" +KDUMP_COMMANDLINE_APPEND="irqpoll nr_cpus=1 reset_devices cgroup_disable=memory mce=off numa=off udev.children-max=2 panic=10 rootflags=nofail acpi_no_memhotplug transparent_hugepage=never" # Any additional kexec arguments required. In most situations, this should # be left empty diff --git a/SOURCES/kdumpctl b/SOURCES/kdumpctl index f1b72da..029ded9 100755 --- a/SOURCES/kdumpctl +++ b/SOURCES/kdumpctl @@ -105,7 +105,7 @@ prepare_cmdline() else cmdline=${KDUMP_COMMANDLINE} fi - cmdline=`remove_cmdline_param "$cmdline" crashkernel hugepages hugepagesz` + cmdline=`remove_cmdline_param "$cmdline" crashkernel hugepages hugepagesz panic_on_warn` cmdline="${cmdline} ${KDUMP_COMMANDLINE_APPEND}" @@ -259,6 +259,8 @@ check_config() esac done < $KDUMP_CONFIG_FILE + check_default_config || return 1 + check_fence_kdump_config || return 1 return 0 @@ -554,6 +556,14 @@ propagate_ssh_key() fi } +show_reserved_mem() +{ + local mem=$(cat /sys/kernel/kexec_crash_size) + local mem_mb=$(expr $mem / 1024 / 1024) + + echo "Reserved "$mem_mb"MB memory for crash kernel" +} + is_fadump_capable() { # Check if firmware-assisted dump is enabled @@ -803,6 +813,25 @@ start_dump() return $? } +check_default_config() +{ + local default_option + + default_option=$(awk '$1 ~ /^default$/ {print $2;}' $KDUMP_CONFIG_FILE) + if [ -z "$default_option" ]; then + return 0 + else + case "$default_option" in + reboot|halt|poweroff|shell|dump_to_rootfs) + return 0 + ;; + *) + echo $"Usage kdump.conf: default {reboot|halt|poweroff|shell|dump_to_rootfs}" + return 1 + esac + fi +} + start() { check_config @@ -946,8 +975,11 @@ main () propagate) propagate_ssh_key ;; + showmem) + show_reserved_mem + ;; *) - echo $"Usage: $0 {start|stop|status|restart|propagate}" + echo $"Usage: $0 {start|stop|status|restart|propagate|showmem}" exit 1 esac } diff --git a/SOURCES/kdumpctl.8 b/SOURCES/kdumpctl.8 new file mode 100644 index 0000000..023562b --- /dev/null +++ b/SOURCES/kdumpctl.8 @@ -0,0 +1,44 @@ +.TH KDUMPCTL 8 2015-07-13 kexec-tools + +.SH NAME +kdumpctl \- control interface for kdump + +.SH SYNOPSIS +.B kdumpctl +.I COMMAND + +.SH DESCRIPTION +.B kdumpctl +is used to check or control the kdump service. +In most cases, you should use +.B systemctl +to start / stop / enable kdump service instead. However, +.B kdumpctl +provides more details for debug and a helper to setup ssh key authentication. + +.SH COMMANDS +.TP +.I start +Start the service. +.TP +.I stop +Stop the service. +.TP +.I status +Prints the current status of kdump service. +It returns non-zero value if kdump is not operational. +.TP +.I restart +Is equal to +.I start; stop +.TP +.I propagate +Helps to setup key authentication for ssh storage since it's +impossible to use password authentication during kdump. +.TP +.I showmem +Prints the size of reserved memory for crash kernel in megabytes. + +.SH "SEE ALSO" +.BR kdump.conf (5), +.BR mkdumprd (8) diff --git a/SOURCES/kexec-tools-2.0.7-makedumpfile-Support-ARM64.patch b/SOURCES/kexec-tools-2.0.7-makedumpfile-Support-ARM64.patch new file mode 100644 index 0000000..f435c89 --- /dev/null +++ b/SOURCES/kexec-tools-2.0.7-makedumpfile-Support-ARM64.patch @@ -0,0 +1,371 @@ +From 145707b5b6495467515cb6f3e0814df81cb55404 Mon Sep 17 00:00:00 2001 +Message-Id: <145707b5b6495467515cb6f3e0814df81cb55404.1431708455.git.panand@redhat.com> +From: Pratyush Anand +Date: Tue, 28 Apr 2015 15:15:15 +0530 +Subject: [PATCH] makedumpfile: Support ARM64 + +Patch adds support for ARM64 in makedumpfile. It takes care of vmalloc, +vmemmap, module and directly map kernel memory region's translation. + +Signed-off-by: Pratyush Anand +--- + Makefile | 1 + + arch/arm64.c | 259 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + makedumpfile.h | 49 +++++++++++ + 3 files changed, 309 insertions(+) + create mode 100644 arch/arm64.c + +diff --git a/makedumpfile-1.5.7/Makefile b/makedumpfile-1.5.7/Makefile +index e45c3cfe5e9d..b8d77dbad856 100644 +--- a/makedumpfile-1.5.7/Makefile ++++ b/makedumpfile-1.5.7/Makefile +@@ -49,6 +49,7 @@ SRC_BASE = makedumpfile.c makedumpfile.h diskdump_mod.h sadump_mod.h sadump_info + SRC_PART = print_info.c dwarf_info.c elf_info.c erase_info.c sadump_info.c cache.c + OBJ_PART=$(patsubst %.c,%.o,$(SRC_PART)) + SRC_ARCH = arch/arm.c arch/x86.c arch/x86_64.c arch/ia64.c arch/ppc64.c arch/s390x.c arch/ppc.c ++SRC_ARCH = arch/arm.c arch/arm64.c arch/x86.c arch/x86_64.c arch/ia64.c arch/ppc64.c arch/s390x.c arch/ppc.c + OBJ_ARCH=$(patsubst %.c,%.o,$(SRC_ARCH)) + + LIBS = -ldw -lbz2 -lebl -ldl -lelf -lz +diff --git a/makedumpfile-1.5.7/arch/arm64.c b/makedumpfile-1.5.7/arch/arm64.c +new file mode 100644 +index 000000000000..28e2adef7ae3 +--- /dev/null ++++ b/makedumpfile-1.5.7/arch/arm64.c +@@ -0,0 +1,259 @@ ++/* ++ * arch/arm64.c : Based on arch/arm.c ++ * ++ * Copyright (C) 2015 Red Hat, Pratyush Anand ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation (version 2 of the License). ++ * ++ * 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#ifdef __aarch64__ ++ ++#include "../elf_info.h" ++#include "../makedumpfile.h" ++#include "../print_info.h" ++ ++#if CONFIG_ARM64_PGTABLE_LEVELS == 2 ++typedef struct { ++ unsigned long pgd; ++} pgd_t; ++ ++typedef struct { ++ pgd_t pgd; ++} pud_t; ++ ++typedef struct { ++ pud_t pud; ++} pmd_t; ++ ++#define pud_offset(pgd, vaddr) ((pud_t *)pgd) ++#define pmd_offset(pud, vaddr) ((pmd_t *)pud) ++#define pgd_val(x) ((x).pgd) ++#define pud_val(x) (pgd_val((x).pgd)) ++#define pmd_val(x) (pud_val((x).pud)) ++ ++#define PUD_SHIFT PGDIR_SHIFT ++#define PUD_SIZE (1UL << PUD_SHIFT) ++ ++#endif ++ ++typedef struct { ++ unsigned long pte; ++} pte_t; ++#define pte_val(x) ((x).pte) ++ ++#define PAGE_SIZE (1UL << PAGE_SHIFT) ++#define PAGE_MASK (~(PAGE_SIZE - 1)) ++#define PGDIR_SHIFT ((PAGE_SHIFT - 3) * ARM64_PGTABLE_LEVELS + 3) ++#define PTRS_PER_PGD (1 << (VA_BITS - PGDIR_SHIFT)) ++#define PMD_SHIFT ((PAGE_SHIFT - 3) * 2 + 3) ++#define PTRS_PER_PTE (1 << (PAGE_SHIFT - 3)) ++#define PMD_SHIFT ((PAGE_SHIFT - 3) * 2 + 3) ++#define PMD_SIZE (1UL << PMD_SHIFT) ++#define PMD_MASK (~(PMD_SIZE - 1)) ++#define PTRS_PER_PMD PTRS_PER_PTE ++ ++#define PAGE_PRESENT (1 << 0) ++#define SECTIONS_SIZE_BITS 30 ++/* ++ ++* Highest possible physical address supported. ++*/ ++#define PHYS_MASK_SHIFT 48 ++#define PHYS_MASK ((1UL << PHYS_MASK_SHIFT) - 1) ++ ++#define PMD_TYPE_MASK 3 ++#define PMD_TYPE_SECT 1 ++#define PMD_TYPE_TABLE 3 ++ ++#define __va(paddr) ((paddr) - info->phys_base + PAGE_OFFSET) ++#define __pa(vaddr) ((vaddr) - PAGE_OFFSET + info->phys_base) ++ ++#define pgd_index(vaddr) (((vaddr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) ++#define pgd_offset(pgdir, vaddr) ((pgd_t *)(pgdir) + pgd_index(vaddr)) ++ ++#define pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) ++#define pmd_page_vaddr(pmd) (__va(pmd_val(pmd) & PHYS_MASK & (int32_t)PAGE_MASK)) ++#define pte_offset(dir, vaddr) ((pte_t*)pmd_page_vaddr((*dir)) + pte_index(vaddr)) ++ ++/* kernel struct page size can be kernel version dependent, currently ++ * keep it constant. ++ */ ++#define KERN_STRUCT_PAGE_SIZE 64 ++#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) ++#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) ++#define VMEMMAP_SIZE ALIGN((1UL << (VA_BITS - PAGE_SHIFT)) * KERN_STRUCT_PAGE_SIZE, PUD_SIZE) ++#define MODULES_END PAGE_OFFSET ++#define MODULES_VADDR (MODULES_END - 0x4000000) ++ ++int is_vmalloc_addr(unsigned long vaddr) ++{ ++ return (vaddr >= VMALLOC_START && vaddr <= VMALLOC_END); ++} ++ ++static int is_vtop_from_page_table_arm64(unsigned long vaddr) ++{ ++ /* If virtual address lies in vmalloc, vmemmap or module space ++ * region then, get the physical address from page table. ++ */ ++ return ((vaddr >= VMALLOC_START && vaddr <= VMALLOC_END) ++ || (vaddr >= VMEMMAP_START && vaddr <= VMEMMAP_END) ++ || (vaddr >= MODULES_VADDR && vaddr <= MODULES_END)); ++} ++ ++int get_phys_base_arm64(void) ++{ ++ unsigned long phys_base = ULONG_MAX; ++ unsigned long long phys_start; ++ int i; ++ /* ++ * We resolve phys_base from PT_LOAD segments. LMA contains physical ++ * address of the segment, and we use the lowest start as ++ * phys_base. ++ */ ++ for (i = 0; get_pt_load(i, &phys_start, NULL, NULL, NULL); i++) { ++ if (phys_start < phys_base) ++ phys_base = phys_start; ++ } ++ ++ if (phys_base == ULONG_MAX) { ++ ERRMSG("Can't determine phys_base\n"); ++ return FALSE; ++ } ++ ++ info->phys_base = phys_base; ++ ++ DEBUG_MSG("phys_base : %lx\n", phys_base); ++ ++ return TRUE; ++} ++ ++int get_machdep_info_arm64(void) ++{ ++ info->max_physmem_bits = PHYS_MASK_SHIFT; ++ info->section_size_bits = SECTIONS_SIZE_BITS; ++ info->page_offset = KVBASE; ++ info->vmalloc_start = 0xffffffffffffffffUL << VA_BITS; ++ info->vmalloc_end = PAGE_OFFSET - PUD_SIZE - VMEMMAP_SIZE - 0x10000; ++ info->vmemmap_start = VMALLOC_END + 0x10000; ++ info->vmemmap_end = VMEMMAP_START + VMEMMAP_SIZE; ++ ++ DEBUG_MSG("max_physmem_bits : %lx\n", info->max_physmem_bits); ++ DEBUG_MSG("section_size_bits: %lx\n", info->section_size_bits); ++ DEBUG_MSG("page_offset : %lx\n", info->page_offset); ++ DEBUG_MSG("vmalloc_start : %lx\n", info->vmalloc_start); ++ DEBUG_MSG("vmalloc_end : %lx\n", info->vmalloc_end); ++ DEBUG_MSG("vmemmap_start : %lx\n", info->vmemmap_start); ++ DEBUG_MSG("vmemmap_end : %lx\n", info->vmemmap_end); ++ DEBUG_MSG("modules_start : %lx\n", MODULES_VADDR); ++ DEBUG_MSG("modules_end : %lx\n", MODULES_END); ++ ++ return TRUE; ++} ++ ++unsigned long long kvtop_xen_arm64(unsigned long kvaddr) ++{ ++ return ERROR; ++} ++ ++int get_xen_basic_info_arm64(void) ++{ ++ return ERROR; ++} ++ ++int get_xen_info_arm64(void) ++{ ++ return ERROR; ++} ++ ++int get_versiondep_info_arm64(void) ++{ ++ return TRUE; ++} ++ ++/* ++ * vtop_arm64() - translate arbitrary virtual address to physical ++ * @vaddr: virtual address to translate ++ * ++ * Function translates @vaddr into physical address using page tables. This ++ * address can be any virtual address. Returns physical address of the ++ * corresponding virtual address or %NOT_PADDR when there is no translation. ++ */ ++static unsigned long long vtop_arm64(unsigned long vaddr) ++{ ++ unsigned long long paddr = NOT_PADDR; ++ pgd_t *pgda, pgdv; ++ pud_t *puda; ++ pmd_t *pmda, pmdv; ++ pte_t *ptea, ptev; ++ ++ if (SYMBOL(swapper_pg_dir) == NOT_FOUND_SYMBOL) { ++ ERRMSG("Can't get the symbol of swapper_pg_dir.\n"); ++ return NOT_PADDR; ++ } ++ ++ pgda = pgd_offset(SYMBOL(swapper_pg_dir), vaddr); ++ if (!readmem(VADDR, (unsigned long long)pgda, &pgdv, sizeof(pgdv))) { ++ ERRMSG("Can't read pgd\n"); ++ return NOT_PADDR; ++ } ++ ++ puda = pud_offset(pgda, vaddr); ++ pmda = pmd_offset(puda, vaddr); ++ if (!readmem(VADDR, (unsigned long long)pmda, &pmdv, sizeof(pmdv))) { ++ ERRMSG("Can't read pmd\n"); ++ return NOT_PADDR; ++ } ++ ++ switch (pmd_val(pmdv) & PMD_TYPE_MASK) { ++ case PMD_TYPE_TABLE: ++ ptea = pte_offset(&pmdv, vaddr); ++ /* 64k page */ ++ if (!readmem(VADDR, (unsigned long long)ptea, &ptev, sizeof(ptev))) { ++ ERRMSG("Can't read pte\n"); ++ return NOT_PADDR; ++ } ++ ++ if (!(pte_val(ptev) & PAGE_PRESENT)) { ++ ERRMSG("Can't get a valid pte.\n"); ++ return NOT_PADDR; ++ } else { ++ ++ paddr = (PAGEBASE(pte_val(ptev)) & PHYS_MASK) ++ + (vaddr & (PAGESIZE() - 1)); ++ } ++ break; ++ case PMD_TYPE_SECT: ++ /* 1GB section */ ++ paddr = (pmd_val(pmdv) & PMD_MASK) + (vaddr & (PMD_SIZE - 1)); ++ break; ++ } ++ ++ return paddr; ++} ++ ++unsigned long long vaddr_to_paddr_arm64(unsigned long vaddr) ++{ ++ /* ++ * use translation tables when a) user has explicitly requested us to ++ * perform translation for a given address. b) virtual address lies in ++ * vmalloc, vmemmap or modules memory region. Otherwise we assume that ++ * the translation is done within the kernel direct mapped region. ++ */ ++ if ((info->vaddr_for_vtop == vaddr) || ++ is_vtop_from_page_table_arm64(vaddr)) ++ return vtop_arm64(vaddr); ++ ++ return __pa(vaddr); ++} ++#endif +diff --git a/makedumpfile-1.5.7/makedumpfile.h b/makedumpfile-1.5.7/makedumpfile.h +index 96830b071f6e..2af3a8e72e0a 100644 +--- a/makedumpfile-1.5.7/makedumpfile.h ++++ b/makedumpfile-1.5.7/makedumpfile.h +@@ -483,6 +483,33 @@ do { \ + #define VMEMMAP_START (info->vmemmap_start) + #define VMEMMAP_END (info->vmemmap_end) + ++#ifdef __aarch64__ ++#define CONFIG_ARM64_PGTABLE_LEVELS 2 ++#define CONFIG_ARM64_VA_BITS 42 ++#define CONFIG_ARM64_64K_PAGES 1 ++ ++/* Currently we only suport following defines based on above ++ * config definitions. ++ * TODOs: We need to find a way to get above defines dynamically and ++ * then to support following definitions based on that ++ */ ++ ++#if CONFIG_ARM64_PGTABLE_LEVELS == 2 ++#define ARM64_PGTABLE_LEVELS 2 ++#endif ++ ++#if CONFIG_ARM64_VA_BITS == 42 ++#define VA_BITS 42 ++#endif ++ ++#ifdef CONFIG_ARM64_64K_PAGES ++#define PAGE_SHIFT 16 ++#endif ++ ++#define KVBASE_MASK (0xffffffffffffffffUL << (VA_BITS - 1)) ++#define KVBASE (SYMBOL(_stext) & KVBASE_MASK) ++#endif /* aarch64 */ ++ + #ifdef __arm__ + #define KVBASE_MASK (0xffff) + #define KVBASE (SYMBOL(_stext) & ~KVBASE_MASK) +@@ -757,6 +784,23 @@ do { \ + /* + * The function of dependence on machine + */ ++#ifdef __aarch64__ ++int get_phys_base_arm64(void); ++int get_machdep_info_arm64(void); ++unsigned long long vaddr_to_paddr_arm64(unsigned long vaddr); ++int get_versiondep_info_arm64(void); ++int get_xen_basic_info_arm64(void); ++int get_xen_info_arm64(void); ++int is_vmalloc_addr_arm64(unsigned long vaddr); ++#define vaddr_to_paddr(X) vaddr_to_paddr_arm64(X) ++#define get_phys_base() get_phys_base_arm64() ++#define get_machdep_info() get_machdep_info_arm64() ++#define get_versiondep_info() get_versiondep_info_arm64() ++#define get_xen_basic_info_arch(X) get_xen_basic_info_arm64(X) ++#define get_xen_info_arch(X) get_xen_info_arm64(X) ++#define is_vmalloc_addr(X) is_vmalloc_addr_arm64(X) ++#endif /* aarch64 */ ++ + #ifdef __arm__ + int get_phys_base_arm(void); + int get_machdep_info_arm(void); +@@ -1581,6 +1625,11 @@ struct domain_list { + #define PAGES_PER_MAPWORD (sizeof(unsigned long) * 8) + #define MFNS_PER_FRAME (info->page_size / sizeof(unsigned long)) + ++#ifdef __aarch64__ ++unsigned long long kvtop_xen_arm64(unsigned long kvaddr); ++#define kvtop_xen(X) kvtop_xen_arm64(X) ++#endif /* aarch64 */ ++ + #ifdef __arm__ + #define kvtop_xen(X) FALSE + #define get_xen_basic_info_arch(X) FALSE +-- +2.1.0 + diff --git a/SOURCES/kexec-tools-2.0.8-Don-t-bail-out-if-check_cpu_nodes-fails.patch b/SOURCES/kexec-tools-2.0.8-Don-t-bail-out-if-check_cpu_nodes-fails.patch new file mode 100644 index 0000000..383e08f --- /dev/null +++ b/SOURCES/kexec-tools-2.0.8-Don-t-bail-out-if-check_cpu_nodes-fails.patch @@ -0,0 +1,34 @@ +From 224112c147c398df25c543fcea42b3a75635c417 Mon Sep 17 00:00:00 2001 +Message-Id: <224112c147c398df25c543fcea42b3a75635c417.1431592766.git.panand@redhat.com> +In-Reply-To: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com> +References: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com> +From: Mark Salter +Date: Mon, 27 Apr 2015 11:18:25 -0400 +Subject: [PATCH 17/17] Don't bail out if check_cpu_nodes() fails + +Current check_cpu_nodes() will fail if firmware does not provide a +devicetree with cpu nodes. When booting with ACPI, we cannot count +on a devicetree with cpu nodes. For now, just warn on error rather +than bailing out. This will allow kexec to work with moonshot. + +Signed-off-by: Mark Salter +--- + kexec/arch/arm64/kexec-arm64.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kexec/arch/arm64/kexec-arm64.c b/kexec/arch/arm64/kexec-arm64.c +index d884c7c1707d..12c589f8001c 100644 +--- a/kexec/arch/arm64/kexec-arm64.c ++++ b/kexec/arch/arm64/kexec-arm64.c +@@ -639,7 +639,7 @@ int arm64_load_other_segments(struct kexec_info *info, + result = check_cpu_nodes(&dtb_1, &dtb_2); + + if (result) +- return result; ++ fprintf(stderr, "kexec: Warning: No device tree available.\n"); + + /* + * Put the DTB after the kernel with an alignment of 128 KiB, giving +-- +2.1.0 + diff --git a/SOURCES/kexec-tools-2.0.8-add-aarch64-to-configure.patch b/SOURCES/kexec-tools-2.0.8-add-aarch64-to-configure.patch new file mode 100644 index 0000000..6db6dad --- /dev/null +++ b/SOURCES/kexec-tools-2.0.8-add-aarch64-to-configure.patch @@ -0,0 +1,13 @@ +diff -Nur -x '*autom4te.cache*' kexec-tools-2.0.7.orig/configure kexec-tools-2.0.7/configure +--- kexec-tools-2.0.7.orig/configure 2014-06-08 20:51:35.000000000 -0400 ++++ kexec-tools-2.0.7/configure 2015-04-21 13:58:57.272137413 -0400 +@@ -2195,6 +2195,9 @@ + ARCH="ppc64" + SUBARCH="LE" + ;; ++ aarch64* ) ++ ARCH="arm64" ++ ;; + arm* ) + ARCH="arm" + ;; diff --git a/SOURCES/kexec-tools-2.0.8-arm64-Add-arm64-kexec-support.patch b/SOURCES/kexec-tools-2.0.8-arm64-Add-arm64-kexec-support.patch new file mode 100644 index 0000000..f1d89c9 --- /dev/null +++ b/SOURCES/kexec-tools-2.0.8-arm64-Add-arm64-kexec-support.patch @@ -0,0 +1,1772 @@ +From 21014aa0868f11223e3b33afa1b6320b79187dbc Mon Sep 17 00:00:00 2001 +Message-Id: <21014aa0868f11223e3b33afa1b6320b79187dbc.1431592766.git.panand@redhat.com> +In-Reply-To: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com> +References: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com> +From: Geoff Levand +Date: Fri, 17 Apr 2015 10:54:55 -0700 +Subject: [PATCH 02/17] arm64: Add arm64 kexec support + +Add kexec reboot support for ARM64 platforms. Uses purgatory. + +Signed-off-by: Geoff Levand +--- + configure.ac | 3 + + kexec/Makefile | 1 + + kexec/arch/arm64/Makefile | 40 ++ + kexec/arch/arm64/crashdump-arm64.c | 21 + + kexec/arch/arm64/crashdump-arm64.h | 12 + + kexec/arch/arm64/image-header.h | 95 +++ + kexec/arch/arm64/include/arch/options.h | 44 ++ + kexec/arch/arm64/kexec-arm64.c | 1041 +++++++++++++++++++++++++++++++ + kexec/arch/arm64/kexec-arm64.h | 51 ++ + kexec/arch/arm64/kexec-elf-arm64.c | 123 ++++ + kexec/arch/arm64/kexec-image-arm64.c | 50 ++ + kexec/kexec-syscall.h | 9 +- + purgatory/Makefile | 1 + + purgatory/arch/arm64/Makefile | 18 + + purgatory/arch/arm64/entry.S | 54 ++ + purgatory/arch/arm64/purgatory-arm64.c | 35 ++ + 16 files changed, 1596 insertions(+), 2 deletions(-) + create mode 100644 kexec/arch/arm64/Makefile + create mode 100644 kexec/arch/arm64/crashdump-arm64.c + create mode 100644 kexec/arch/arm64/crashdump-arm64.h + create mode 100644 kexec/arch/arm64/image-header.h + create mode 100644 kexec/arch/arm64/include/arch/options.h + create mode 100644 kexec/arch/arm64/kexec-arm64.c + create mode 100644 kexec/arch/arm64/kexec-arm64.h + create mode 100644 kexec/arch/arm64/kexec-elf-arm64.c + create mode 100644 kexec/arch/arm64/kexec-image-arm64.c + create mode 100644 purgatory/arch/arm64/Makefile + create mode 100644 purgatory/arch/arm64/entry.S + create mode 100644 purgatory/arch/arm64/purgatory-arm64.c + +diff --git a/configure.ac b/configure.ac +index 6946780d498f..701ed69c5033 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -35,6 +35,9 @@ case $target_cpu in + ARCH="ppc64" + SUBARCH="LE" + ;; ++ aarch64* ) ++ ARCH="arm64" ++ ;; + arm* ) + ARCH="arm" + ;; +diff --git a/kexec/Makefile b/kexec/Makefile +index 6937a4dbb38b..fac668072463 100644 +--- a/kexec/Makefile ++++ b/kexec/Makefile +@@ -75,6 +75,7 @@ KEXEC_SRCS += $($(ARCH)_DT_OPS) + + include $(srcdir)/kexec/arch/alpha/Makefile + include $(srcdir)/kexec/arch/arm/Makefile ++include $(srcdir)/kexec/arch/arm64/Makefile + include $(srcdir)/kexec/arch/i386/Makefile + include $(srcdir)/kexec/arch/ia64/Makefile + include $(srcdir)/kexec/arch/m68k/Makefile +diff --git a/kexec/arch/arm64/Makefile b/kexec/arch/arm64/Makefile +new file mode 100644 +index 000000000000..37414dc5c900 +--- /dev/null ++++ b/kexec/arch/arm64/Makefile +@@ -0,0 +1,40 @@ ++ ++arm64_FS2DT += kexec/fs2dt.c ++arm64_FS2DT_INCLUDE += -include $(srcdir)/kexec/arch/arm64/kexec-arm64.h \ ++ -include $(srcdir)/kexec/arch/arm64/crashdump-arm64.h ++ ++arm64_DT_OPS += kexec/dt-ops.c ++ ++arm64_CPPFLAGS += -I $(srcdir)/kexec/ ++ ++arm64_KEXEC_SRCS += \ ++ kexec/arch/arm64/kexec-arm64.c \ ++ kexec/arch/arm64/kexec-image-arm64.c \ ++ kexec/arch/arm64/kexec-elf-arm64.c \ ++ kexec/arch/arm64/crashdump-arm64.c ++ ++arm64_ARCH_REUSE_INITRD = ++arm64_ADD_SEGMENT = ++arm64_VIRT_TO_PHYS = ++arm64_PHYS_TO_VIRT = ++ ++dist += $(arm64_KEXEC_SRCS) \ ++ kexec/arch/arm64/Makefile \ ++ kexec/arch/arm64/kexec-arm64.h \ ++ kexec/arch/arm64/crashdump-arm64.h ++ ++ifdef HAVE_LIBFDT ++ ++LIBS += -lfdt ++ ++else ++ ++include $(srcdir)/kexec/libfdt/Makefile.libfdt ++ ++libfdt_SRCS += $(LIBFDT_SRCS:%=kexec/libfdt/%) ++ ++arm64_CPPFLAGS += -I$(srcdir)/kexec/libfdt ++ ++arm64_KEXEC_SRCS += $(libfdt_SRCS) ++ ++endif +diff --git a/kexec/arch/arm64/crashdump-arm64.c b/kexec/arch/arm64/crashdump-arm64.c +new file mode 100644 +index 000000000000..d2272c8124d0 +--- /dev/null ++++ b/kexec/arch/arm64/crashdump-arm64.c +@@ -0,0 +1,21 @@ ++/* ++ * ARM64 crashdump. ++ */ ++ ++#define _GNU_SOURCE ++ ++#include ++#include ++ ++#include "kexec.h" ++#include "crashdump.h" ++#include "crashdump-arm64.h" ++#include "kexec-arm64.h" ++#include "kexec-elf.h" ++ ++struct memory_ranges usablemem_rgns = {}; ++ ++int is_crashkernel_mem_reserved(void) ++{ ++ return 0; ++} +diff --git a/kexec/arch/arm64/crashdump-arm64.h b/kexec/arch/arm64/crashdump-arm64.h +new file mode 100644 +index 000000000000..f33c7a25b454 +--- /dev/null ++++ b/kexec/arch/arm64/crashdump-arm64.h +@@ -0,0 +1,12 @@ ++/* ++ * ARM64 crashdump. ++ */ ++ ++#if !defined(CRASHDUMP_ARM64_H) ++#define CRASHDUMP_ARM64_H ++ ++#include "kexec.h" ++ ++extern struct memory_ranges usablemem_rgns; ++ ++#endif +diff --git a/kexec/arch/arm64/image-header.h b/kexec/arch/arm64/image-header.h +new file mode 100644 +index 000000000000..acb839ab889c +--- /dev/null ++++ b/kexec/arch/arm64/image-header.h +@@ -0,0 +1,95 @@ ++/* ++ * ARM64 binary image support. ++ * Copyright (C) 2014 Linaro. ++ */ ++ ++#if !defined(__ARM64_IMAGE_HEADER_H) ++#define __ARM64_IMAGE_HEADER_H ++ ++#if !defined(__KERNEL__) ++#include ++#endif ++ ++#if !defined(__ASSEMBLY__) ++ ++/** ++ * struct arm64_image_header - arm64 kernel image header. ++ * ++ * @pe_sig: Optional PE format 'MZ' signature. ++ * @branch_code: Reserved for instructions to branch to stext. ++ * @text_offset: The image load offset in LSB byte order. ++ * @image_size: An estimated size of the memory image size in LSB byte order. ++ * @flags: Bit flags: ++ * Bit 7.0: Image byte order, 1=MSB. ++ * @reserved_1: Reserved. ++ * @magic: Magic number, "ARM\x64". ++ * @pe_header: Optional offset to a PE format header. ++ **/ ++ ++struct arm64_image_header { ++ uint8_t pe_sig[2]; ++ uint16_t branch_code[3]; ++ uint64_t text_offset; ++ uint64_t image_size; ++ uint8_t flags[8]; ++ uint64_t reserved_1[3]; ++ uint8_t magic[4]; ++ uint32_t pe_header; ++}; ++ ++static const uint8_t arm64_image_magic[4] = {'A', 'R', 'M', 0x64U}; ++static const uint8_t arm64_image_pe_sig[2] = {'M', 'Z'}; ++static const uint64_t arm64_image_flag_7_be = 0x01U; ++ ++/** ++ * arm64_header_check_magic - Helper to check the arm64 image header. ++ * ++ * Returns non-zero if header is OK. ++ */ ++ ++static inline int arm64_header_check_magic(const struct arm64_image_header *h) ++{ ++ if (!h) ++ return 0; ++ ++ if (!h->text_offset) ++ return 0; ++ ++ return (h->magic[0] == arm64_image_magic[0] ++ && h->magic[1] == arm64_image_magic[1] ++ && h->magic[2] == arm64_image_magic[2] ++ && h->magic[3] == arm64_image_magic[3]); ++} ++ ++/** ++ * arm64_header_check_pe_sig - Helper to check the arm64 image header. ++ * ++ * Returns non-zero if 'MZ' signature is found. ++ */ ++ ++static inline int arm64_header_check_pe_sig(const struct arm64_image_header *h) ++{ ++ if (!h) ++ return 0; ++ ++ return (h->pe_sig[0] == arm64_image_pe_sig[0] ++ && h->pe_sig[1] == arm64_image_pe_sig[1]); ++} ++ ++/** ++ * arm64_header_check_msb - Helper to check the arm64 image header. ++ * ++ * Returns non-zero if the image was built as big endian. ++ */ ++ ++static inline int arm64_header_check_msb(const struct arm64_image_header *h) ++{ ++ if (!h) ++ return 0; ++ ++ return !!(h->flags[7] & arm64_image_flag_7_be); ++} ++ ++#endif /* !defined(__ASSEMBLY__) */ ++ ++#endif +diff --git a/kexec/arch/arm64/include/arch/options.h b/kexec/arch/arm64/include/arch/options.h +new file mode 100644 +index 000000000000..51afc5f1f6f2 +--- /dev/null ++++ b/kexec/arch/arm64/include/arch/options.h +@@ -0,0 +1,44 @@ ++#if !defined(KEXEC_ARCH_ARM64_OPTIONS_H) ++#define KEXEC_ARCH_ARM64_OPTIONS_H ++ ++#define OPT_APPEND ((OPT_MAX)+0) ++#define OPT_DTB ((OPT_MAX)+1) ++#define OPT_INITRD ((OPT_MAX)+2) ++#define OPT_LITE ((OPT_MAX)+3) ++#define OPT_PORT ((OPT_MAX)+4) ++#define OPT_ARCH_MAX ((OPT_MAX)+5) ++ ++#define KEXEC_ARCH_OPTIONS \ ++ KEXEC_OPTIONS \ ++ { "append", 1, NULL, OPT_APPEND }, \ ++ { "command-line", 1, NULL, OPT_APPEND }, \ ++ { "dtb", 1, NULL, OPT_DTB }, \ ++ { "initrd", 1, NULL, OPT_INITRD }, \ ++ { "lite", 0, NULL, OPT_LITE }, \ ++ { "port", 1, NULL, OPT_PORT }, \ ++ { "ramdisk", 1, NULL, OPT_INITRD }, \ ++ ++#define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR /* Only accept long arch options. */ ++#define KEXEC_ALL_OPTIONS KEXEC_ARCH_OPTIONS ++#define KEXEC_ALL_OPT_STR KEXEC_ARCH_OPT_STR ++ ++static const char arm64_opts_usage[] __attribute__ ((unused)) = ++" --append=STRING Set the kernel command line to STRING.\n" ++" --command-line=STRING Set the kernel command line to STRING.\n" ++" --dtb=FILE Use FILE as the device tree blob.\n" ++" --initrd=FILE Use FILE as the kernel initial ramdisk.\n" ++" --lite Fast reboot, no memory integrity checks - currently NOT SUPPORTED.\n"); ++" --port=ADDRESS Purgatory output to port ADDRESS.\n" ++" --ramdisk=FILE Use FILE as the kernel initial ramdisk.\n"; ++ ++struct arm64_opts { ++ const char *command_line; ++ const char *dtb; ++ const char *initrd; ++ uint64_t port; ++ int lite; ++}; ++ ++extern struct arm64_opts arm64_opts; ++ ++#endif +diff --git a/kexec/arch/arm64/kexec-arm64.c b/kexec/arch/arm64/kexec-arm64.c +new file mode 100644 +index 000000000000..0860810b6e86 +--- /dev/null ++++ b/kexec/arch/arm64/kexec-arm64.c +@@ -0,0 +1,1041 @@ ++/* ++ * ARM64 kexec. ++ */ ++ ++#define _GNU_SOURCE ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++ ++#include "dt-ops.h" ++#include "kexec.h" ++#include "crashdump.h" ++#include "crashdump-arm64.h" ++#include "kexec-arm64.h" ++#include "fs2dt.h" ++#include "kexec-syscall.h" ++#include "arch/options.h" ++ ++/* Global varables the core kexec routines expect. */ ++ ++unsigned char reuse_initrd; ++ ++off_t initrd_base; ++off_t initrd_size; ++ ++const struct arch_map_entry arches[] = { ++ { "aarch64", KEXEC_ARCH_ARM64 }, ++ { "aarch64_be", KEXEC_ARCH_ARM64 }, ++ { NULL, 0 }, ++}; ++ ++/* arm64 global varables. */ ++ ++struct arm64_opts arm64_opts; ++struct arm64_mem arm64_mem = { ++ .memstart = UINT64_MAX, ++}; ++ ++static void set_memstart(uint64_t v) ++{ ++ if (arm64_mem.memstart == UINT64_MAX || v < arm64_mem.memstart) ++ arm64_mem.memstart = v; ++} ++ ++static int check_memstart(void) ++{ ++ return arm64_mem.memstart != UINT64_MAX; ++} ++ ++void arch_usage(void) ++{ ++ dbgprintf("Build time: %s : %s\n", __DATE__, __TIME__); ++ printf(arm64_opts_usage); ++} ++ ++int arch_process_options(int argc, char **argv) ++{ ++ static const char short_options[] = KEXEC_OPT_STR ""; ++ static const struct option options[] = { ++ KEXEC_ARCH_OPTIONS ++ { 0 } ++ }; ++ int opt; ++ ++ for (opt = 0; opt != -1; ) { ++ opt = getopt_long(argc, argv, short_options, options, 0); ++ ++ switch (opt) { ++ case OPT_APPEND: ++ arm64_opts.command_line = optarg; ++ break; ++ case OPT_DTB: ++ arm64_opts.dtb = optarg; ++ break; ++ case OPT_INITRD: ++ arm64_opts.initrd = optarg; ++ break; ++ case OPT_LITE: ++ arm64_opts.lite = 1; ++ fprintf(stderr, "kexec: --lite option currently NOT SUPPORTED.\n"); ++ break; ++ case OPT_PORT: ++ arm64_opts.port = strtoull(optarg, NULL, 0); ++ break; ++ default: ++ break; /* Ignore core and unknown options. */ ++ } ++ } ++ ++ kexec_debug = 1; // FIXME: for debugging only. ++ ++ dbgprintf("%s:%d: command_line: %s\n", __func__, __LINE__, ++ arm64_opts.command_line); ++ dbgprintf("%s:%d: initrd: %s\n", __func__, __LINE__, ++ arm64_opts.initrd); ++ dbgprintf("%s:%d: dtb: %s\n", __func__, __LINE__, arm64_opts.dtb); ++ dbgprintf("%s:%d: lite: %d\n", __func__, __LINE__, arm64_opts.lite); ++ dbgprintf("%s:%d: port: 0x%" PRIx64 "\n", __func__, __LINE__, ++ arm64_opts.port); ++ ++ return 0; ++} ++ ++struct dtb { ++ char *buf; ++ off_t size; ++ const char *name; ++ const char *path; ++}; ++ ++static void dump_reservemap(const struct dtb *dtb) ++{ ++ int i; ++ ++ for (i = 0; ; i++) { ++ uint64_t address; ++ uint64_t size; ++ ++ fdt_get_mem_rsv(dtb->buf, i, &address, &size); ++ ++ if (!size) ++ break; ++ ++ dbgprintf("%s: %s {%" PRIx64 ", %" PRIx64 "}\n", __func__, ++ dtb->name, address, size); ++ } ++} ++ ++enum cpu_enable_method { ++ cpu_enable_method_unknown, ++ cpu_enable_method_psci, ++ cpu_enable_method_spin_table, ++}; ++ ++/** ++ * struct cpu_properties - Various properties from a device tree cpu node. ++ * ++ * These properties will be valid over a dtb re-size. ++ */ ++ ++struct cpu_properties { ++ uint64_t hwid; ++ uint64_t cpu_release_addr; ++ char node_path[128]; ++ char enable_method[128]; ++ enum cpu_enable_method type; ++}; ++ ++/** ++ * read_cpu_properties - Helper to read the device tree cpu properties. ++ */ ++ ++static int read_cpu_properties(struct cpu_properties *cp, ++ const struct dtb *dtb, int node_offset, unsigned int address_cells) ++{ ++ int result; ++ const void *data; ++ ++ result = fdt_get_path(dtb->buf, node_offset, cp->node_path, ++ sizeof(cp->node_path)); ++ ++ if (result < 0) { ++ fprintf(stderr, "kexec: %s:%d: %s: fdt_get_path failed: %s\n", ++ __func__, __LINE__, dtb->name, fdt_strerror(result)); ++ return result; ++ } ++ ++ data = fdt_getprop(dtb->buf, node_offset, "device_type", &result); ++ ++ if (!data) { ++ dbgprintf("%s: %s (%s) read device_type failed: %s\n", ++ __func__, dtb->name, cp->node_path, ++ fdt_strerror(result)); ++ return result == -FDT_ERR_NOTFOUND ? 0 : result; ++ } ++ ++ if (strcmp(data, "cpu")) { ++ dbgprintf("%s: %s (%s): '%s'\n", __func__, dtb->name, ++ cp->node_path, (const char *)data); ++ return 0; ++ } ++ ++ data = fdt_getprop(dtb->buf, node_offset, "reg", &result); ++ ++ if (!data) { ++ fprintf(stderr, "kexec: %s:%d: read hwid failed: %s\n", ++ __func__, __LINE__, fdt_strerror(result)); ++ return result; ++ } ++ ++ cp->hwid = (address_cells == 1) ? fdt32_to_cpu(*(uint32_t *)data) : ++ fdt64_to_cpu(*(uint64_t *)data); ++ ++ data = fdt_getprop(dtb->buf, node_offset, "enable-method", &result); ++ ++ if (!data) { ++ fprintf(stderr, ++ "kexec: %s:%d: read enable_method failed: %s\n", ++ __func__, __LINE__, fdt_strerror(result)); ++ return result; ++ } ++ ++ strncpy(cp->enable_method, data, sizeof(cp->enable_method)); ++ cp->enable_method[sizeof(cp->enable_method) - 1] = 0; ++ ++ if (!strcmp(cp->enable_method, "psci")) { ++ cp->type = cpu_enable_method_psci; ++ return 1; ++ } ++ ++ if (strcmp(cp->enable_method, "spin-table")) { ++ cp->type = cpu_enable_method_unknown; ++ return -1; ++ } ++ ++ cp->type = cpu_enable_method_spin_table; ++ ++ data = fdt_getprop(dtb->buf, node_offset, "cpu-release-addr", &result); ++ ++ if (!data) { ++ fprintf(stderr, "kexec: %s:%d: " ++ "read cpu-release-addr failed: %s\n", ++ __func__, __LINE__, fdt_strerror(result)); ++ return result; ++ } ++ ++ cp->cpu_release_addr = fdt64_to_cpu(*(uint64_t *)data); ++ ++ return 1; ++} ++ ++static int check_cpu_properties(const struct cpu_properties *cp_1, ++ const struct cpu_properties *cp_2) ++{ ++ assert(cp_1->hwid == cp_2->hwid); ++ ++ if (cp_1->type != cp_2->type) { ++ fprintf(stderr, ++ "%s:%d: hwid-%" PRIx64 ": " ++ "Error: Different enable methods: %s -> %s\n", ++ __func__, __LINE__, cp_1->hwid, cp_1->enable_method, ++ cp_2->enable_method); ++ return -EINVAL; ++ } ++ ++ if (cp_1->type != cpu_enable_method_psci ++ && cp_1->type != cpu_enable_method_spin_table) { ++ fprintf(stderr, ++ "%s:%d: hwid-%" PRIx64 ": " ++ "Warning: Unknown enable method: %s.\n", ++ __func__, __LINE__, cp_1->hwid, ++ cp_1->enable_method); ++ } ++ ++ if (cp_1->type == cpu_enable_method_spin_table) { ++ if (cp_1->cpu_release_addr != cp_2->cpu_release_addr) { ++ fprintf(stderr, "%s:%d: hwid-%" PRIx64 ": " ++ "Error: Different cpu-release-addr: " ++ "%" PRIx64 " -> %" PRIx64 ".\n", ++ __func__, __LINE__, ++ cp_1->hwid, ++ cp_2->cpu_release_addr, ++ cp_1->cpu_release_addr); ++ return -EINVAL; ++ } ++ } ++ ++ dbgprintf("%s: hwid-%" PRIx64 ": OK\n", __func__, cp_1->hwid); ++ ++ return 0; ++} ++ ++struct cpu_info { ++ unsigned int cpu_count; ++ struct cpu_properties *cp; ++}; ++ ++static int read_cpu_info(struct cpu_info *info, const struct dtb *dtb) ++{ ++ int i; ++ int offset; ++ int result; ++ int depth; ++ const void *data; ++ unsigned int address_cells; ++ ++ offset = fdt_subnode_offset(dtb->buf, 0, "cpus"); ++ ++ if (offset < 0) { ++ fprintf(stderr, "kexec: %s:%d: read cpus node failed: %s\n", ++ __func__, __LINE__, fdt_strerror(offset)); ++ return offset; ++ } ++ ++ data = fdt_getprop(dtb->buf, offset, "#address-cells", &result); ++ ++ if (!data) { ++ fprintf(stderr, ++ "kexec: %s:%d: read cpus address-cells failed: %s\n", ++ __func__, __LINE__, fdt_strerror(result)); ++ return result; ++ } ++ ++ address_cells = fdt32_to_cpu(*(uint32_t *)data); ++ ++ if (address_cells < 1 || address_cells > 2) { ++ fprintf(stderr, ++ "kexec: %s:%d: bad cpus address-cells value: %u\n", ++ __func__, __LINE__, address_cells); ++ return -EINVAL; ++ } ++ ++ for (i = 0, depth = 0; ; i++) { ++ info->cp = realloc(info->cp, (i + 1) * sizeof(*info->cp)); ++ ++ if (!info->cp) { ++ fprintf(stderr, "kexec: %s:%d: malloc failed: %s\n", ++ __func__, __LINE__, fdt_strerror(offset)); ++ result = -ENOMEM; ++ goto on_error; ++ } ++ ++next_node: ++ memset(&info->cp[i], 0, sizeof(*info->cp)); ++ ++ offset = fdt_next_node(dtb->buf, offset, &depth); ++ ++ if (offset < 0) { ++ fprintf(stderr, "kexec: %s:%d: " ++ "read cpu node failed: %s\n", __func__, ++ __LINE__, fdt_strerror(offset)); ++ result = offset; ++ goto on_error; ++ } ++ ++ if (depth != 1) ++ break; ++ ++ result = read_cpu_properties(&info->cp[i], dtb, offset, ++ address_cells); ++ ++ if (result == 0) ++ goto next_node; ++ ++ if (result < 0) ++ goto on_error; ++ ++ if (info->cp[i].type == cpu_enable_method_psci) ++ dbgprintf("%s: %s cpu-%d (%s): hwid-%" PRIx64 ", '%s'\n", ++ __func__, dtb->name, i, info->cp[i].node_path, ++ info->cp[i].hwid, ++ info->cp[i].enable_method); ++ else ++ dbgprintf("%s: %s cpu-%d (%s): hwid-%" PRIx64 ", '%s', " ++ "cpu-release-addr %" PRIx64 "\n", ++ __func__, dtb->name, i, info->cp[i].node_path, ++ info->cp[i].hwid, ++ info->cp[i].enable_method, ++ info->cp[i].cpu_release_addr); ++ } ++ ++ info->cpu_count = i; ++ return 0; ++ ++on_error: ++ free(info->cp); ++ info->cp = NULL; ++ return result; ++} ++ ++static int check_cpu_nodes(const struct dtb *dtb_1, const struct dtb *dtb_2) ++{ ++ int result; ++ unsigned int cpu_1; ++ struct cpu_info info_1; ++ struct cpu_info info_2; ++ unsigned int to_process; ++ ++ memset(&info_1, 0, sizeof(info_1)); ++ memset(&info_2, 0, sizeof(info_2)); ++ ++ result = read_cpu_info(&info_1, dtb_1); ++ ++ if (result) ++ goto on_exit; ++ ++ result = read_cpu_info(&info_2, dtb_2); ++ ++ if (result) ++ goto on_exit; ++ ++ to_process = info_1.cpu_count < info_2.cpu_count ++ ? info_1.cpu_count : info_2.cpu_count; ++ ++ for (cpu_1 = 0; cpu_1 < info_1.cpu_count; cpu_1++) { ++ struct cpu_properties *cp_1 = &info_1.cp[cpu_1]; ++ unsigned int cpu_2; ++ ++ for (cpu_2 = 0; cpu_2 < info_2.cpu_count; cpu_2++) { ++ struct cpu_properties *cp_2 = &info_2.cp[cpu_2]; ++ ++ if (cp_1->hwid != cp_2->hwid) ++ continue; ++ ++ to_process--; ++ ++ result = check_cpu_properties(cp_1, cp_2); ++ ++ if (result) ++ goto on_exit; ++ } ++ } ++ ++ if (to_process) { ++ fprintf(stderr, "kexec: %s:%d: Warning: " ++ "Failed to process %u CPUs.\n", ++ __func__, __LINE__, to_process); ++ result = -EINVAL; ++ goto on_exit; ++ } ++ ++on_exit: ++ free(info_1.cp); ++ free(info_2.cp); ++ return result; ++} ++ ++static int set_bootargs(struct dtb *dtb, const char *command_line) ++{ ++ int result; ++ ++ if (!command_line || !command_line[0]) ++ return 0; ++ ++ result = dtb_set_bootargs((char **)&dtb->buf, &dtb->size, command_line); ++ ++ if (result) ++ fprintf(stderr, ++ "kexec: Set device tree bootargs failed.\n"); ++ ++ return result; ++} ++ ++static int read_proc_dtb(struct dtb *dtb, const char *command_line) ++{ ++ int result; ++ struct stat s; ++ static const char path[] = "/proc/device-tree"; ++ ++ result = stat(path, &s); ++ ++ if (result) { ++ dbgprintf("%s: %s\n", __func__, strerror(errno)); ++ return -1; ++ } ++ ++ dtb->path = path; ++ create_flatten_tree((char **)&dtb->buf, &dtb->size, ++ (command_line && command_line[0]) ? command_line : NULL); ++ ++ return 0; ++} ++ ++static int read_sys_dtb(struct dtb *dtb, const char *command_line) ++{ ++ int result; ++ struct stat s; ++ static const char path[] = "/sys/firmware/fdt"; ++ ++ result = stat(path, &s); ++ ++ if (result) { ++ dbgprintf("%s: %s\n", __func__, strerror(errno)); ++ return -1; ++ } ++ ++ dtb->path = path; ++ dtb->buf = slurp_file("/sys/firmware/fdt", &dtb->size); ++ ++ return set_bootargs(dtb, command_line); ++} ++ ++static int read_1st_dtb(struct dtb *dtb, const char *command_line) ++{ ++ int result; ++ ++ result = read_sys_dtb(dtb, command_line); ++ ++ if (!result) ++ goto on_success; ++ ++ result = read_proc_dtb(dtb, command_line); ++ ++ if (!result) ++ goto on_success; ++ ++ return -1; ++ ++on_success: ++ dbgprintf("%s: found %s\n", __func__, dtb->path); ++ return 0; ++} ++ ++static int setup_2nd_dtb(char *command_line, const struct dtb *dtb_1, ++ struct dtb *dtb_2) ++{ ++ int result; ++ ++ result = fdt_check_header(dtb_2->buf); ++ ++ if (result) { ++ fprintf(stderr, "kexec: Invalid 2nd device tree.\n"); ++ return -EINVAL; ++ } ++ ++ result = set_bootargs(dtb_2, command_line); ++ ++ dump_reservemap(dtb_2); ++ ++ return result; ++} ++ ++static uint64_t read_sink(const char *command_line) ++{ ++ uint64_t v; ++ const char *p; ++ ++ if (arm64_opts.port) ++ return arm64_opts.port; ++ ++#if defined(ARM64_DEBUG_PORT) ++ return (uint64_t)(ARM64_DEBUG_PORT); ++#endif ++ if (!command_line) ++ return 0; ++ ++ p = strstr(command_line, "earlyprintk="); ++ ++ if (!p) ++ return 0; ++ ++ while (*p != ',') ++ p++; ++ ++ p++; ++ ++ while (isspace(*p)) ++ p++; ++ ++ if (*p == 0) ++ return 0; ++ ++ errno = 0; ++ ++ v = strtoull(p, NULL, 0); ++ ++ if (errno) ++ return 0; ++ ++ return v; ++} ++ ++/** ++ * arm64_load_other_segments - Prepare the dtb, initrd and purgatory segments. ++ */ ++ ++int arm64_load_other_segments(struct kexec_info *info, ++ unsigned long kernel_entry) ++{ ++ int result; ++ struct mem_ehdr ehdr; ++ unsigned long dtb_max; ++ unsigned long dtb_base; ++ char *initrd_buf = NULL; ++ uint64_t purgatory_sink; ++ unsigned long purgatory_base; ++ struct dtb dtb_1 = {.name = "dtb_1"}; ++ struct dtb dtb_2 = {.name = "dtb_2"}; ++ char command_line[COMMAND_LINE_SIZE] = ""; ++ ++ if (arm64_opts.command_line) { ++ strncpy(command_line, arm64_opts.command_line, ++ sizeof(command_line)); ++ command_line[sizeof(command_line) - 1] = 0; ++ } ++ ++ purgatory_sink = read_sink(command_line); ++ ++ dbgprintf("%s:%d: purgatory sink: 0x%" PRIx64 "\n", __func__, __LINE__, ++ purgatory_sink); ++ ++ if (arm64_opts.dtb) { ++ dtb_2.buf = slurp_file(arm64_opts.dtb, &dtb_2.size); ++ assert(dtb_2.buf); ++ } ++ ++ result = read_1st_dtb(&dtb_1, command_line); ++ ++ if (result && !arm64_opts.dtb) { ++ fprintf(stderr, "kexec: Error: No device tree available.\n"); ++ return result; ++ } ++ ++ if (result && arm64_opts.dtb) ++ dtb_1 = dtb_2; ++ else if (!result && !arm64_opts.dtb) ++ dtb_2 = dtb_1; ++ ++ result = setup_2nd_dtb(command_line, &dtb_1, &dtb_2); ++ ++ if (result) ++ return result; ++ ++ result = check_cpu_nodes(&dtb_1, &dtb_2); ++ ++ if (result) ++ return result; ++ ++ /* ++ * Put the DTB after the kernel with an alignment of 128 KiB, giving ++ * a max supported DTB size of 128 KiB (worst case). Also add 2 KiB ++ * to the DTB size for any DTB growth. ++ */ ++ ++ dtb_max = dtb_2.size + 2 * 1024; ++ ++ dtb_base = locate_hole(info, dtb_max, 128UL * 1024, ++ arm64_mem.memstart + arm64_mem.text_offset ++ + arm64_mem.image_size, ++ _ALIGN_UP(arm64_mem.memstart + arm64_mem.text_offset, ++ 512UL * 1024 * 1024), ++ 1); ++ ++ dbgprintf("dtb: base %lx, size %lxh (%ld)\n", dtb_base, dtb_2.size, ++ dtb_2.size); ++ ++ if (dtb_base == ULONG_MAX) ++ return -ENOMEM; ++ ++ purgatory_base = dtb_base + dtb_2.size; ++ initrd_base = 0; ++ initrd_size = 0; ++ ++ if (arm64_opts.initrd) { ++ initrd_buf = slurp_file(arm64_opts.initrd, &initrd_size); ++ ++ if (!initrd_buf) ++ fprintf(stderr, "kexec: Empty ramdisk file.\n"); ++ else { ++ /* Put the initrd after the DTB with an alignment of ++ * page size. */ ++ ++ initrd_base = locate_hole(info, initrd_size, 0, ++ dtb_base + dtb_max, -1, 1); ++ ++ dbgprintf("initrd: base %lx, size %lxh (%ld)\n", ++ initrd_base, initrd_size, initrd_size); ++ ++ if (initrd_base == ULONG_MAX) ++ return -ENOMEM; ++ ++ result = dtb_set_initrd((char **)&dtb_2.buf, ++ &dtb_2.size, initrd_base, ++ initrd_base + initrd_size); ++ ++ if (result) ++ return result; ++ ++ purgatory_base = initrd_base + initrd_size; ++ } ++ } ++ ++ if (dtb_2.size > dtb_max) { ++ fprintf(stderr, "%s: Error: Too many DTB mods.\n", __func__); ++ return -EINVAL; ++ } ++ ++ add_segment_phys_virt(info, dtb_2.buf, dtb_2.size, dtb_base, ++ dtb_2.size, 0); ++ ++ if (arm64_opts.initrd) ++ add_segment_phys_virt(info, initrd_buf, initrd_size, ++ initrd_base, initrd_size, 0); ++ ++ if (arm64_opts.lite) { ++ fprintf(stderr, "kexec: --lite option currently NOT SUPPORTED.\n"); ++ return -ENOSYS; ++ } else { ++ result = build_elf_rel_info(purgatory, purgatory_size, &ehdr, ++ 0); ++ ++ if (result < 0) { ++ fprintf(stderr, "%s: Error: " ++ "build_elf_rel_info failed.\n", __func__); ++ return -EBADF; ++ } ++ ++ elf_rel_build_load(info, &info->rhdr, purgatory, purgatory_size, ++ purgatory_base, ULONG_MAX, 1, 0); ++ ++ info->entry = (void *)elf_rel_get_addr(&info->rhdr, ++ "purgatory_start"); ++ ++ elf_rel_set_symbol(&info->rhdr, "arm64_sink", &purgatory_sink, ++ sizeof(purgatory_sink)); ++ ++ elf_rel_set_symbol(&info->rhdr, "arm64_kernel_entry", ++ &kernel_entry, sizeof(kernel_entry)); ++ ++ elf_rel_set_symbol(&info->rhdr, "arm64_dtb_addr", &dtb_base, ++ sizeof(dtb_base)); ++ } ++ ++ return 0; ++} ++ ++unsigned long virt_to_phys(unsigned long v) ++{ ++ unsigned long p; ++ ++ assert(arm64_mem.page_offset); ++ assert(check_memstart()); ++ ++ p = v - arm64_mem.page_offset + arm64_mem.memstart; ++ ++ dbgprintf("%s: %016lx -> %016lx\n", __func__, v, p); ++ return p; ++} ++ ++unsigned long phys_to_virt(struct crash_elf_info *UNUSED(elf_info), ++ unsigned long p) ++{ ++ unsigned long v; ++ ++ assert(arm64_mem.page_offset); ++ assert(check_memstart()); ++ ++ v = p - arm64_mem.memstart + arm64_mem.page_offset; ++ ++ dbgprintf("%s: %016lx -> %016lx\n", __func__, p, v); ++ return p; ++} ++ ++void add_segment(struct kexec_info *info, const void *buf, size_t bufsz, ++ unsigned long base, size_t memsz) ++{ ++ add_segment_phys_virt(info, buf, bufsz, base, memsz, 1); ++} ++ ++int arm64_process_image_header(const struct arm64_image_header *h) ++{ ++#if !defined(KERNEL_IMAGE_SIZE) ++# define KERNEL_IMAGE_SIZE (768 * 1024) ++#endif ++ ++ if (!arm64_header_check_magic(h)) ++ return -EINVAL; ++ ++ if (h->image_size) { ++ arm64_mem.text_offset = le64_to_cpu(h->text_offset); ++ arm64_mem.image_size = le64_to_cpu(h->image_size); ++ } else { ++ /* For 3.16 and older kernels. */ ++ arm64_mem.text_offset = 0x80000; ++ arm64_mem.image_size = KERNEL_IMAGE_SIZE; ++ } ++ ++ return 0; ++} ++ ++static int get_memory_ranges_dt(struct memory_range *array, unsigned int *count) ++{ ++ struct region {uint64_t base; uint64_t size;}; ++ struct dtb dtb = {.name = "range_dtb"}; ++ int offset; ++ int result; ++ ++ *count = 0; ++ ++ result = read_1st_dtb(&dtb, NULL); ++ ++ if (result) { ++ goto on_error; ++ } ++ ++ result = fdt_check_header(dtb.buf); ++ ++ if (result) { ++ dbgprintf("%s:%d: %s: fdt_check_header failed:%s\n", __func__, ++ __LINE__, dtb.path, fdt_strerror(result)); ++ goto on_error; ++ } ++ ++ for (offset = 0; ; ) { ++ const struct region *region; ++ const struct region *end; ++ int len; ++ ++ offset = fdt_subnode_offset(dtb.buf, offset, "memory"); ++ ++ if (offset == -FDT_ERR_NOTFOUND) ++ break; ++ ++ if (offset <= 0) { ++ dbgprintf("%s:%d: fdt_subnode_offset failed: %d %s\n", ++ __func__, __LINE__, offset, ++ fdt_strerror(offset)); ++ goto on_error; ++ } ++ ++ dbgprintf("%s:%d: node_%d %s\n", __func__, __LINE__, offset, ++ fdt_get_name(dtb.buf, offset, NULL)); ++ ++ region = fdt_getprop(dtb.buf, offset, "reg", &len); ++ ++ if (region <= 0) { ++ dbgprintf("%s:%d: fdt_getprop failed: %d %s\n", ++ __func__, __LINE__, offset, ++ fdt_strerror(offset)); ++ goto on_error; ++ } ++ ++ for (end = region + len / sizeof(*region); ++ region < end && *count < KEXEC_SEGMENT_MAX; ++ region++) { ++ struct memory_range r; ++ ++ r.type = RANGE_RAM; ++ r.start = fdt64_to_cpu(region->base); ++ r.end = r.start + fdt64_to_cpu(region->size); ++ ++ if (!region->size) { ++ dbgprintf("%s:%d: SKIP: %016llx - %016llx\n", ++ __func__, __LINE__, r.start, r.end); ++ continue; ++ } ++ ++ dbgprintf("%s:%d: RAM: %016llx - %016llx\n", __func__, ++ __LINE__, r.start, r.end); ++ ++ array[(*count)++] = r; ++ ++ set_memstart(r.start); ++ } ++ } ++ ++ if (!*count) { ++ dbgprintf("%s:%d: %s: No RAM found.\n", __func__, __LINE__, ++ dtb.path); ++ goto on_error; ++ } ++ ++ dbgprintf("%s:%d: %s: Success\n", __func__, __LINE__, dtb.path); ++ result = 0; ++ goto on_exit; ++ ++on_error: ++ fprintf(stderr, "%s:%d: %s: Unusable device-tree file\n", __func__, ++ __LINE__, dtb.path); ++ result = -1; ++ ++on_exit: ++ free(dtb.buf); ++ return result; ++} ++ ++static int get_memory_ranges_iomem(struct memory_range *array, ++ unsigned int *count) ++{ ++ const char *iomem; ++ char line[MAX_LINE]; ++ FILE *fp; ++ ++ *count = 0; ++ ++ iomem = proc_iomem(); ++ fp = fopen(iomem, "r"); ++ ++ if (!fp) { ++ fprintf(stderr, "Cannot open %s: %s\n", iomem, strerror(errno)); ++ return -1; ++ } ++ ++ while(fgets(line, sizeof(line), fp) != 0) { ++ struct memory_range r; ++ char *str; ++ int consumed; ++ ++ if (*count >= KEXEC_SEGMENT_MAX) ++ break; ++ ++ if (sscanf(line, "%Lx-%Lx : %n", &r.start, &r.end, &consumed) ++ != 2) ++ continue; ++ ++ str = line + consumed; ++ r.end++; ++ ++ if (memcmp(str, "System RAM\n", 11)) { ++ dbgprintf("%s:%d: SKIP: %016Lx - %016Lx : %s", __func__, ++ __LINE__, r.start, r.end, str); ++ continue; ++ } ++ ++ r.type = RANGE_RAM; ++ ++ dbgprintf("%s:%d: RAM: %016llx - %016llx : %s", __func__, ++ __LINE__, r.start, r.end, str); ++ ++ array[(*count)++] = r; ++ ++ set_memstart(r.start); ++ } ++ ++ fclose(fp); ++ ++ if (!*count) { ++ dbgprintf("%s:%d: failed: No RAM found.\n", __func__, __LINE__); ++ return -1; ++ } ++ ++ dbgprintf("%s:%d: Success\n", __func__, __LINE__); ++ return 0; ++} ++ ++int get_memory_ranges(struct memory_range **range, int *ranges, ++ unsigned long kexec_flags) ++{ ++ static struct memory_range array[KEXEC_SEGMENT_MAX]; ++ unsigned int count; ++ int result; ++ ++ result = get_memory_ranges_dt(array, &count); ++ ++ if (result) ++ result = get_memory_ranges_iomem(array, &count); ++ ++ *range = result ? NULL : array; ++ *ranges = result ? 0 : count; ++ ++ return result; ++} ++ ++struct file_type file_type[] = { ++ {"elf-arm64", elf_arm64_probe, elf_arm64_load, elf_arm64_usage}, ++ {"image-arm64", image_arm64_probe, image_arm64_load, image_arm64_usage}, ++}; ++ ++int file_types = sizeof(file_type) / sizeof(file_type[0]); ++ ++int arch_compat_trampoline(struct kexec_info *info) ++{ ++ return 0; ++} ++ ++int machine_verify_elf_rel(struct mem_ehdr *ehdr) ++{ ++ return (ehdr->e_machine == EM_AARCH64); ++} ++ ++void machine_apply_elf_rel(struct mem_ehdr *ehdr, unsigned long r_type, ++ void *ptr, unsigned long address, unsigned long value) ++{ ++#if !defined(R_AARCH64_ABS64) ++# define R_AARCH64_ABS64 257 ++#endif ++ ++#if !defined(R_AARCH64_LD_PREL_LO19) ++# define R_AARCH64_LD_PREL_LO19 273 ++#endif ++ ++#if !defined(R_AARCH64_ADR_PREL_LO21) ++# define R_AARCH64_ADR_PREL_LO21 274 ++#endif ++ ++#if !defined(R_AARCH64_JUMP26) ++# define R_AARCH64_JUMP26 282 ++#endif ++ ++#if !defined(R_AARCH64_CALL26) ++# define R_AARCH64_CALL26 283 ++#endif ++ ++ uint64_t *location = (uint64_t *)ptr; ++ uint64_t data = *location; ++ const char *type = NULL; ++ ++ switch(r_type) { ++ case R_AARCH64_ABS64: ++ type = "ABS64"; ++ *location += value; ++ break; ++ case R_AARCH64_LD_PREL_LO19: ++ type = "LD_PREL_LO19"; ++ *location += ((value - address) << 3) & 0xffffe0; ++ break; ++ case R_AARCH64_ADR_PREL_LO21: ++ if (value & 3) ++ die("%s: ERROR Unaligned value: %lx\n", __func__, ++ value); ++ type = "ADR_PREL_LO21"; ++ *location += ((value - address) << 3) & 0xffffe0; ++ break; ++ case R_AARCH64_JUMP26: ++ type = "JUMP26"; ++ *location += ((value - address) >> 2) & 0x3ffffff; ++ break; ++ case R_AARCH64_CALL26: ++ type = "CALL26"; ++ *location += ((value - address) >> 2) & 0x3ffffff; ++ break; ++ default: ++ die("%s: ERROR Unknown type: %lu\n", __func__, r_type); ++ break; ++ } ++ ++ dbgprintf("%s: %s %lx->%lx\n", __func__, type, data, *location); ++} ++ ++void arch_reuse_initrd(void) ++{ ++ reuse_initrd = 1; ++} ++ ++void arch_update_purgatory(struct kexec_info *UNUSED(info)) ++{ ++} +diff --git a/kexec/arch/arm64/kexec-arm64.h b/kexec/arch/arm64/kexec-arm64.h +new file mode 100644 +index 000000000000..057acf313b49 +--- /dev/null ++++ b/kexec/arch/arm64/kexec-arm64.h +@@ -0,0 +1,51 @@ ++/* ++ * ARM64 kexec. ++ */ ++ ++#if !defined(KEXEC_ARM64_H) ++#define KEXEC_ARM64_H ++ ++#include ++#include ++ ++#include "image-header.h" ++#include "kexec.h" ++ ++#define KEXEC_SEGMENT_MAX 16 ++ ++#define BOOT_BLOCK_VERSION 17 ++#define BOOT_BLOCK_LAST_COMP_VERSION 16 ++#define COMMAND_LINE_SIZE 512 ++ ++int elf_arm64_probe(const char *kernel_buf, off_t kernel_size); ++int elf_arm64_load(int argc, char **argv, const char *kernel_buf, ++ off_t kernel_size, struct kexec_info *info); ++void elf_arm64_usage(void); ++ ++int image_arm64_probe(const char *kernel_buf, off_t kernel_size); ++int image_arm64_load(int argc, char **argv, const char *kernel_buf, ++ off_t kernel_size, struct kexec_info *info); ++void image_arm64_usage(void); ++ ++struct memory_ranges usablemem_rgns; ++off_t initrd_base; ++off_t initrd_size; ++ ++/** ++ * struct arm64_mem - Memory layout info. ++ */ ++ ++struct arm64_mem { ++ uint64_t text_offset; ++ uint64_t image_size; ++ uint64_t page_offset; ++ uint64_t memstart; ++}; ++ ++extern struct arm64_mem arm64_mem; ++ ++int arm64_process_image_header(const struct arm64_image_header *h); ++int arm64_load_other_segments(struct kexec_info *info, ++ unsigned long kernel_entry); ++ ++#endif +diff --git a/kexec/arch/arm64/kexec-elf-arm64.c b/kexec/arch/arm64/kexec-elf-arm64.c +new file mode 100644 +index 000000000000..13dc5e2724d9 +--- /dev/null ++++ b/kexec/arch/arm64/kexec-elf-arm64.c +@@ -0,0 +1,123 @@ ++/* ++ * ARM64 kexec elf support. ++ */ ++ ++#define _GNU_SOURCE ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "dt-ops.h" ++#include "crashdump-arm64.h" ++#include "kexec-arm64.h" ++#include "fs2dt.h" ++#include "kexec-syscall.h" ++#include "arch/options.h" ++ ++int elf_arm64_probe(const char *kernel_buf, off_t kernel_size) ++{ ++ int result; ++ struct mem_ehdr ehdr; ++ ++ result = build_elf_exec_info(kernel_buf, kernel_size, &ehdr, 0); ++ ++ if (result < 0) { ++ dbgprintf("%s: Not an ELF executable.\n", __func__); ++ goto on_exit; ++ } ++ ++ if (ehdr.e_machine != EM_AARCH64) { ++ dbgprintf("%s: Not an AARCH64 ELF executable.\n", __func__); ++ result = -EINVAL; ++ goto on_exit; ++ } ++ ++ result = 0; ++ ++on_exit: ++ free_elf_info(&ehdr); ++ return result; ++} ++ ++int elf_arm64_load(int argc, char **argv, const char *kernel_buf, ++ off_t kernel_size, struct kexec_info *info) ++{ ++ int result; ++ struct mem_ehdr ehdr; ++ bool found_header; ++ int i; ++ ++ if (info->kexec_flags & KEXEC_ON_CRASH) { ++ fprintf(stderr, "kexec: kdump not yet supported on arm64\n"); ++ return -EINVAL; ++ } ++ ++ result = build_elf_exec_info(kernel_buf, kernel_size, &ehdr, 0); ++ ++ if (result < 0) { ++ dbgprintf("%s: build_elf_exec_info failed\n", __func__); ++ goto exit; ++ } ++ ++ /* Find and process the arm64 image header. */ ++ ++ for (i = 0, found_header = false; i < ehdr.e_phnum; i++) { ++ struct mem_phdr *phdr = &ehdr.e_phdr[i]; ++ const struct arm64_image_header *h; ++ ++ if (phdr->p_type != PT_LOAD) ++ continue; ++ ++ h = (const struct arm64_image_header *)(kernel_buf ++ + phdr->p_offset); ++ ++ if (arm64_process_image_header(h)) ++ continue; ++ ++ found_header = true; ++ ++ arm64_mem.page_offset = phdr->p_vaddr - arm64_mem.text_offset; ++ ++ dbgprintf("%s: PE format: %s\n", __func__, ++ (arm64_header_check_pe_sig(h) ? "yes" : "no")); ++ dbgprintf("p_vaddr: %016llx\n", phdr->p_vaddr); ++ ++ break; ++ } ++ ++ if (!found_header) { ++ fprintf(stderr, "kexec: Bad arm64 image header.\n"); ++ result = -EINVAL; ++ goto exit; ++ } ++ ++ result = elf_exec_load(&ehdr, info); ++ ++ if (result) { ++ fprintf(stderr, "kexec: Elf load failed.\n"); ++ goto exit; ++ } ++ ++ dbgprintf("%s: text_offset: %016lx\n", __func__, arm64_mem.text_offset); ++ dbgprintf("%s: image_size: %016lx\n", __func__, arm64_mem.image_size); ++ dbgprintf("%s: page_offset: %016lx\n", __func__, arm64_mem.page_offset); ++ dbgprintf("%s: memstart: %016lx\n", __func__, arm64_mem.memstart); ++ dbgprintf("%s: e_entry: %016llx -> %016lx\n", __func__, ++ ehdr.e_entry, virt_to_phys(ehdr.e_entry)); ++ ++ result = arm64_load_other_segments(info, virt_to_phys(ehdr.e_entry)); ++exit: ++ free_elf_info(&ehdr); ++ return result; ++} ++ ++void elf_arm64_usage(void) ++{ ++ printf( ++" An arm64 ELF file, big or little endian.\n" ++" Typically vmlinux or a stripped version of vmlinux.\n\n"); ++} +diff --git a/kexec/arch/arm64/kexec-image-arm64.c b/kexec/arch/arm64/kexec-image-arm64.c +new file mode 100644 +index 000000000000..b025dc6c0185 +--- /dev/null ++++ b/kexec/arch/arm64/kexec-image-arm64.c +@@ -0,0 +1,50 @@ ++/* ++ * ARM64 kexec binary image support. ++ */ ++ ++#define _GNU_SOURCE ++ ++#include ++#include ++#include ++#include ++ ++#include "dt-ops.h" ++#include "image-header.h" ++#include "kexec-arm64.h" ++#include "fs2dt.h" ++#include "kexec-syscall.h" ++#include "arch/options.h" ++ ++int image_arm64_probe(const char *kernel_buf, off_t kernel_size) ++{ ++ const struct arm64_image_header *h; ++ ++ if (kernel_size < sizeof(struct arm64_image_header)) ++ return -EINVAL; ++ ++ h = (const struct arm64_image_header *)(kernel_buf); ++ ++ if (!arm64_header_check_magic(h)) ++ return -1; ++ ++ dbgprintf("%s: PE format: %s\n", __func__, ++ (arm64_header_check_pe_sig(h) ? "yes" : "no")); ++ ++ fprintf(stderr, "kexec: arm64 binary Image files are currently NOT SUPPORTED.\n"); ++ ++ return -1; ++} ++ ++int image_arm64_load(int argc, char **argv, const char *kernel_buf, ++ off_t kernel_size, struct kexec_info *info) ++{ ++ return -ENOSYS; ++} ++ ++void image_arm64_usage(void) ++{ ++ printf( ++" An arm64 binary Image file, big or little endian.\n" ++" This file type is currently NOT SUPPORTED.\n\n"); ++} +diff --git a/kexec/kexec-syscall.h b/kexec/kexec-syscall.h +index ce2e20b8b04b..267b75b02272 100644 +--- a/kexec/kexec-syscall.h ++++ b/kexec/kexec-syscall.h +@@ -39,8 +39,8 @@ + #ifdef __s390__ + #define __NR_kexec_load 277 + #endif +-#ifdef __arm__ +-#define __NR_kexec_load __NR_SYSCALL_BASE + 347 ++#if defined(__arm__) || defined(__arm64__) ++#define __NR_kexec_load __NR_SYSCALL_BASE + 347 + #endif + #if defined(__mips__) + #define __NR_kexec_load 4311 +@@ -108,6 +108,8 @@ static inline long kexec_file_load(int kernel_fd, int initrd_fd, + #define KEXEC_ARCH_PPC64 (21 << 16) + #define KEXEC_ARCH_IA_64 (50 << 16) + #define KEXEC_ARCH_ARM (40 << 16) ++#define KEXEC_ARCH_ARM64 (183 << 16) ++/* #define KEXEC_ARCH_AARCH64 (183 << 16) */ + #define KEXEC_ARCH_S390 (22 << 16) + #define KEXEC_ARCH_SH (42 << 16) + #define KEXEC_ARCH_MIPS_LE (10 << 16) +@@ -153,5 +155,8 @@ static inline long kexec_file_load(int kernel_fd, int initrd_fd, + #ifdef __m68k__ + #define KEXEC_ARCH_NATIVE KEXEC_ARCH_68K + #endif ++#if defined(__arm64__) ++#define KEXEC_ARCH_NATIVE KEXEC_ARCH_ARM64 ++#endif + + #endif /* KEXEC_SYSCALL_H */ +diff --git a/purgatory/Makefile b/purgatory/Makefile +index 19457029e79f..0c85da6e29b8 100644 +--- a/purgatory/Makefile ++++ b/purgatory/Makefile +@@ -18,6 +18,7 @@ dist += purgatory/Makefile $(PURGATORY_SRCS) \ + + include $(srcdir)/purgatory/arch/alpha/Makefile + include $(srcdir)/purgatory/arch/arm/Makefile ++include $(srcdir)/purgatory/arch/arm64/Makefile + include $(srcdir)/purgatory/arch/i386/Makefile + include $(srcdir)/purgatory/arch/ia64/Makefile + include $(srcdir)/purgatory/arch/mips/Makefile +diff --git a/purgatory/arch/arm64/Makefile b/purgatory/arch/arm64/Makefile +new file mode 100644 +index 000000000000..636abeab17b2 +--- /dev/null ++++ b/purgatory/arch/arm64/Makefile +@@ -0,0 +1,18 @@ ++ ++arm64_PURGATORY_EXTRA_CFLAGS = \ ++ -mcmodel=large \ ++ -fno-stack-protector \ ++ -fno-asynchronous-unwind-tables \ ++ -Wundef \ ++ -Werror-implicit-function-declaration \ ++ -Wdeclaration-after-statement \ ++ -Werror=implicit-int \ ++ -Werror=strict-prototypes ++ ++arm64_PURGATORY_SRCS += \ ++ purgatory/arch/arm64/entry.S \ ++ purgatory/arch/arm64/purgatory-arm64.c ++ ++dist += \ ++ $(arm64_PURGATORY_SRCS) \ ++ purgatory/arch/arm64/Makefile +diff --git a/purgatory/arch/arm64/entry.S b/purgatory/arch/arm64/entry.S +new file mode 100644 +index 000000000000..140e91d87ab1 +--- /dev/null ++++ b/purgatory/arch/arm64/entry.S +@@ -0,0 +1,54 @@ ++/* ++ * ARM64 purgatory. ++ */ ++ ++.macro debug_brk ++ mov x0, #0x18; /* angel_SWIreason_ReportException */ ++ mov x1, #0x20000; ++ add x1, x1, #0x20; /* ADP_Stopped_BreakPoint */ ++ hlt #0xf000 /* A64 semihosting */ ++.endm ++ ++.macro size, sym:req ++ .size \sym, . - \sym ++.endm ++ ++.text ++ ++.globl purgatory_start ++purgatory_start: ++ ++ adr x19, .Lstack ++ mov sp, x19 ++ ++ bl purgatory ++ ++1: debug_brk ++ b 1b ++ ++size purgatory_start ++ ++.align 4 ++ .rept 256 ++ .quad 0 ++ .endr ++.Lstack: ++ ++.data ++ ++.align 3 ++ ++.globl arm64_sink ++arm64_sink: ++ .quad 0 ++size arm64_sink ++ ++.globl arm64_kernel_entry ++arm64_kernel_entry: ++ .quad 0 ++size arm64_kernel_entry ++ ++.globl arm64_dtb_addr ++arm64_dtb_addr: ++ .quad 0 ++size arm64_dtb_addr +diff --git a/purgatory/arch/arm64/purgatory-arm64.c b/purgatory/arch/arm64/purgatory-arm64.c +new file mode 100644 +index 000000000000..25960c30bd05 +--- /dev/null ++++ b/purgatory/arch/arm64/purgatory-arm64.c +@@ -0,0 +1,35 @@ ++/* ++ * ARM64 purgatory. ++ */ ++ ++#include ++#include ++ ++/* Symbols set by kexec. */ ++ ++extern uint32_t *arm64_sink; ++extern void (*arm64_kernel_entry)(uint64_t); ++extern uint64_t arm64_dtb_addr; ++ ++void putchar(int ch) ++{ ++ if (!arm64_sink) ++ return; ++ ++ *arm64_sink = ch; ++ ++ if (ch == '\n') ++ *arm64_sink = '\r'; ++} ++ ++void setup_arch(void) ++{ ++ printf("purgatory: kernel_entry: %lx\n", ++ (unsigned long)arm64_kernel_entry); ++ printf("purgatory: dtb: %lx\n", arm64_dtb_addr); ++} ++ ++void post_verification_setup_arch(void) ++{ ++ arm64_kernel_entry(arm64_dtb_addr); ++} +-- +2.1.0 + diff --git a/SOURCES/kexec-tools-2.0.8-arm64-Add-enable-disable-d-cache-support-for-purgato.patch b/SOURCES/kexec-tools-2.0.8-arm64-Add-enable-disable-d-cache-support-for-purgato.patch new file mode 100644 index 0000000..9a65476 --- /dev/null +++ b/SOURCES/kexec-tools-2.0.8-arm64-Add-enable-disable-d-cache-support-for-purgato.patch @@ -0,0 +1,309 @@ +From 8b40614f4c1925fe94f274dfc69d1a63537fe399 Mon Sep 17 00:00:00 2001 +Message-Id: <8b40614f4c1925fe94f274dfc69d1a63537fe399.1430751022.git.panand@redhat.com> +From: Pratyush Anand +Date: Mon, 4 May 2015 17:43:25 +0530 +Subject: [PATCH 1/3] arm64: Add enable/disable d-cache support for purgatory + +This patch adds support to enable/disable d-cache, which can be used for +faster purgatory sha256 verification. + +Signed-off-by: Pratyush Anand +--- + purgatory/arch/arm64/Makefile | 1 + + purgatory/arch/arm64/cache.S | 222 ++++++++++++++++++++++++++++++++++++++++++ + purgatory/arch/arm64/cache.h | 42 ++++++++ + 3 files changed, 265 insertions(+) + create mode 100644 purgatory/arch/arm64/cache.S + create mode 100644 purgatory/arch/arm64/cache.h + +diff --git a/purgatory/arch/arm64/Makefile b/purgatory/arch/arm64/Makefile +index 5d35161fc5f4..04fef16476fb 100644 +--- a/purgatory/arch/arm64/Makefile ++++ b/purgatory/arch/arm64/Makefile +@@ -12,6 +12,7 @@ arm64_PURGATORY_EXTRA_CFLAGS = \ + + arm64_PURGATORY_SRCS += \ + purgatory/arch/arm64/entry.S \ ++ purgatory/arch/arm64/cache.S \ + purgatory/arch/arm64/purgatory-arm64.c + + dist += \ +diff --git a/purgatory/arch/arm64/cache.S b/purgatory/arch/arm64/cache.S +new file mode 100644 +index 000000000000..6bbdeacdab47 +--- /dev/null ++++ b/purgatory/arch/arm64/cache.S +@@ -0,0 +1,222 @@ ++/* ++ * Cache maintenance ++ * Some of the routine has been copied from Linux Kernel, therefore ++ * copying the license as well. ++ * ++ * Copyright (C) 2001 Deep Blue Solutions Ltd. ++ * Copyright (C) 2012 ARM Ltd. ++ * Copyright (C) 2015 Pratyush Anand ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++#include "cache.h" ++ ++/* ++ * dcache_line_size - get the minimum D-cache line size from the CTR register. ++ */ ++ .macro dcache_line_size, reg, tmp ++ mrs \tmp, ctr_el0 // read CTR ++ ubfm \tmp, \tmp, #16, #19 // cache line size encoding ++ mov \reg, #4 // bytes per word ++ lsl \reg, \reg, \tmp // actual cache line size ++ .endm ++ ++/* ++ * __inval_cache_range(start, end) ++ * - start - start address of region ++ * - end - end address of region ++ */ ++__inval_cache_range: ++ dcache_line_size x2, x3 ++ sub x3, x2, #1 ++ tst x1, x3 // end cache line aligned? ++ bic x1, x1, x3 ++ b.eq 1f ++ dc civac, x1 // clean & invalidate D / U line ++1: tst x0, x3 // start cache line aligned? ++ bic x0, x0, x3 ++ b.eq 2f ++ dc civac, x0 // clean & invalidate D / U line ++ b 3f ++2: dc ivac, x0 // invalidate D / U line ++3: add x0, x0, x2 ++ cmp x0, x1 ++ b.lo 2b ++ dsb sy ++ ret ++/* ++ * __flush_dcache_range(start, end) ++ * - start - start address of region ++ * - end - end address of region ++ * ++ */ ++__flush_dcache_range: ++ dcache_line_size x2, x3 ++ sub x3, x2, #1 ++ bic x0, x0, x3 ++1: dc civac, x0 // clean & invalidate D line / unified line ++ add x0, x0, x2 ++ cmp x0, x1 ++ b.lo 1b ++ dsb sy ++ ret ++ ++/* ++ * enable_dcache(start, end, page_table) ++ * - start - start address of ram ++ * - end - end address of ram ++ * - page_table - base of page table ++ */ ++.globl enable_dcache ++enable_dcache: ++ stp x6, x7, [sp,#-16]! ++ stp x16, x17, [sp,#-16]! ++ stp x18, x19, [sp,#-16]! ++ ++ /* save args */ ++ mov x16, x0 /* first segment start */ ++ mov x17, x1 /* last segment end */ ++ mov x18, x2 /* page table */ ++ mov x19, x30 /* save ret addr */ ++ ++ /* ++ * Invalidate the page tables to avoid potential ++ * dirty cache lines being evicted. ++ */ ++ mov x0, x18 ++ add x1, x0, #PAGE_TABLE_SIZE ++ bl __inval_cache_range ++ ++ /* ++ * Clear the page tables. ++ */ ++ mov x0, x18 ++ add x1, x0, #PAGE_TABLE_SIZE ++1: stp xzr, xzr, [x0], #16 ++ stp xzr, xzr, [x0], #16 ++ stp xzr, xzr, [x0], #16 ++ stp xzr, xzr, [x0], #16 ++ cmp x0, x1 ++ b.lo 1b ++ ++ /* ++ * Create the identity mapping. ++ */ ++ ldr x6, =SECTION_SHIFT ++ ldr x7, =MM_MMUFLAGS ++ lsr x0, x16, x6 //first index ++ lsr x1, x17, x6 //last index ++ ++next_sect: ++ lsl x2, x0, x6 //section ++ orr x2, x2, x7 ++ str x2, [x18, x0, lsl #3] ++ add x0, x0, #1 ++ cmp x0, x1 ++ b.ls next_sect ++ ++ /* ++ * Since the page tables have been populated with non-cacheable ++ * accesses (MMU disabled), invalidate the idmap page ++ * tables again to remove any speculatively loaded cache lines. ++ */ ++ mov x0, x18 ++ add x1, x0, #PAGE_TABLE_SIZE ++ bl __inval_cache_range ++ ++ mrs x0, CurrentEL ++ cmp x0, #12 //EL3 ++ b.eq set_el3 ++ cmp x0, #8 //EL2 ++ b.eq set_el2 ++ cmp x0, #4 //EL1 ++ b.eq set_el1 ++ b done_enable ++ ++set_el1: ++ msr ttbr0_el1, x18 ++ ldr x0, =TCR_FLAGS ++ orr x0, x0, #TCR_EL1_IPS_BITS ++ msr tcr_el1, x0 ++ ldr x0, =MEMORY_ATTRIBUTES ++ msr mair_el1, x0 ++ mrs x0, sctlr_el1 ++ orr x0, x0, #CR_M ++ orr x0, x0, #CR_C ++ msr sctlr_el1, x0 ++ b done_enable ++set_el2: ++ msr ttbr0_el2, x18 ++ ldr x0, =TCR_FLAGS ++ orr x0, x0, #TCR_EL2_IPS_BITS ++ msr tcr_el2, x0 ++ ldr x0, =MEMORY_ATTRIBUTES ++ msr mair_el2, x0 ++ mrs x0, sctlr_el2 ++ orr x0, x0, #CR_M ++ orr x0, x0, #CR_C ++ msr sctlr_el2, x0 ++ b done_enable ++set_el3: ++ msr ttbr0_el3, x18 ++ ldr x0, =TCR_FLAGS ++ orr x0, x0, #TCR_EL3_IPS_BITS ++ msr tcr_el3, x0 ++ ldr x0, =MEMORY_ATTRIBUTES ++ msr mair_el3, x0 ++ mrs x0, sctlr_el3 ++ orr x0, x0, #CR_M ++ orr x0, x0, #CR_C ++ msr sctlr_el3, x0 ++done_enable: ++ ++ mov x30, x19 ++ ldp x18, x19, [sp],#16 ++ ldp x16, x17, [sp],#16 ++ ldp x6, x7, [sp],#16 ++ ++ ret ++ ++.globl disable_dcache ++disable_dcache: ++ stp x5, x30, [sp,#-16]! ++ mrs x5, CurrentEL ++ cmp x5, #12 //EL3 ++ b.eq disable_el3 ++ cmp x5, #8 //EL2 ++ b.eq disable_el2 ++ cmp x5, #4 //EL1 ++ b.eq disable_el1 ++ b done_disable ++disable_el3: ++ mrs x5, sctlr_el3 ++ bic x5, x2, #CR_M ++ bic x5, x2, #CR_C ++ msr sctlr_el3, x5 ++ b done_disable ++disable_el2: ++ mrs x5, sctlr_el2 ++ bic x5, x2, #CR_M ++ bic x5, x2, #CR_C ++ msr sctlr_el2, x5 ++ b done_disable ++disable_el1: ++ mrs x5, sctlr_el1 ++ bic x5, x2, #CR_M ++ bic x5, x2, #CR_C ++ msr sctlr_el1, x5 ++done_disable: ++ bl __flush_dcache_range ++ ldp x5, x30, [sp],#16 ++ ret +diff --git a/purgatory/arch/arm64/cache.h b/purgatory/arch/arm64/cache.h +new file mode 100644 +index 000000000000..3ca1d7f9a5ca +--- /dev/null ++++ b/purgatory/arch/arm64/cache.h +@@ -0,0 +1,42 @@ ++#ifndef __CACHE_H__ ++#define __CACHE_H__ ++ ++#define VA_BITS 42 ++#define SECTION_SHIFT 29 ++#define PAGE_TABLE_SIZE (1 << (VA_BITS - SECTION_SHIFT + 3)) ++ ++#define TCR_TG0_64K (1 << 14) ++#define TCR_SHARED_NON (0 << 12) ++#define TCR_ORGN_WBWA (1 << 10) ++#define TCR_IRGN_WBWA (1 << 8) ++#define TCR_T0SZ(x) ((64 - (x)) << 0) ++#define TCR_EL1_IPS_BITS (3 << 32) /* 42 bits physical address */ ++#define TCR_EL2_IPS_BITS (3 << 16) /* 42 bits physical address */ ++#define TCR_EL3_IPS_BITS (3 << 16) /* 42 bits physical address */ ++ ++#define TCR_FLAGS (TCR_TG0_64K | TCR_SHARED_NON | TCR_ORGN_WBWA | \ ++ TCR_IRGN_WBWA | TCR_T0SZ(VA_BITS)) ++ ++#define MT_DEVICE_NGNRNE 0 ++#define MT_DEVICE_NGNRE 1 ++#define MT_DEVICE_GRE 2 ++#define MT_NORMAL_NC 3 ++#define MT_NORMAL 4 ++ ++#define MEMORY_ATTRIBUTES ((0x00 << (MT_DEVICE_NGNRNE*8)) | \ ++ (0x04 << (MT_DEVICE_NGNRE*8)) | \ ++ (0x0c << (MT_DEVICE_GRE*8)) | \ ++ (0x44 << (MT_NORMAL_NC*8)) | \ ++ (0xff << (MT_NORMAL*8))) ++ ++#define CR_M (1 << 0) /* MMU enable */ ++#define CR_C (1 << 2) /* Dcache enable */ ++ ++ ++#define PMD_TYPE_SECT (1 << 0) ++#define PMD_SECT_AF (1 << 10) ++#define PMD_ATTRINDX(t) ((t) << 2) ++#define PMD_FLAGS (PMD_TYPE_SECT | PMD_SECT_AF) ++#define MM_MMUFLAGS PMD_ATTRINDX(MT_NORMAL) | PMD_FLAGS ++ ++#endif +-- +2.1.0 + diff --git a/SOURCES/kexec-tools-2.0.8-arm64-Add-support-for-kexec-lite-option.patch b/SOURCES/kexec-tools-2.0.8-arm64-Add-support-for-kexec-lite-option.patch new file mode 100644 index 0000000..04baeb6 --- /dev/null +++ b/SOURCES/kexec-tools-2.0.8-arm64-Add-support-for-kexec-lite-option.patch @@ -0,0 +1,58 @@ +From d665fa8c7cb6fa6713bad2633b9cccbad98245bc Mon Sep 17 00:00:00 2001 +Message-Id: +In-Reply-To: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com> +References: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com> +From: Geoff Levand +Date: Fri, 17 Apr 2015 10:54:55 -0700 +Subject: [PATCH 04/17] arm64: Add support for kexec --lite option + +WARNING: This implementation uses kernel feature not yet merged upstream. In +the future I may convert this to use a minimal purgatory that is just a +trampoline. +--- + kexec/arch/arm64/include/arch/options.h | 2 +- + kexec/arch/arm64/kexec-arm64.c | 8 +++----- + 2 files changed, 4 insertions(+), 6 deletions(-) + +diff --git a/kexec/arch/arm64/include/arch/options.h b/kexec/arch/arm64/include/arch/options.h +index 903b4a1fbd7f..afe3e9827ff3 100644 +--- a/kexec/arch/arm64/include/arch/options.h ++++ b/kexec/arch/arm64/include/arch/options.h +@@ -29,7 +29,7 @@ static const char arm64_opts_usage[] __attribute__ ((unused)) = + " --command-line=STRING Set the kernel command line to STRING.\n" + " --dtb=FILE Use FILE as the device tree blob.\n" + " --initrd=FILE Use FILE as the kernel initial ramdisk.\n" +-" --lite Fast reboot, no memory integrity checks - currently NOT SUPPORTED.\n"); ++" --lite Fast reboot, no memory integrity checks.\n" + " --port=ADDRESS Purgatory output to port ADDRESS.\n" + " --ramdisk=FILE Use FILE as the kernel initial ramdisk.\n" + " --reuse-cmdline Use command line arg of primary kernel.\n"; +diff --git a/kexec/arch/arm64/kexec-arm64.c b/kexec/arch/arm64/kexec-arm64.c +index 22d70244f8db..6398e55fe575 100644 +--- a/kexec/arch/arm64/kexec-arm64.c ++++ b/kexec/arch/arm64/kexec-arm64.c +@@ -96,7 +96,6 @@ int arch_process_options(int argc, char **argv) + break; + case OPT_LITE: + arm64_opts.lite = 1; +- fprintf(stderr, "kexec: --lite option currently NOT SUPPORTED.\n"); + break; + case OPT_PORT: + arm64_opts.port = strtoull(optarg, NULL, 0); +@@ -702,10 +701,9 @@ int arm64_load_other_segments(struct kexec_info *info, + add_segment_phys_virt(info, initrd_buf, initrd_size, + initrd_base, initrd_size, 0); + +- if (arm64_opts.lite) { +- fprintf(stderr, "kexec: --lite option currently NOT SUPPORTED.\n"); +- return -ENOSYS; +- } else { ++ if (arm64_opts.lite) ++ info->entry = (void *)kernel_entry; ++ else { + result = build_elf_rel_info(purgatory, purgatory_size, &ehdr, + 0); + +-- +2.1.0 + diff --git a/SOURCES/kexec-tools-2.0.8-arm64-Add-support-for-reuse-cmdline-option.patch b/SOURCES/kexec-tools-2.0.8-arm64-Add-support-for-reuse-cmdline-option.patch new file mode 100644 index 0000000..52ba3c3 --- /dev/null +++ b/SOURCES/kexec-tools-2.0.8-arm64-Add-support-for-reuse-cmdline-option.patch @@ -0,0 +1,82 @@ +From 0730d377b6a6f6cdac25f26016a95db8a9333802 Mon Sep 17 00:00:00 2001 +Message-Id: <0730d377b6a6f6cdac25f26016a95db8a9333802.1431592766.git.panand@redhat.com> +In-Reply-To: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com> +References: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com> +From: Pratyush Anand +Date: Fri, 17 Apr 2015 10:54:55 -0700 +Subject: [PATCH 03/17] arm64: Add support for --reuse-cmdline option + +Signed-off-by: Pratyush Anand +Signed-off-by: Geoff Levand +--- + kexec/arch/arm64/include/arch/options.h | 7 +++++-- + kexec/arch/arm64/kexec-arm64.c | 8 +++++++- + 2 files changed, 12 insertions(+), 3 deletions(-) + +diff --git a/kexec/arch/arm64/include/arch/options.h b/kexec/arch/arm64/include/arch/options.h +index 51afc5f1f6f2..903b4a1fbd7f 100644 +--- a/kexec/arch/arm64/include/arch/options.h ++++ b/kexec/arch/arm64/include/arch/options.h +@@ -6,7 +6,8 @@ + #define OPT_INITRD ((OPT_MAX)+2) + #define OPT_LITE ((OPT_MAX)+3) + #define OPT_PORT ((OPT_MAX)+4) +-#define OPT_ARCH_MAX ((OPT_MAX)+5) ++#define OPT_REUSE_CMDLINE ((OPT_MAX+5)) ++#define OPT_ARCH_MAX ((OPT_MAX)+6) + + #define KEXEC_ARCH_OPTIONS \ + KEXEC_OPTIONS \ +@@ -17,6 +18,7 @@ + { "lite", 0, NULL, OPT_LITE }, \ + { "port", 1, NULL, OPT_PORT }, \ + { "ramdisk", 1, NULL, OPT_INITRD }, \ ++ { "reuse-cmdline", 0, NULL, OPT_REUSE_CMDLINE }, \ + + #define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR /* Only accept long arch options. */ + #define KEXEC_ALL_OPTIONS KEXEC_ARCH_OPTIONS +@@ -29,7 +31,8 @@ static const char arm64_opts_usage[] __attribute__ ((unused)) = + " --initrd=FILE Use FILE as the kernel initial ramdisk.\n" + " --lite Fast reboot, no memory integrity checks - currently NOT SUPPORTED.\n"); + " --port=ADDRESS Purgatory output to port ADDRESS.\n" +-" --ramdisk=FILE Use FILE as the kernel initial ramdisk.\n"; ++" --ramdisk=FILE Use FILE as the kernel initial ramdisk.\n" ++" --reuse-cmdline Use command line arg of primary kernel.\n"; + + struct arm64_opts { + const char *command_line; +diff --git a/kexec/arch/arm64/kexec-arm64.c b/kexec/arch/arm64/kexec-arm64.c +index 0860810b6e86..22d70244f8db 100644 +--- a/kexec/arch/arm64/kexec-arm64.c ++++ b/kexec/arch/arm64/kexec-arm64.c +@@ -75,13 +75,18 @@ int arch_process_options(int argc, char **argv) + { 0 } + }; + int opt; ++ const char *append = NULL; ++ char *tmp_cmdline = NULL; + + for (opt = 0; opt != -1; ) { + opt = getopt_long(argc, argv, short_options, options, 0); + + switch (opt) { + case OPT_APPEND: +- arm64_opts.command_line = optarg; ++ append = optarg; ++ break; ++ case OPT_REUSE_CMDLINE: ++ tmp_cmdline = get_command_line(); + break; + case OPT_DTB: + arm64_opts.dtb = optarg; +@@ -101,6 +106,7 @@ int arch_process_options(int argc, char **argv) + } + } + ++ arm64_opts.command_line = concat_cmdline(tmp_cmdline, append); + kexec_debug = 1; // FIXME: for debugging only. + + dbgprintf("%s:%d: command_line: %s\n", __func__, __LINE__, +-- +2.1.0 + diff --git a/SOURCES/kexec-tools-2.0.8-arm64-Enable-disable-D-cache-before-after-sha-verifi.patch b/SOURCES/kexec-tools-2.0.8-arm64-Enable-disable-D-cache-before-after-sha-verifi.patch new file mode 100644 index 0000000..e21d5ae --- /dev/null +++ b/SOURCES/kexec-tools-2.0.8-arm64-Enable-disable-D-cache-before-after-sha-verifi.patch @@ -0,0 +1,70 @@ +From 2939844d0211a820cf22a8d666df90af889ec6f1 Mon Sep 17 00:00:00 2001 +Message-Id: <2939844d0211a820cf22a8d666df90af889ec6f1.1430751022.git.panand@redhat.com> +In-Reply-To: <8b40614f4c1925fe94f274dfc69d1a63537fe399.1430751022.git.panand@redhat.com> +References: <8b40614f4c1925fe94f274dfc69d1a63537fe399.1430751022.git.panand@redhat.com> +From: Pratyush Anand +Date: Mon, 4 May 2015 17:50:21 +0530 +Subject: [PATCH 3/3] arm64: Enable/disable D-cache before/after sha + verification + +Enable D cache before SHA verification and disable it before switching +to kernel. + +Since we only map RAM area, therefore currently no printf is allowed +between d-cache enable and disable events. Identity mapping for port +area with device type memory attributes need to be created for printf to +work. + +Signed-off-by: Pratyush Anand +--- + purgatory/arch/arm64/purgatory-arm64.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/purgatory/arch/arm64/purgatory-arm64.c b/purgatory/arch/arm64/purgatory-arm64.c +index 3a1c9243bfa2..e045039039b6 100644 +--- a/purgatory/arch/arm64/purgatory-arm64.c ++++ b/purgatory/arch/arm64/purgatory-arm64.c +@@ -2,6 +2,7 @@ + * ARM64 purgatory. + */ + ++#include "cache.h" + #include + #include + +@@ -10,6 +11,8 @@ + extern uint32_t *arm64_sink; + extern void (*arm64_kernel_entry)(uint64_t); + extern uint64_t arm64_dtb_addr; ++extern uint64_t arm64_ram_start; ++extern uint64_t arm64_ram_end; + + static void wait_for_xmit_complete(void) + { +@@ -44,14 +47,23 @@ void putchar(int ch) + } + } + ++uint64_t page_table[PAGE_TABLE_SIZE / sizeof(uint64_t)] __attribute__ ((aligned (PAGE_TABLE_SIZE))) = { }; ++extern void enable_dcache(uint64_t , uint64_t , uint64_t *); ++extern void disable_dcache(uint64_t , uint64_t); ++ + void setup_arch(void) + { + printf("purgatory: kernel_entry: %lx\n", + (unsigned long)arm64_kernel_entry); + printf("purgatory: dtb: %lx\n", arm64_dtb_addr); ++ printf("purgatory: RAM start: %lx\n", arm64_ram_start); ++ printf("purgatory: RAM end: %lx\n", arm64_ram_end); ++ ++ enable_dcache(arm64_ram_start, arm64_ram_end, page_table); + } + + void post_verification_setup_arch(void) + { ++ disable_dcache(arm64_ram_start, arm64_ram_end); + arm64_kernel_entry(arm64_dtb_addr); + } +-- +2.1.0 + diff --git a/SOURCES/kexec-tools-2.0.8-arm64-Kexec-Add-support-for-binary-image.patch b/SOURCES/kexec-tools-2.0.8-arm64-Kexec-Add-support-for-binary-image.patch new file mode 100644 index 0000000..1461967 --- /dev/null +++ b/SOURCES/kexec-tools-2.0.8-arm64-Kexec-Add-support-for-binary-image.patch @@ -0,0 +1,201 @@ +From 6dd781cca908aea5f282b5c980d806c2f35ea171 Mon Sep 17 00:00:00 2001 +Message-Id: <6dd781cca908aea5f282b5c980d806c2f35ea171.1431592766.git.panand@redhat.com> +In-Reply-To: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com> +References: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com> +From: Pratyush Anand +Date: Mon, 13 Apr 2015 17:19:49 +0530 +Subject: [PATCH 05/17] arm64: Kexec: Add support for binary image + +This patch adds support to use binary image ie arch/arm64/boot/Image. + +Binary image does not have sufficient knowledge to extract page offset +information, which is needed by kexec tool. Use a new command parameter +--page-offset, so that user can provide page offset information for +linear mapping. + +Signed-off-by: Pratyush Anand +--- + kexec/arch/arm64/include/arch/options.h | 9 ++-- + kexec/arch/arm64/kexec-arm64.c | 3 ++ + kexec/arch/arm64/kexec-arm64.h | 2 + + kexec/arch/arm64/kexec-image-arm64.c | 86 +++++++++++++++++++++++++++++++-- + 4 files changed, 93 insertions(+), 7 deletions(-) + +diff --git a/kexec/arch/arm64/include/arch/options.h b/kexec/arch/arm64/include/arch/options.h +index afe3e9827ff3..fa4ad2c68642 100644 +--- a/kexec/arch/arm64/include/arch/options.h ++++ b/kexec/arch/arm64/include/arch/options.h +@@ -5,9 +5,10 @@ + #define OPT_DTB ((OPT_MAX)+1) + #define OPT_INITRD ((OPT_MAX)+2) + #define OPT_LITE ((OPT_MAX)+3) +-#define OPT_PORT ((OPT_MAX)+4) +-#define OPT_REUSE_CMDLINE ((OPT_MAX+5)) +-#define OPT_ARCH_MAX ((OPT_MAX)+6) ++#define OPT_PAGE_OFFSET ((OPT_MAX)+4) ++#define OPT_PORT ((OPT_MAX)+5) ++#define OPT_REUSE_CMDLINE ((OPT_MAX+6)) ++#define OPT_ARCH_MAX ((OPT_MAX)+7) + + #define KEXEC_ARCH_OPTIONS \ + KEXEC_OPTIONS \ +@@ -16,6 +17,7 @@ + { "dtb", 1, NULL, OPT_DTB }, \ + { "initrd", 1, NULL, OPT_INITRD }, \ + { "lite", 0, NULL, OPT_LITE }, \ ++ { "page-offset", 1, NULL, OPT_PAGE_OFFSET }, \ + { "port", 1, NULL, OPT_PORT }, \ + { "ramdisk", 1, NULL, OPT_INITRD }, \ + { "reuse-cmdline", 0, NULL, OPT_REUSE_CMDLINE }, \ +@@ -38,6 +40,7 @@ struct arm64_opts { + const char *command_line; + const char *dtb; + const char *initrd; ++ uint64_t page_offset; + uint64_t port; + int lite; + }; +diff --git a/kexec/arch/arm64/kexec-arm64.c b/kexec/arch/arm64/kexec-arm64.c +index 6398e55fe575..86408598a465 100644 +--- a/kexec/arch/arm64/kexec-arm64.c ++++ b/kexec/arch/arm64/kexec-arm64.c +@@ -100,6 +100,9 @@ int arch_process_options(int argc, char **argv) + case OPT_PORT: + arm64_opts.port = strtoull(optarg, NULL, 0); + break; ++ case OPT_PAGE_OFFSET: ++ arm64_opts.page_offset = strtoull(optarg, NULL, 0); ++ break; + default: + break; /* Ignore core and unknown options. */ + } +diff --git a/kexec/arch/arm64/kexec-arm64.h b/kexec/arch/arm64/kexec-arm64.h +index 057acf313b49..7f0ca13fec11 100644 +--- a/kexec/arch/arm64/kexec-arm64.h ++++ b/kexec/arch/arm64/kexec-arm64.h +@@ -17,6 +17,8 @@ + #define BOOT_BLOCK_LAST_COMP_VERSION 16 + #define COMMAND_LINE_SIZE 512 + ++#define ARM64_DEFAULT_PAGE_OFFSET 0xfffffe0000000000 ++ + int elf_arm64_probe(const char *kernel_buf, off_t kernel_size); + int elf_arm64_load(int argc, char **argv, const char *kernel_buf, + off_t kernel_size, struct kexec_info *info); +diff --git a/kexec/arch/arm64/kexec-image-arm64.c b/kexec/arch/arm64/kexec-image-arm64.c +index b025dc6c0185..c577b96d5e31 100644 +--- a/kexec/arch/arm64/kexec-image-arm64.c ++++ b/kexec/arch/arm64/kexec-image-arm64.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + + #include "dt-ops.h" + #include "image-header.h" +@@ -31,20 +32,97 @@ int image_arm64_probe(const char *kernel_buf, off_t kernel_size) + dbgprintf("%s: PE format: %s\n", __func__, + (arm64_header_check_pe_sig(h) ? "yes" : "no")); + +- fprintf(stderr, "kexec: arm64 binary Image files are currently NOT SUPPORTED.\n"); ++ return 0; ++} ++ ++static unsigned long long get_kernel_text_sym(void) ++{ ++ const char *kallsyms = "/proc/kallsyms"; ++ const char *text = "_text"; ++ char sym[128]; ++ char line[128]; ++ FILE *fp; ++ unsigned long long vaddr; ++ char type; + +- return -1; ++ fp = fopen(kallsyms, "r"); if (!fp) { ++ fprintf(stderr, "Cannot open %s\n", kallsyms); ++ return 0; ++ } ++ ++ while(fgets(line, sizeof(line), fp) != NULL) { ++ if (sscanf(line, "%Lx %c %s", &vaddr, &type, sym) != 3) ++ continue; ++ if (strcmp(sym, text) == 0) { ++ dbgprintf("kernel symbol %s vaddr = %16llx\n", text, vaddr); ++ return vaddr; ++ } ++ } ++ ++ fprintf(stderr, "Cannot get kernel %s symbol address\n", text); ++ return 0; ++} ++ ++static unsigned long long get_kernel_page_offset(void) ++{ ++ unsigned long long text_sym_addr = get_kernel_text_sym(); ++ unsigned long long text_page_offset = ++ text_sym_addr & 0xFFFFFFFFFFE00000; ++ ++ if(arm64_opts.page_offset) { ++ if (text_page_offset != arm64_opts.page_offset) ++ dbgprintf("User page offset %lx did not match with text page offset %llx\n", ++ arm64_opts.page_offset, text_page_offset); ++ return arm64_opts.page_offset; ++ } else if(text_page_offset) { ++ dbgprintf("text page offset is %llx\n", text_page_offset); ++ return text_page_offset; ++ } else { ++ return ARM64_DEFAULT_PAGE_OFFSET; ++ } + } + + int image_arm64_load(int argc, char **argv, const char *kernel_buf, + off_t kernel_size, struct kexec_info *info) + { +- return -ENOSYS; ++ int result; ++ uint64_t start; ++ const struct arm64_image_header *h; ++ char *header_option = NULL; ++ ++ h = (const struct arm64_image_header *)(kernel_buf); ++ ++ arm64_mem.text_offset = le64_to_cpu(h->text_offset); ++ arm64_mem.image_size = le64_to_cpu(h->image_size); ++ ++ arm64_mem.page_offset = get_kernel_page_offset(); ++ ++ result = parse_iomem_single("Kernel code\n", &start, NULL); ++ ++ if (result) { ++ fprintf(stderr, "kexec: Could not get kernel code address.\n"); ++ return -1; ++ } ++ start -= arm64_mem.text_offset; ++ ++ /* Add kernel */ ++ add_segment_phys_virt(info, kernel_buf, kernel_size, ++ start + arm64_mem.text_offset, ++ kernel_size, 0); ++ ++ info->entry = (void *)start + arm64_mem.text_offset; ++ ++ result = arm64_load_other_segments(info, (unsigned long)info->entry); ++ ++ if (header_option) ++ free(header_option); ++ ++ return result; + } + + void image_arm64_usage(void) + { + printf( + " An arm64 binary Image file, big or little endian.\n" +-" This file type is currently NOT SUPPORTED.\n\n"); ++" --page-offset Kernel page-offset for binary image load.\n"); + } +-- +2.1.0 + diff --git a/SOURCES/kexec-tools-2.0.8-arm64-Pass-RAM-boundary-to-purgatory.patch b/SOURCES/kexec-tools-2.0.8-arm64-Pass-RAM-boundary-to-purgatory.patch new file mode 100644 index 0000000..424beaa --- /dev/null +++ b/SOURCES/kexec-tools-2.0.8-arm64-Pass-RAM-boundary-to-purgatory.patch @@ -0,0 +1,105 @@ +From 04a2b7bb55bfee0495cc39796846adf8d6a313bc Mon Sep 17 00:00:00 2001 +Message-Id: <04a2b7bb55bfee0495cc39796846adf8d6a313bc.1430751022.git.panand@redhat.com> +In-Reply-To: <8b40614f4c1925fe94f274dfc69d1a63537fe399.1430751022.git.panand@redhat.com> +References: <8b40614f4c1925fe94f274dfc69d1a63537fe399.1430751022.git.panand@redhat.com> +From: Pratyush Anand +Date: Mon, 4 May 2015 17:47:14 +0530 +Subject: [PATCH 2/3] arm64: Pass RAM boundary to purgatory + +RAM boundary which includes all the sections is needed for creating +identity page mapping and to enable d-cache for those areas. + +Signed-off-by: Pratyush Anand +--- + kexec/arch/arm64/include/types.h | 16 ++++++++++++++++ + kexec/arch/arm64/kexec-arm64.c | 16 +++++++++++++++- + purgatory/arch/arm64/entry.S | 10 ++++++++++ + 3 files changed, 41 insertions(+), 1 deletion(-) + create mode 100644 kexec/arch/arm64/include/types.h + +diff --git a/kexec/arch/arm64/include/types.h b/kexec/arch/arm64/include/types.h +new file mode 100644 +index 000000000000..08f833a6d585 +--- /dev/null ++++ b/kexec/arch/arm64/include/types.h +@@ -0,0 +1,16 @@ ++#ifndef _TYPES_H_ ++#define _TYPES_H_ ++ ++#define min(x,y) ({ \ ++ typeof(x) _x = (x); \ ++ typeof(y) _y = (y); \ ++ (void) (&_x == &_y); \ ++ _x < _y ? _x : _y; }) ++ ++#define max(x,y) ({ \ ++ typeof(x) _x = (x); \ ++ typeof(y) _y = (y); \ ++ (void) (&_x == &_y); \ ++ _x > _y ? _x : _y; }) ++ ++#endif /* _TYPES_H_ */ +diff --git a/kexec/arch/arm64/kexec-arm64.c b/kexec/arch/arm64/kexec-arm64.c +index 12c589f8001c..8ce4a61fc9c2 100644 +--- a/kexec/arch/arm64/kexec-arm64.c ++++ b/kexec/arch/arm64/kexec-arm64.c +@@ -28,6 +28,7 @@ + #include "fs2dt.h" + #include "kexec-syscall.h" + #include "arch/options.h" ++#include "types.h" + + /* Global varables the core kexec routines expect. */ + +@@ -588,9 +589,11 @@ static uint64_t read_sink(const char *command_line) + int arm64_load_other_segments(struct kexec_info *info, + unsigned long kernel_entry, char *option) + { +- int result; ++ int result, i; + struct mem_ehdr ehdr; + unsigned long dtb_base; ++ unsigned long arm64_ram_start = -1; ++ unsigned long arm64_ram_end = 0; + unsigned long hole_min, hole_max; + char *initrd_buf = NULL; + uint64_t purgatory_sink; +@@ -720,6 +723,17 @@ int arm64_load_other_segments(struct kexec_info *info, + + elf_rel_set_symbol(&info->rhdr, "arm64_dtb_addr", &dtb_base, + sizeof(dtb_base)); ++ for (i = 0; i < info->nr_segments; i++) { ++ arm64_ram_start = min(arm64_ram_start, ++ (unsigned long)info->segment[i].mem); ++ arm64_ram_end = max(arm64_ram_end, ++ ((unsigned long)info->segment[i].mem + ++ info->segment[i].memsz)); ++ } ++ elf_rel_set_symbol(&info->rhdr, "arm64_ram_start", ++ &arm64_ram_start, sizeof(arm64_ram_start)); ++ elf_rel_set_symbol(&info->rhdr, "arm64_ram_end", ++ &arm64_ram_end, sizeof(arm64_ram_end)); + } + + return 0; +diff --git a/purgatory/arch/arm64/entry.S b/purgatory/arch/arm64/entry.S +index 140e91d87ab1..0713ccdec4ad 100644 +--- a/purgatory/arch/arm64/entry.S ++++ b/purgatory/arch/arm64/entry.S +@@ -52,3 +52,13 @@ size arm64_kernel_entry + arm64_dtb_addr: + .quad 0 + size arm64_dtb_addr ++ ++.globl arm64_ram_start ++arm64_ram_start: ++ .quad 0 ++size arm64_ram_start ++ ++.globl arm64_ram_end ++arm64_ram_end: ++ .quad 0 ++size arm64_ram_end +-- +2.1.0 + diff --git a/SOURCES/kexec-tools-2.0.8-arm64-clean-up-on-crash-dump.patch b/SOURCES/kexec-tools-2.0.8-arm64-clean-up-on-crash-dump.patch new file mode 100644 index 0000000..c2af525 --- /dev/null +++ b/SOURCES/kexec-tools-2.0.8-arm64-clean-up-on-crash-dump.patch @@ -0,0 +1,98 @@ +From 359dec003b758e4d950de965f76ecaf6d81c007d Mon Sep 17 00:00:00 2001 +Message-Id: <359dec003b758e4d950de965f76ecaf6d81c007d.1431592766.git.panand@redhat.com> +In-Reply-To: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com> +References: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com> +From: AKASHI Takahiro +Date: Wed, 22 Apr 2015 11:20:27 +0900 +Subject: [PATCH 12/17] arm64: clean up on crash dump + +--- + kexec/arch/arm64/crashdump-arm64.c | 12 +++--------- + kexec/arch/arm64/crashdump-arm64.h | 6 +++--- + kexec/arch/arm64/kexec-elf-arm64.c | 9 +++++---- + 3 files changed, 11 insertions(+), 16 deletions(-) + +diff --git a/kexec/arch/arm64/crashdump-arm64.c b/kexec/arch/arm64/crashdump-arm64.c +index 04958418ae82..a929b9e3ecb1 100644 +--- a/kexec/arch/arm64/crashdump-arm64.c ++++ b/kexec/arch/arm64/crashdump-arm64.c +@@ -288,7 +288,7 @@ int load_crashdump_segments(struct kexec_info *info, char **option) + return 0; + } + +-void modify_ehdr_for_crashmem(struct mem_ehdr *ehdr) ++void modify_ehdr_for_crashdump(struct mem_ehdr *ehdr) + { + struct mem_phdr *phdr; + int i; +@@ -304,13 +304,7 @@ void modify_ehdr_for_crashmem(struct mem_ehdr *ehdr) + } + } + +-void set_crash_entry(struct mem_ehdr *ehdr, struct kexec_info *info) ++void *get_crash_entry(void) + { +- info->entry = (void *)crash_reserved_mem.start + arm64_mem.text_offset; +-} +- +-off_t locate_dtb_in_crashmem(struct kexec_info *info, off_t dtb_size) +-{ +- return locate_hole(info, dtb_size, 128UL * 1024, +- crash_reserved_mem.start, crash_reserved_mem.end, -1); ++ return (void *)crash_reserved_mem.start + arm64_mem.text_offset; + } +diff --git a/kexec/arch/arm64/crashdump-arm64.h b/kexec/arch/arm64/crashdump-arm64.h +index d4fd3f2288c9..6457ea7cabec 100644 +--- a/kexec/arch/arm64/crashdump-arm64.h ++++ b/kexec/arch/arm64/crashdump-arm64.h +@@ -17,10 +17,10 @@ + #define CRASH_MAX_MEMORY_RANGES 32 + + extern struct memory_ranges usablemem_rgns; ++extern struct memory_range crash_reserved_mem; + + int load_crashdump_segments(struct kexec_info *info, char **option); +-void modify_ehdr_for_crashmem(struct mem_ehdr *ehdr); +-void set_crash_entry(struct mem_ehdr *ehdr, struct kexec_info *info); +-off_t locate_dtb_in_crashmem(struct kexec_info *info, off_t dtb_size); ++void modify_ehdr_for_crashdump(struct mem_ehdr *ehdr); ++void *get_crash_entry(void); + + #endif +diff --git a/kexec/arch/arm64/kexec-elf-arm64.c b/kexec/arch/arm64/kexec-elf-arm64.c +index f5ecda825278..9fda5e539471 100644 +--- a/kexec/arch/arm64/kexec-elf-arm64.c ++++ b/kexec/arch/arm64/kexec-elf-arm64.c +@@ -93,16 +93,17 @@ int elf_arm64_load(int argc, char **argv, const char *kernel_buf, + } + + if (info->kexec_flags & KEXEC_ON_CRASH) { ++ /* allocate and initialize elf core header */ + result = load_crashdump_segments(info, &header_option); + + if (result) { + fprintf(stderr, "kexec: creating eflcorehdr failed.\n"); + goto exit; + } +- } + +- if (info->kexec_flags & KEXEC_ON_CRASH) +- modify_ehdr_for_crashmem(&ehdr); ++ /* offset addresses to load vmlinux(elf_exec) in crash memory */ ++ modify_ehdr_for_crashdump(&ehdr); ++ } + + result = elf_exec_load(&ehdr, info); + +@@ -112,7 +113,7 @@ int elf_arm64_load(int argc, char **argv, const char *kernel_buf, + } + + if (info->kexec_flags & KEXEC_ON_CRASH) +- set_crash_entry(&ehdr, info); ++ info->entry = get_crash_entry(); + else + info->entry = (void *)virt_to_phys(ehdr.e_entry); + +-- +2.1.0 + diff --git a/SOURCES/kexec-tools-2.0.8-arm64-fix-elf-related-header-issues.patch b/SOURCES/kexec-tools-2.0.8-arm64-fix-elf-related-header-issues.patch new file mode 100644 index 0000000..0fadd22 --- /dev/null +++ b/SOURCES/kexec-tools-2.0.8-arm64-fix-elf-related-header-issues.patch @@ -0,0 +1,71 @@ +From edac28173d05a547ad20442991ffd7708eba10bb Mon Sep 17 00:00:00 2001 +Message-Id: +In-Reply-To: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com> +References: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com> +From: AKASHI Takahiro +Date: Tue, 17 Feb 2015 15:53:07 +0900 +Subject: [PATCH 07/17] arm64: fix elf-related header issues + +- add a missing EM_AARCH64 macro +- linux/elf.h was also replaced with elf.h because they are conflicting + each other. +--- + include/elf.h | 1 + + kexec/arch/arm64/kexec-arm64.c | 3 +-- + kexec/arch/arm64/kexec-elf-arm64.c | 3 +-- + 3 files changed, 3 insertions(+), 4 deletions(-) + +diff --git a/include/elf.h b/include/elf.h +index 5db637ba2f60..cd2802ae1091 100644 +--- a/include/elf.h ++++ b/include/elf.h +@@ -259,6 +259,7 @@ typedef struct + #define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ + #define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ + #define EM_NUM 95 ++#define EM_AARCH64 183 /* ARMv8-A */ + + /* If it is necessary to assign new unofficial EM_* values, please + pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the +diff --git a/kexec/arch/arm64/kexec-arm64.c b/kexec/arch/arm64/kexec-arm64.c +index 86408598a465..eb68b6b3d9e3 100644 +--- a/kexec/arch/arm64/kexec-arm64.c ++++ b/kexec/arch/arm64/kexec-arm64.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -19,8 +20,6 @@ + + #include + +-#include +- + #include "dt-ops.h" + #include "kexec.h" + #include "crashdump.h" +diff --git a/kexec/arch/arm64/kexec-elf-arm64.c b/kexec/arch/arm64/kexec-elf-arm64.c +index 13dc5e2724d9..8b336054a6ab 100644 +--- a/kexec/arch/arm64/kexec-elf-arm64.c ++++ b/kexec/arch/arm64/kexec-elf-arm64.c +@@ -5,12 +5,11 @@ + #define _GNU_SOURCE + + #include ++#include + #include + #include + #include + +-#include +- + #include "dt-ops.h" + #include "crashdump-arm64.h" + #include "kexec-arm64.h" +-- +2.1.0 + diff --git a/SOURCES/kexec-tools-2.0.8-arm64-kdump-Add-support-for-binary-image.patch b/SOURCES/kexec-tools-2.0.8-arm64-kdump-Add-support-for-binary-image.patch new file mode 100644 index 0000000..8eb064b --- /dev/null +++ b/SOURCES/kexec-tools-2.0.8-arm64-kdump-Add-support-for-binary-image.patch @@ -0,0 +1,70 @@ +From 249821e20306fbafff9094a4e02c82b189ea0676 Mon Sep 17 00:00:00 2001 +Message-Id: <249821e20306fbafff9094a4e02c82b189ea0676.1431592766.git.panand@redhat.com> +In-Reply-To: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com> +References: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com> +From: Pratyush Anand +Date: Tue, 21 Apr 2015 18:23:38 +0530 +Subject: [PATCH 14/17] arm64: kdump: Add support for binary image + +This patch adds support to use binary image ie arch/arm64/boot/Image +with kdump. + +Signed-off-by: Pratyush Anand +--- + kexec/arch/arm64/kexec-image-arm64.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/kexec/arch/arm64/kexec-image-arm64.c b/kexec/arch/arm64/kexec-image-arm64.c +index c577b96d5e31..6f8a6590639a 100644 +--- a/kexec/arch/arm64/kexec-image-arm64.c ++++ b/kexec/arch/arm64/kexec-image-arm64.c +@@ -10,6 +10,7 @@ + #include + #include + ++#include "crashdump-arm64.h" + #include "dt-ops.h" + #include "image-header.h" + #include "kexec-arm64.h" +@@ -97,13 +98,23 @@ int image_arm64_load(int argc, char **argv, const char *kernel_buf, + + arm64_mem.page_offset = get_kernel_page_offset(); + +- result = parse_iomem_single("Kernel code\n", &start, NULL); ++ if (info->kexec_flags & KEXEC_ON_CRASH) { ++ result = load_crashdump_segments(info, &header_option); + +- if (result) { +- fprintf(stderr, "kexec: Could not get kernel code address.\n"); +- return -1; ++ if (result) { ++ fprintf(stderr, "kexec: load crashdump segments failed.\n"); ++ return -1; ++ } ++ start = crash_reserved_mem.start; ++ } else { ++ result = parse_iomem_single("Kernel code\n", &start, NULL); ++ ++ if (result) { ++ fprintf(stderr, "kexec: Could not get kernel code address.\n"); ++ return -1; ++ } ++ start -= arm64_mem.text_offset; + } +- start -= arm64_mem.text_offset; + + /* Add kernel */ + add_segment_phys_virt(info, kernel_buf, kernel_size, +@@ -112,7 +123,8 @@ int image_arm64_load(int argc, char **argv, const char *kernel_buf, + + info->entry = (void *)start + arm64_mem.text_offset; + +- result = arm64_load_other_segments(info, (unsigned long)info->entry); ++ result = arm64_load_other_segments(info, (unsigned long)info->entry, ++ header_option); + + if (header_option) + free(header_option); +-- +2.1.0 + diff --git a/SOURCES/kexec-tools-2.0.8-arm64-kdump-append-kdump-specific-parameter-to-comma.patch b/SOURCES/kexec-tools-2.0.8-arm64-kdump-append-kdump-specific-parameter-to-comma.patch new file mode 100644 index 0000000..a1b5609 --- /dev/null +++ b/SOURCES/kexec-tools-2.0.8-arm64-kdump-append-kdump-specific-parameter-to-comma.patch @@ -0,0 +1,78 @@ +From dd86e7cedfc0509df5dd7f824611d59cf7e9f007 Mon Sep 17 00:00:00 2001 +Message-Id: +In-Reply-To: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com> +References: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com> +From: AKASHI Takahiro +Date: Tue, 24 Feb 2015 16:46:35 +0900 +Subject: [PATCH 09/17] arm64: kdump: append kdump-specific parameter to + command line + +--- + kexec/arch/arm64/kexec-arm64.c | 9 +++++++-- + kexec/arch/arm64/kexec-arm64.h | 2 +- + kexec/arch/arm64/kexec-elf-arm64.c | 3 ++- + 3 files changed, 10 insertions(+), 4 deletions(-) + +diff --git a/kexec/arch/arm64/kexec-arm64.c b/kexec/arch/arm64/kexec-arm64.c +index e83e83bdd6db..173631c66951 100644 +--- a/kexec/arch/arm64/kexec-arm64.c ++++ b/kexec/arch/arm64/kexec-arm64.c +@@ -586,7 +586,7 @@ static uint64_t read_sink(const char *command_line) + */ + + int arm64_load_other_segments(struct kexec_info *info, +- unsigned long kernel_entry) ++ unsigned long kernel_entry, char *option) + { + int result; + struct mem_ehdr ehdr; +@@ -599,14 +599,19 @@ int arm64_load_other_segments(struct kexec_info *info, + struct dtb dtb_2 = {.name = "dtb_2"}; + char command_line[COMMAND_LINE_SIZE] = ""; + ++ dbgprintf("%s:%d: add '%s' to command line\n", __func__, __LINE__, ++ option); ++ + if (arm64_opts.command_line) { + strncpy(command_line, arm64_opts.command_line, + sizeof(command_line)); + command_line[sizeof(command_line) - 1] = 0; + } + +- purgatory_sink = read_sink(command_line); ++ if (option && option[0]) ++ strcat(command_line, option); + ++ purgatory_sink = read_sink(command_line); + dbgprintf("%s:%d: purgatory sink: 0x%" PRIx64 "\n", __func__, __LINE__, + purgatory_sink); + +diff --git a/kexec/arch/arm64/kexec-arm64.h b/kexec/arch/arm64/kexec-arm64.h +index 7f0ca13fec11..7e4d0568bd01 100644 +--- a/kexec/arch/arm64/kexec-arm64.h ++++ b/kexec/arch/arm64/kexec-arm64.h +@@ -48,6 +48,6 @@ extern struct arm64_mem arm64_mem; + + int arm64_process_image_header(const struct arm64_image_header *h); + int arm64_load_other_segments(struct kexec_info *info, +- unsigned long kernel_entry); ++ unsigned long kernel_entry, char *option); + + #endif +diff --git a/kexec/arch/arm64/kexec-elf-arm64.c b/kexec/arch/arm64/kexec-elf-arm64.c +index 903602985eb4..f5ecda825278 100644 +--- a/kexec/arch/arm64/kexec-elf-arm64.c ++++ b/kexec/arch/arm64/kexec-elf-arm64.c +@@ -123,7 +123,8 @@ int elf_arm64_load(int argc, char **argv, const char *kernel_buf, + dbgprintf("%s: e_entry: %016llx -> %016lx\n", __func__, + ehdr.e_entry, virt_to_phys(ehdr.e_entry)); + +- result = arm64_load_other_segments(info, (unsigned long)info->entry); ++ result = arm64_load_other_segments(info, (unsigned long)info->entry, ++ header_option); + exit: + free_elf_info(&ehdr); + if (header_option) +-- +2.1.0 + diff --git a/SOURCES/kexec-tools-2.0.8-arm64-kdump-copy-dtb-file-into-crash-kernel-memory.patch b/SOURCES/kexec-tools-2.0.8-arm64-kdump-copy-dtb-file-into-crash-kernel-memory.patch new file mode 100644 index 0000000..516aa71 --- /dev/null +++ b/SOURCES/kexec-tools-2.0.8-arm64-kdump-copy-dtb-file-into-crash-kernel-memory.patch @@ -0,0 +1,68 @@ +From 55cd3491542a0d696451611a4cae38db78f964dd Mon Sep 17 00:00:00 2001 +Message-Id: <55cd3491542a0d696451611a4cae38db78f964dd.1431592766.git.panand@redhat.com> +In-Reply-To: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com> +References: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com> +From: AKASHI Takahiro +Date: Tue, 24 Feb 2015 15:48:29 +0900 +Subject: [PATCH 10/17] arm64: kdump: copy dtb file into crash kernel memory + +--- + kexec/arch/arm64/crashdump-arm64.c | 6 ++++++ + kexec/arch/arm64/crashdump-arm64.h | 1 + + kexec/arch/arm64/kexec-arm64.c | 15 +++++++++------ + 3 files changed, 16 insertions(+), 6 deletions(-) + +diff --git a/kexec/arch/arm64/crashdump-arm64.c b/kexec/arch/arm64/crashdump-arm64.c +index ec83cf0c0f38..80f5985c5d85 100644 +--- a/kexec/arch/arm64/crashdump-arm64.c ++++ b/kexec/arch/arm64/crashdump-arm64.c +@@ -306,3 +306,9 @@ void set_crash_entry(struct mem_ehdr *ehdr, struct kexec_info *info) + { + info->entry = (void *)crash_reserved_mem.start + arm64_mem.text_offset; + } ++ ++off_t locate_dtb_in_crashmem(struct kexec_info *info, off_t dtb_size) ++{ ++ return locate_hole(info, dtb_size, 128UL * 1024, ++ crash_reserved_mem.start, crash_reserved_mem.end, -1); ++} +diff --git a/kexec/arch/arm64/crashdump-arm64.h b/kexec/arch/arm64/crashdump-arm64.h +index 3f8b38350841..d4fd3f2288c9 100644 +--- a/kexec/arch/arm64/crashdump-arm64.h ++++ b/kexec/arch/arm64/crashdump-arm64.h +@@ -21,5 +21,6 @@ extern struct memory_ranges usablemem_rgns; + int load_crashdump_segments(struct kexec_info *info, char **option); + void modify_ehdr_for_crashmem(struct mem_ehdr *ehdr); + void set_crash_entry(struct mem_ehdr *ehdr, struct kexec_info *info); ++off_t locate_dtb_in_crashmem(struct kexec_info *info, off_t dtb_size); + + #endif +diff --git a/kexec/arch/arm64/kexec-arm64.c b/kexec/arch/arm64/kexec-arm64.c +index 173631c66951..190037c75186 100644 +--- a/kexec/arch/arm64/kexec-arm64.c ++++ b/kexec/arch/arm64/kexec-arm64.c +@@ -650,12 +650,15 @@ int arm64_load_other_segments(struct kexec_info *info, + + dtb_max = dtb_2.size + 2 * 1024; + +- dtb_base = locate_hole(info, dtb_max, 128UL * 1024, +- arm64_mem.memstart + arm64_mem.text_offset +- + arm64_mem.image_size, +- _ALIGN_UP(arm64_mem.memstart + arm64_mem.text_offset, +- 512UL * 1024 * 1024), +- 1); ++ if (info->kexec_flags & KEXEC_ON_CRASH) ++ dtb_base = locate_dtb_in_crashmem(info, dtb_max); ++ else ++ dtb_base = locate_hole(info, dtb_max, 128UL * 1024, ++ arm64_mem.memstart + arm64_mem.text_offset ++ + arm64_mem.image_size, ++ _ALIGN_UP(arm64_mem.memstart + arm64_mem.text_offset, ++ 512UL * 1024 * 1024), ++ 1); + + dbgprintf("dtb: base %lx, size %lxh (%ld)\n", dtb_base, dtb_2.size, + dtb_2.size); +-- +2.1.0 + diff --git a/SOURCES/kexec-tools-2.0.8-arm64-kdump-create-elf-core-header.patch b/SOURCES/kexec-tools-2.0.8-arm64-kdump-create-elf-core-header.patch new file mode 100644 index 0000000..31d3dbe --- /dev/null +++ b/SOURCES/kexec-tools-2.0.8-arm64-kdump-create-elf-core-header.patch @@ -0,0 +1,468 @@ +From 9cd9f0ab98ce6ddbdbb9a045ed2887e0dd857afe Mon Sep 17 00:00:00 2001 +Message-Id: <9cd9f0ab98ce6ddbdbb9a045ed2887e0dd857afe.1431592766.git.panand@redhat.com> +In-Reply-To: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com> +References: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com> +From: AKASHI Takahiro +Date: Tue, 17 Feb 2015 16:06:55 +0900 +Subject: [PATCH 08/17] arm64: kdump: create elf core header + +--- + kexec/arch/arm64/crashdump-arm64.c | 295 ++++++++++++++++++++++++++++++++++++- + kexec/arch/arm64/crashdump-arm64.h | 17 ++- + kexec/arch/arm64/kexec-arm64.c | 4 +- + kexec/arch/arm64/kexec-elf-arm64.c | 31 +++- + 4 files changed, 332 insertions(+), 15 deletions(-) + +diff --git a/kexec/arch/arm64/crashdump-arm64.c b/kexec/arch/arm64/crashdump-arm64.c +index d2272c8124d0..ec83cf0c0f38 100644 +--- a/kexec/arch/arm64/crashdump-arm64.c ++++ b/kexec/arch/arm64/crashdump-arm64.c +@@ -1,11 +1,28 @@ + /* +- * ARM64 crashdump. ++ * crashdump for arm64 ++ * ++ * Copyright (C) Nokia Corporation, 2010. ++ * Author: Mika Westerberg ++ * ++ * Based on x86 implementation ++ * Copyright (C) IBM Corporation, 2005. All rights reserved ++ * ++ * Copyright (c) 2014 Linaro Limited ++ * Author: AKASHI Takahiro ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. + */ + +-#define _GNU_SOURCE ++#define _GNU_SOURCE /* for asprintf */ + ++#include ++#include + #include +-#include ++#include ++#include ++#include + + #include "kexec.h" + #include "crashdump.h" +@@ -13,9 +30,279 @@ + #include "kexec-arm64.h" + #include "kexec-elf.h" + +-struct memory_ranges usablemem_rgns = {}; ++ ++/* ++ * Used to save various memory ranges/regions needed for the captured ++ * kernel to boot. (like memmap= option in other archs) ++ */ ++static struct memory_range crash_memory_ranges[CRASH_MAX_MEMORY_RANGES]; ++struct memory_ranges crashmem_rgns = { ++ .size = 0, ++ .ranges = crash_memory_ranges, ++}; ++ ++/* memory range reserved for crashkernel */ ++struct memory_range crash_reserved_mem; ++struct memory_ranges usablemem_rgns = { ++ .size = 0, ++ .ranges = &crash_reserved_mem, ++}; ++ ++static struct crash_elf_info elf_info = { ++ .class = ELFCLASS64, ++#if (__BYTE_ORDER == __LITTLE_ENDIAN) ++ .data = ELFDATA2LSB, ++#else ++ .data = ELFDATA2MSB, ++#endif ++ .machine = EM_AARCH64, ++}; + + int is_crashkernel_mem_reserved(void) + { ++ uint64_t start, end; ++ ++ if (parse_iomem_single("Crash kernel\n", &start, &end) == 0) ++ return start != end; ++ ++ return 0; ++} ++ ++/* ++ * crash_range_callback() - callback called for each iomem region ++ * @data: not used ++ * @nr: not used ++ * @str: name of the memory region ++ * @base: start address of the memory region ++ * @length: size of the memory region ++ * ++ * This function is called once for each memory region found in /proc/iomem. ++ * It locates system RAM and crashkernel reserved memory and places these to ++ * variables: @crash_memory_ranges and @crash_reserved_mem. Number of memory ++ * regions is placed in @crash_memory_nr_ranges. ++ */ ++ ++static int crash_range_callback(void *UNUSED(data), int UNUSED(nr), ++ char *str, unsigned long long base, ++ unsigned long long length) ++{ ++ struct memory_range *range; ++ ++ assert(arm64_mem.memstart); ++ ++ if (crashmem_rgns.size >= CRASH_MAX_MEMORY_RANGES) ++ return 1; ++ ++ range = crashmem_rgns.ranges + crashmem_rgns.size; ++ ++ if (strncmp(str, "System RAM\n", 11) == 0) { ++ range->start = base; ++ range->end = base + length - 1; ++ range->type = RANGE_RAM; ++ crashmem_rgns.size++; ++ } else if (strncmp(str, "Crash kernel\n", 13) == 0) { ++ if (base < arm64_mem.memstart) ++ base += arm64_mem.memstart; ++ crash_reserved_mem.start = base; ++ crash_reserved_mem.end = base + length - 1; ++ crash_reserved_mem.type = RANGE_RAM; ++ usablemem_rgns.size++; ++ } ++ ++ return 0; ++} ++ ++/* ++ * crash_exclude_range() - excludes memory region reserved for crashkernel ++ * ++ * Function locates where crashkernel reserved memory is and removes that ++ * region from the available memory regions. ++ */ ++static void crash_exclude_range(void) ++{ ++ const struct memory_range *range = &crash_reserved_mem; ++ int i; ++ ++ for (i = 0; i < crashmem_rgns.size; i++) { ++ struct memory_range *r = crashmem_rgns.ranges + i; ++ ++ /* ++ * We assume that crash area is fully contained in ++ * some larger memory area. ++ */ ++ if (r->start <= range->start && r->end >= range->end) { ++ struct memory_range *new; ++ ++ if (r->start == range->start) { ++ if (r->end == range->end) { ++ memcpy(r, r + 1, ++ sizeof(r) ++ * (crashmem_rgns.size - i - 1)); ++ crashmem_rgns.size--; ++ } else { ++ r->start = range->end + 1; ++ } ++ break; ++ } ++ if (r->end == range->end) { ++ r->end = range->start - 1; ++ break; ++ } ++ ++ /* ++ * Let's split this area into 2 smaller ones and ++ * remove excluded range from between. First create ++ * new entry for the remaining area. ++ */ ++ new = crashmem_rgns.ranges + crashmem_rgns.size; ++ new->start = range->end + 1; ++ new->end = r->end; ++ crashmem_rgns.size++; ++ /* ++ * Next update this area to end before excluded range. ++ */ ++ r->end = range->start - 1; ++ break; ++ } ++ } ++} ++ ++/* ++ * crash_get_memory_ranges() - read system physical memory ++ * ++ * Function reads through system physical memory and stores found memory ++ * regions in @crash_memory_ranges. Number of memory regions found is placed ++ * in @crash_memory_nr_ranges. Regions are sorted in ascending order. ++ * ++ * Returns %0 in case of success and %-1 otherwise (errno is set). ++ */ ++static int crash_get_memory_ranges(void) ++{ ++ /* ++ * First read all memory regions that can be considered as ++ * system memory including the crash area. ++ */ ++ kexec_iomem_for_each_line(NULL, crash_range_callback, NULL); ++ ++ if (usablemem_rgns.size != 1) { ++ errno = EINVAL; ++ return -1; ++ } ++ ++ /* ++ * Exclude memory reserved for crashkernel (this may result int ++ * split memory regions). ++ */ ++ /* ++ * FIXME: ++ * Do we have to check crashkernel is within main memory? ++ */ ++ crash_exclude_range(); ++ ++ return 0; ++} ++ ++/* ++ * range_size - Return range size in MiB. ++ */ ++ ++static unsigned long range_size(const struct memory_range *r) ++{ ++ return (r->end - r->start + 1) >> 20; ++} ++ ++static void dump_crash_ranges(void) ++{ ++ int i; ++ ++ if (!kexec_debug) ++ return; ++ ++ dbgprintf("%s: kernel: %016llx - %016llx (%ld MiB)\n", __func__, ++ crash_reserved_mem.start, crash_reserved_mem.end, ++ range_size(&crash_reserved_mem)); ++ ++ for (i = 0; i < crashmem_rgns.size; i++) { ++ struct memory_range *r = crashmem_rgns.ranges + i; ++ dbgprintf("%s: RAM: %016llx - %016llx (%ld MiB)\n", __func__, ++ r->start, r->end, range_size(r)); ++ } ++} ++ ++/* ++ * load_crashdump_segments() - create elf core header for /proc/vmcore ++ * @info: kexec info structure ++ * @option: To be appended to kernel command line ++ * ++ * This function loads additional segments which are needed for the dump ++ * capture kernel. It also updates kernel command line passed in ++ * @command_line_extra to have the correct parameters for the dump capture ++ * kernel. ++ * ++ * Return %0 in case of success and %-1 in case of error. ++ */ ++ ++int load_crashdump_segments(struct kexec_info *info, char **option) ++{ ++ unsigned long elfcorehdr; ++ unsigned long bufsz; ++ void *buf; ++ int err; ++ ++ /* ++ * First fetch all the memory (RAM) ranges that we are going to ++ * pass to the crashdump kernel during panic. ++ */ ++ ++ err = crash_get_memory_ranges(); ++ ++ if (err) ++ return err; ++ ++ dump_crash_ranges(); ++ ++ elf_info.page_offset = arm64_mem.page_offset; ++ ++ err = crash_create_elf64_headers(info, &elf_info, crashmem_rgns.ranges, ++ crashmem_rgns.size, &buf, &bufsz, ELF_CORE_HEADER_ALIGN); ++ ++ if (err) ++ return err; ++ ++ /* ++ * FIXME: check if we need 128KB alignment here as stated in arm. ++ */ ++ elfcorehdr = add_buffer_phys_virt(info, buf, bufsz, bufsz, 0, ++ crash_reserved_mem.start, crash_reserved_mem.end, ++ -1, 0); ++ ++ err = asprintf(option, " elfcorehdr=%#lx@%#lx", bufsz, elfcorehdr); ++ ++ if (err == -1) ++ return err; ++ ++ dbgprintf("%s:%s\n", __func__, *option); ++ + return 0; + } ++ ++void modify_ehdr_for_crashmem(struct mem_ehdr *ehdr) ++{ ++ struct mem_phdr *phdr; ++ int i; ++ ++ ehdr->e_entry += crash_reserved_mem.start; ++ ++ for (i = 0; i < ehdr->e_phnum; i++) { ++ phdr = &ehdr->e_phdr[i]; ++ if (phdr->p_type != PT_LOAD) ++ continue; ++ phdr->p_paddr += ++ (-arm64_mem.memstart + crash_reserved_mem.start); ++ } ++} ++ ++void set_crash_entry(struct mem_ehdr *ehdr, struct kexec_info *info) ++{ ++ info->entry = (void *)crash_reserved_mem.start + arm64_mem.text_offset; ++} +diff --git a/kexec/arch/arm64/crashdump-arm64.h b/kexec/arch/arm64/crashdump-arm64.h +index f33c7a25b454..3f8b38350841 100644 +--- a/kexec/arch/arm64/crashdump-arm64.h ++++ b/kexec/arch/arm64/crashdump-arm64.h +@@ -1,12 +1,25 @@ + /* +- * ARM64 crashdump. ++ * crashdump for arm64 ++ * ++ * Copyright (c) 2014 Linaro Limited ++ * Author: AKASHI Takahiro ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. + */ + +-#if !defined(CRASHDUMP_ARM64_H) ++#ifndef CRASHDUMP_ARM64_H + #define CRASHDUMP_ARM64_H + + #include "kexec.h" + ++#define CRASH_MAX_MEMORY_RANGES 32 ++ + extern struct memory_ranges usablemem_rgns; + ++int load_crashdump_segments(struct kexec_info *info, char **option); ++void modify_ehdr_for_crashmem(struct mem_ehdr *ehdr); ++void set_crash_entry(struct mem_ehdr *ehdr, struct kexec_info *info); ++ + #endif +diff --git a/kexec/arch/arm64/kexec-arm64.c b/kexec/arch/arm64/kexec-arm64.c +index eb68b6b3d9e3..e83e83bdd6db 100644 +--- a/kexec/arch/arm64/kexec-arm64.c ++++ b/kexec/arch/arm64/kexec-arm64.c +@@ -758,7 +758,7 @@ unsigned long phys_to_virt(struct crash_elf_info *UNUSED(elf_info), + v = p - arm64_mem.memstart + arm64_mem.page_offset; + + dbgprintf("%s: %016lx -> %016lx\n", __func__, p, v); +- return p; ++ return v; + } + + void add_segment(struct kexec_info *info, const void *buf, size_t bufsz, +@@ -924,7 +924,7 @@ static int get_memory_ranges_iomem(struct memory_range *array, + + r.type = RANGE_RAM; + +- dbgprintf("%s:%d: RAM: %016llx - %016llx : %s", __func__, ++ dbgprintf("%s:%d: RAM: %016llx - %016llx : %s", __func__, + __LINE__, r.start, r.end, str); + + array[(*count)++] = r; +diff --git a/kexec/arch/arm64/kexec-elf-arm64.c b/kexec/arch/arm64/kexec-elf-arm64.c +index 8b336054a6ab..903602985eb4 100644 +--- a/kexec/arch/arm64/kexec-elf-arm64.c ++++ b/kexec/arch/arm64/kexec-elf-arm64.c +@@ -9,9 +9,10 @@ + #include + #include + #include ++#include + +-#include "dt-ops.h" + #include "crashdump-arm64.h" ++#include "dt-ops.h" + #include "kexec-arm64.h" + #include "fs2dt.h" + #include "kexec-syscall.h" +@@ -45,16 +46,13 @@ on_exit: + int elf_arm64_load(int argc, char **argv, const char *kernel_buf, + off_t kernel_size, struct kexec_info *info) + { ++ char *header_option = NULL; + int result; + struct mem_ehdr ehdr; + bool found_header; + int i; + +- if (info->kexec_flags & KEXEC_ON_CRASH) { +- fprintf(stderr, "kexec: kdump not yet supported on arm64\n"); +- return -EINVAL; +- } +- ++ /* Parse the Elf file */ + result = build_elf_exec_info(kernel_buf, kernel_size, &ehdr, 0); + + if (result < 0) { +@@ -94,6 +92,18 @@ int elf_arm64_load(int argc, char **argv, const char *kernel_buf, + goto exit; + } + ++ if (info->kexec_flags & KEXEC_ON_CRASH) { ++ result = load_crashdump_segments(info, &header_option); ++ ++ if (result) { ++ fprintf(stderr, "kexec: creating eflcorehdr failed.\n"); ++ goto exit; ++ } ++ } ++ ++ if (info->kexec_flags & KEXEC_ON_CRASH) ++ modify_ehdr_for_crashmem(&ehdr); ++ + result = elf_exec_load(&ehdr, info); + + if (result) { +@@ -101,6 +111,11 @@ int elf_arm64_load(int argc, char **argv, const char *kernel_buf, + goto exit; + } + ++ if (info->kexec_flags & KEXEC_ON_CRASH) ++ set_crash_entry(&ehdr, info); ++ else ++ info->entry = (void *)virt_to_phys(ehdr.e_entry); ++ + dbgprintf("%s: text_offset: %016lx\n", __func__, arm64_mem.text_offset); + dbgprintf("%s: image_size: %016lx\n", __func__, arm64_mem.image_size); + dbgprintf("%s: page_offset: %016lx\n", __func__, arm64_mem.page_offset); +@@ -108,9 +123,11 @@ int elf_arm64_load(int argc, char **argv, const char *kernel_buf, + dbgprintf("%s: e_entry: %016llx -> %016lx\n", __func__, + ehdr.e_entry, virt_to_phys(ehdr.e_entry)); + +- result = arm64_load_other_segments(info, virt_to_phys(ehdr.e_entry)); ++ result = arm64_load_other_segments(info, (unsigned long)info->entry); + exit: + free_elf_info(&ehdr); ++ if (header_option) ++ free(header_option); + return result; + } + +-- +2.1.0 + diff --git a/SOURCES/kexec-tools-2.0.8-arm64-pass-mem-parameter-to-a-crash-dump-kernel.patch b/SOURCES/kexec-tools-2.0.8-arm64-pass-mem-parameter-to-a-crash-dump-kernel.patch new file mode 100644 index 0000000..b21731c --- /dev/null +++ b/SOURCES/kexec-tools-2.0.8-arm64-pass-mem-parameter-to-a-crash-dump-kernel.patch @@ -0,0 +1,30 @@ +From dbb9a351c5bd0c51b959a9ffc19859bee1b82008 Mon Sep 17 00:00:00 2001 +Message-Id: +In-Reply-To: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com> +References: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com> +From: AKASHI Takahiro +Date: Thu, 26 Mar 2015 19:13:44 +0900 +Subject: [PATCH 11/17] arm64: pass "mem=" parameter to a crash dump kernel + +--- + kexec/arch/arm64/crashdump-arm64.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/kexec/arch/arm64/crashdump-arm64.c b/kexec/arch/arm64/crashdump-arm64.c +index 80f5985c5d85..04958418ae82 100644 +--- a/kexec/arch/arm64/crashdump-arm64.c ++++ b/kexec/arch/arm64/crashdump-arm64.c +@@ -276,7 +276,9 @@ int load_crashdump_segments(struct kexec_info *info, char **option) + crash_reserved_mem.start, crash_reserved_mem.end, + -1, 0); + +- err = asprintf(option, " elfcorehdr=%#lx@%#lx", bufsz, elfcorehdr); ++ err = asprintf(option, " elfcorehdr=%#lx@%#lx mem=%#llx", ++ bufsz, elfcorehdr, ++ crash_reserved_mem.end - crash_reserved_mem.start + 1); + + if (err == -1) + return err; +-- +2.1.0 + diff --git a/SOURCES/kexec-tools-2.0.8-arm64-remove-restriction-on-the-segments-order.patch b/SOURCES/kexec-tools-2.0.8-arm64-remove-restriction-on-the-segments-order.patch new file mode 100644 index 0000000..0d850fe --- /dev/null +++ b/SOURCES/kexec-tools-2.0.8-arm64-remove-restriction-on-the-segments-order.patch @@ -0,0 +1,123 @@ +From 97905e5e71d417e8bbbfa3c42d559a464a1570da Mon Sep 17 00:00:00 2001 +Message-Id: <97905e5e71d417e8bbbfa3c42d559a464a1570da.1431592766.git.panand@redhat.com> +In-Reply-To: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com> +References: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com> +From: AKASHI Takahiro +Date: Wed, 22 Apr 2015 11:21:05 +0900 +Subject: [PATCH 13/17] arm64: remove restriction on the segments order + +Done by changing locate_hole() to add_buffer_phys_virt() in +load_other_segments() since locate_hole() assumes that the segments in +struct info be sorted properly. +This also simplifies the difference between kexec case and kdump case. +--- + kexec/arch/arm64/kexec-arm64.c | 57 +++++++++++++++--------------------------- + 1 file changed, 20 insertions(+), 37 deletions(-) + +diff --git a/kexec/arch/arm64/kexec-arm64.c b/kexec/arch/arm64/kexec-arm64.c +index 190037c75186..d884c7c1707d 100644 +--- a/kexec/arch/arm64/kexec-arm64.c ++++ b/kexec/arch/arm64/kexec-arm64.c +@@ -590,11 +590,10 @@ int arm64_load_other_segments(struct kexec_info *info, + { + int result; + struct mem_ehdr ehdr; +- unsigned long dtb_max; + unsigned long dtb_base; ++ unsigned long hole_min, hole_max; + char *initrd_buf = NULL; + uint64_t purgatory_sink; +- unsigned long purgatory_base; + struct dtb dtb_1 = {.name = "dtb_1"}; + struct dtb dtb_2 = {.name = "dtb_2"}; + char command_line[COMMAND_LINE_SIZE] = ""; +@@ -648,27 +647,15 @@ int arm64_load_other_segments(struct kexec_info *info, + * to the DTB size for any DTB growth. + */ + +- dtb_max = dtb_2.size + 2 * 1024; +- +- if (info->kexec_flags & KEXEC_ON_CRASH) +- dtb_base = locate_dtb_in_crashmem(info, dtb_max); +- else +- dtb_base = locate_hole(info, dtb_max, 128UL * 1024, +- arm64_mem.memstart + arm64_mem.text_offset +- + arm64_mem.image_size, +- _ALIGN_UP(arm64_mem.memstart + arm64_mem.text_offset, +- 512UL * 1024 * 1024), +- 1); +- +- dbgprintf("dtb: base %lx, size %lxh (%ld)\n", dtb_base, dtb_2.size, +- dtb_2.size); +- +- if (dtb_base == ULONG_MAX) +- return -ENOMEM; +- +- purgatory_base = dtb_base + dtb_2.size; +- initrd_base = 0; +- initrd_size = 0; ++ if (info->kexec_flags & KEXEC_ON_CRASH) { ++ hole_min = crash_reserved_mem.start + arm64_mem.text_offset ++ + arm64_mem.image_size; ++ hole_max = crash_reserved_mem.end; ++ } else { ++ hole_min = arm64_mem.memstart + arm64_mem.text_offset ++ + arm64_mem.image_size; ++ hole_max = ULONG_MAX; ++ } + + if (arm64_opts.initrd) { + initrd_buf = slurp_file(arm64_opts.initrd, &initrd_size); +@@ -679,8 +666,9 @@ int arm64_load_other_segments(struct kexec_info *info, + /* Put the initrd after the DTB with an alignment of + * page size. */ + +- initrd_base = locate_hole(info, initrd_size, 0, +- dtb_base + dtb_max, -1, 1); ++ initrd_base = add_buffer_phys_virt(info, initrd_buf, ++ initrd_size, initrd_size, 0, ++ hole_min, hole_max, 1, 0); + + dbgprintf("initrd: base %lx, size %lxh (%ld)\n", + initrd_base, initrd_size, initrd_size); +@@ -694,22 +682,17 @@ int arm64_load_other_segments(struct kexec_info *info, + + if (result) + return result; +- +- purgatory_base = initrd_base + initrd_size; + } + } + +- if (dtb_2.size > dtb_max) { +- fprintf(stderr, "%s: Error: Too many DTB mods.\n", __func__); +- return -EINVAL; +- } ++ dtb_base = add_buffer_phys_virt(info, dtb_2.buf, dtb_2.size, dtb_2.size, ++ 128UL * 1024, hole_min, hole_max, 1, 0); + +- add_segment_phys_virt(info, dtb_2.buf, dtb_2.size, dtb_base, +- dtb_2.size, 0); ++ dbgprintf("dtb: base %lx, size %lxh (%ld)\n", dtb_base, dtb_2.size, ++ dtb_2.size); + +- if (arm64_opts.initrd) +- add_segment_phys_virt(info, initrd_buf, initrd_size, +- initrd_base, initrd_size, 0); ++ if (dtb_base == ULONG_MAX) ++ return -ENOMEM; + + if (arm64_opts.lite) + info->entry = (void *)kernel_entry; +@@ -724,7 +707,7 @@ int arm64_load_other_segments(struct kexec_info *info, + } + + elf_rel_build_load(info, &info->rhdr, purgatory, purgatory_size, +- purgatory_base, ULONG_MAX, 1, 0); ++ hole_min, hole_max, 1, 0); + + info->entry = (void *)elf_rel_get_addr(&info->rhdr, + "purgatory_start"); +-- +2.1.0 + diff --git a/SOURCES/kexec-tools-2.0.8-arm64-wait-for-transmit-completion-before-next-chara.patch b/SOURCES/kexec-tools-2.0.8-arm64-wait-for-transmit-completion-before-next-chara.patch new file mode 100644 index 0000000..400a868 --- /dev/null +++ b/SOURCES/kexec-tools-2.0.8-arm64-wait-for-transmit-completion-before-next-chara.patch @@ -0,0 +1,64 @@ +From fc60d1ebadfba9a4344969507d8bd9de43c5c7e8 Mon Sep 17 00:00:00 2001 +Message-Id: +In-Reply-To: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com> +References: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com> +From: Pratyush Anand +Date: Thu, 16 Apr 2015 14:00:03 +0530 +Subject: [PATCH 15/17] arm64: wait for transmit completion before next + character transmission + +Previous transmission must be completed before next character to be +transmitted, otherwise TX buffer may saturate and we will not see all +the characters on screen. + +Signed-off-by: Pratyush Anand +--- + purgatory/arch/arm64/purgatory-arm64.c | 24 +++++++++++++++++++++++- + 1 file changed, 23 insertions(+), 1 deletion(-) + +diff --git a/purgatory/arch/arm64/purgatory-arm64.c b/purgatory/arch/arm64/purgatory-arm64.c +index 25960c30bd05..3a1c9243bfa2 100644 +--- a/purgatory/arch/arm64/purgatory-arm64.c ++++ b/purgatory/arch/arm64/purgatory-arm64.c +@@ -11,15 +11,37 @@ extern uint32_t *arm64_sink; + extern void (*arm64_kernel_entry)(uint64_t); + extern uint64_t arm64_dtb_addr; + ++static void wait_for_xmit_complete(void) ++{ ++ volatile uint32_t status; ++ volatile uint32_t *status_reg; ++ ++ /* ++ * Since most of the UART with ARM platform has LSR register at ++ * offset 0x14 and should have value as 0x60 for TX empty, so we ++ * have hardcoded these values. Can modify in future if need ++ * arises. ++ */ ++ status_reg = (volatile uint32_t *)((uint64_t)arm64_sink + 0x14); ++ while (1) { ++ status = *status_reg; ++ if ((status & 0x60) == 0x60) ++ break; ++ } ++} ++ + void putchar(int ch) + { + if (!arm64_sink) + return; + ++ wait_for_xmit_complete(); + *arm64_sink = ch; + +- if (ch == '\n') ++ if (ch == '\n') { ++ wait_for_xmit_complete(); + *arm64_sink = '\r'; ++ } + } + + void setup_arch(void) +-- +2.1.0 + diff --git a/SOURCES/kexec-tools-2.0.8-bugfix-calc-correct-end-address-of-memory-ranges-in-.patch b/SOURCES/kexec-tools-2.0.8-bugfix-calc-correct-end-address-of-memory-ranges-in-.patch new file mode 100644 index 0000000..b3d5ef6 --- /dev/null +++ b/SOURCES/kexec-tools-2.0.8-bugfix-calc-correct-end-address-of-memory-ranges-in-.patch @@ -0,0 +1,41 @@ +From 0ed5f4fb8dfd33bc52c8dbe15c61285d50c769b2 Mon Sep 17 00:00:00 2001 +Message-Id: <0ed5f4fb8dfd33bc52c8dbe15c61285d50c769b2.1431592766.git.panand@redhat.com> +In-Reply-To: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com> +References: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com> +From: AKASHI Takahiro +Date: Fri, 22 Aug 2014 13:48:52 +0900 +Subject: [PATCH 06/17] (bugfix) calc correct end address of memory ranges in + device tree + +The end address of "reg" attribute in device tree's memory should be +inclusive. +--- + kexec/fs2dt.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/kexec/fs2dt.c b/kexec/fs2dt.c +index 1e5f074da8b2..3ba217873f4f 100644 +--- a/kexec/fs2dt.c ++++ b/kexec/fs2dt.c +@@ -234,7 +234,8 @@ static void add_dyn_reconf_usable_mem_property__(int fd) + ranges_size*8); + } + ranges[rlen++] = cpu_to_be64(loc_base); +- ranges[rlen++] = cpu_to_be64(loc_end - loc_base); ++ ranges[rlen++] = cpu_to_be64(loc_end ++ - loc_base + 1); + rngs_cnt++; + } + } +@@ -348,7 +349,7 @@ static void add_usable_mem_property(int fd, size_t len) + ranges_size*sizeof(*ranges)); + } + ranges[rlen++] = cpu_to_be64(loc_base); +- ranges[rlen++] = cpu_to_be64(loc_end - loc_base); ++ ranges[rlen++] = cpu_to_be64(loc_end - loc_base + 1); + } + } + +-- +2.1.0 + diff --git a/SOURCES/kexec-tools-2.0.8-kexec-Add-common-device-tree-routines.patch b/SOURCES/kexec-tools-2.0.8-kexec-Add-common-device-tree-routines.patch new file mode 100644 index 0000000..b2630fc --- /dev/null +++ b/SOURCES/kexec-tools-2.0.8-kexec-Add-common-device-tree-routines.patch @@ -0,0 +1,194 @@ +From 1fb6841aa15407dbf371589d7abca7bc2d35815c Mon Sep 17 00:00:00 2001 +Message-Id: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com> +From: Geoff Levand +Date: Fri, 17 Apr 2015 10:54:55 -0700 +Subject: [PATCH 01/17] kexec: Add common device tree routines + +Signed-off-by: Geoff Levand +--- + kexec/Makefile | 4 ++ + kexec/dt-ops.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + kexec/dt-ops.h | 13 ++++++ + 3 files changed, 153 insertions(+) + create mode 100644 kexec/dt-ops.c + create mode 100644 kexec/dt-ops.h + +diff --git a/kexec/Makefile b/kexec/Makefile +index a758b4aae13a..6937a4dbb38b 100644 +--- a/kexec/Makefile ++++ b/kexec/Makefile +@@ -69,6 +69,10 @@ dist += kexec/fs2dt.c kexec/fs2dt.h + $(ARCH)_FS2DT = + KEXEC_SRCS += $($(ARCH)_FS2DT) + ++dist += kexec/dt-ops.c kexec/dt-ops.h ++$(ARCH)_DT_OPS = ++KEXEC_SRCS += $($(ARCH)_DT_OPS) ++ + include $(srcdir)/kexec/arch/alpha/Makefile + include $(srcdir)/kexec/arch/arm/Makefile + include $(srcdir)/kexec/arch/i386/Makefile +diff --git a/kexec/dt-ops.c b/kexec/dt-ops.c +new file mode 100644 +index 000000000000..bbba986cfbb4 +--- /dev/null ++++ b/kexec/dt-ops.c +@@ -0,0 +1,136 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "kexec.h" ++#include "dt-ops.h" ++ ++static const char n_chosen[] = "/chosen"; ++ ++static const char p_bootargs[] = "bootargs"; ++static const char p_initrd_start[] = "linux,initrd-start"; ++static const char p_initrd_end[] = "linux,initrd-end"; ++ ++int dtb_set_initrd(char **dtb, off_t *dtb_size, off_t start, off_t end) ++{ ++ int result; ++ uint64_t value; ++ ++ dbgprintf("%s: start %jd, end %jd, size %jd (%jd KiB)\n", ++ __func__, (intmax_t)start, (intmax_t)end, ++ (intmax_t)(end - start), ++ (intmax_t)(end - start) / 1024); ++ ++ value = cpu_to_fdt64(start); ++ ++ result = dtb_set_property(dtb, dtb_size, n_chosen, p_initrd_start, ++ &value, sizeof(value)); ++ ++ if (result) ++ return result; ++ ++ value = cpu_to_fdt64(end); ++ ++ result = dtb_set_property(dtb, dtb_size, n_chosen, p_initrd_end, ++ &value, sizeof(value)); ++ ++ if (result) { ++ dtb_delete_property(*dtb, n_chosen, p_initrd_start); ++ return result; ++ } ++ ++ return 0; ++} ++ ++int dtb_set_bootargs(char **dtb, off_t *dtb_size, const char *command_line) ++{ ++ return dtb_set_property(dtb, dtb_size, n_chosen, p_bootargs, ++ command_line, strlen(command_line) + 1); ++} ++ ++int dtb_set_property(char **dtb, off_t *dtb_size, const char *node, ++ const char *prop, const void *value, int value_len) ++{ ++ int result; ++ int nodeoffset; ++ void *new_dtb; ++ int new_size; ++ ++ value_len = FDT_TAGALIGN(value_len); ++ ++ new_size = FDT_TAGALIGN(*dtb_size + fdt_node_len(node) ++ + fdt_prop_len(prop, value_len)); ++ ++ new_dtb = malloc(new_size); ++ ++ if (!new_dtb) { ++ dbgprintf("%s: malloc failed\n", __func__); ++ return -ENOMEM; ++ } ++ ++ result = fdt_open_into(*dtb, new_dtb, new_size); ++ ++ if (result) { ++ dbgprintf("%s: fdt_open_into failed: %s\n", __func__, ++ fdt_strerror(result)); ++ goto on_error; ++ } ++ ++ nodeoffset = fdt_path_offset(new_dtb, node); ++ ++ if (nodeoffset == -FDT_ERR_NOTFOUND) { ++ result = fdt_add_subnode(new_dtb, nodeoffset, node); ++ ++ if (result) { ++ dbgprintf("%s: fdt_add_subnode failed: %s\n", __func__, ++ fdt_strerror(result)); ++ goto on_error; ++ } ++ } else if (nodeoffset < 0) { ++ dbgprintf("%s: fdt_path_offset failed: %s\n", __func__, ++ fdt_strerror(nodeoffset)); ++ goto on_error; ++ } ++ ++ result = fdt_setprop(new_dtb, nodeoffset, prop, value, value_len); ++ ++ if (result) { ++ dbgprintf("%s: fdt_setprop failed: %s\n", __func__, ++ fdt_strerror(result)); ++ goto on_error; ++ } ++ ++ free(*dtb); ++ ++ *dtb = new_dtb; ++ *dtb_size = new_size; ++ ++ return 0; ++ ++on_error: ++ free(new_dtb); ++ return result; ++} ++ ++int dtb_delete_property(char *dtb, const char *node, const char *prop) ++{ ++ int result; ++ int nodeoffset = fdt_path_offset(dtb, node); ++ ++ if (nodeoffset < 0) { ++ dbgprintf("%s: fdt_path_offset failed: %s\n", __func__, ++ fdt_strerror(nodeoffset)); ++ return nodeoffset; ++ } ++ ++ result = fdt_delprop(dtb, nodeoffset, prop); ++ ++ if (result) ++ dbgprintf("%s: fdt_delprop failed: %s\n", __func__, ++ fdt_strerror(nodeoffset)); ++ ++ return result; ++} +diff --git a/kexec/dt-ops.h b/kexec/dt-ops.h +new file mode 100644 +index 000000000000..e70d15d8ffbf +--- /dev/null ++++ b/kexec/dt-ops.h +@@ -0,0 +1,13 @@ ++#if !defined(KEXEC_DT_OPS_H) ++#define KEXEC_DT_OPS_H ++ ++#include ++ ++int dtb_set_initrd(char **dtb, off_t *dtb_size, off_t start, off_t end); ++int dtb_set_bootargs(char **dtb, off_t *dtb_size, const char *command_line); ++int dtb_set_property(char **dtb, off_t *dtb_size, const char *node, ++ const char *prop, const void *value, int value_len); ++ ++int dtb_delete_property(char *dtb, const char *node, const char *prop); ++ ++#endif +-- +2.1.0 + diff --git a/SOURCES/kexec-tools-2.0.8-makedumpfile-Add-module-of-calculating-start_pfn-and.patch b/SOURCES/kexec-tools-2.0.8-makedumpfile-Add-module-of-calculating-start_pfn-and.patch new file mode 100644 index 0000000..c4e7676 --- /dev/null +++ b/SOURCES/kexec-tools-2.0.8-makedumpfile-Add-module-of-calculating-start_pfn-and.patch @@ -0,0 +1,146 @@ +Return-Path: yishimat@redhat.com +Received: from zmta04.collab.prod.int.phx2.redhat.com (LHLO + zmta04.collab.prod.int.phx2.redhat.com) (10.5.81.11) by + zmail24.collab.prod.int.phx2.redhat.com with LMTP; Thu, 2 Jul 2015 01:09:57 + -0400 (EDT) +Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) + by zmta04.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 29864DA114; + Thu, 2 Jul 2015 01:09:57 -0400 (EDT) +Received: from [10.3.112.13] ([10.3.112.13]) + by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t6259s7J004916; + Thu, 2 Jul 2015 01:09:55 -0400 +Subject: [RHEL7.2 PATCH resend v3 4/5] Add module of calculating start_pfn and + end_pfn in each dumpfile. +To: kexec-kdump-list@redhat.com +References: <55929D94.4020500@redhat.com> <5594C62C.3030407@redhat.com> +Cc: Minfei Huang , bhe@redhat.com, yishimat@redhat.com +From: Yasuaki Ishimatsu +Message-ID: <5594C7A1.6020609@redhat.com> +Date: Thu, 2 Jul 2015 01:09:53 -0400 +User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 + Thunderbird/38.0.1 +MIME-Version: 1.0 +In-Reply-To: <5594C62C.3030407@redhat.com> +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: 7bit +X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 +Content-Length: 3398 + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1182379 + +The patch is back ported directory from the following upstream commit: + +commit 2b74c02081fa0777c8cfb336adb63d9ccb2b46dd +Author: Zhou Wenjian +Date: Fri Nov 7 09:44:56 2014 +0900 + + [PATCH v5 4/5] Add module of calculating start_pfn and end_pfn in each + + When --split is specified in cyclic mode, start_pfn and end_pfn of each + will be calculated to make each dumpfile have the same size. + + Signed-off-by: Qiao Nuohan + Signed-off-by: Zhou Wenjian + +Resolves: rhbz#1182379 +Signed-off-by: Yasuaki Ishimatsu + +--- + makedumpfile-1.5.7/makedumpfile.c | 73 ++++++++++++++++++++++++++++++++++--- + 1 files changed, 68 insertions(+), 5 deletions(-) + +diff --git a/makedumpfile-1.5.7/makedumpfile.c b/makedumpfile-1.5.7/makedumpfile.c +index 5ffe8e1..c4309af 100644 +--- a/makedumpfile-1.5.7/makedumpfile.c ++++ b/makedumpfile-1.5.7/makedumpfile.c +@@ -8218,6 +8218,65 @@ out: + return ret; + } + ++/* ++ * calculate end_pfn of one dumpfile. ++ * try to make every output file have the same size. ++ * splitblock_table is used to reduce calculate time. ++ */ ++ ++#define CURRENT_SPLITBLOCK_PFN_NUM (*cur_splitblock_num * splitblock->page_per_splitblock) ++mdf_pfn_t ++calculate_end_pfn_by_splitblock(mdf_pfn_t start_pfn, ++ int *cur_splitblock_num) ++{ ++ if (start_pfn >= info->max_mapnr) ++ return info->max_mapnr; ++ ++ mdf_pfn_t end_pfn; ++ long long pfn_needed, offset; ++ char *splitblock_value_offset; ++ ++ pfn_needed = info->num_dumpable / info->num_dumpfile; ++ offset = *cur_splitblock_num * splitblock->entry_size; ++ splitblock_value_offset = splitblock->table + offset; ++ end_pfn = start_pfn; ++ ++ while (*cur_splitblock_num < splitblock->num && pfn_needed > 0) { ++ pfn_needed -= read_from_splitblock_table(splitblock_value_offset); ++ splitblock_value_offset += splitblock->entry_size; ++ ++*cur_splitblock_num; ++ } ++ ++ end_pfn = CURRENT_SPLITBLOCK_PFN_NUM; ++ if (end_pfn > info->max_mapnr) ++ end_pfn = info->max_mapnr; ++ ++ return end_pfn; ++} ++ ++/* ++ * calculate start_pfn and end_pfn in each output file. ++ */ ++static int setup_splitting_cyclic(void) ++{ ++ int i; ++ mdf_pfn_t start_pfn, end_pfn; ++ int cur_splitblock_num = 0; ++ start_pfn = end_pfn = 0; ++ ++ for (i = 0; i < info->num_dumpfile - 1; i++) { ++ start_pfn = end_pfn; ++ end_pfn = calculate_end_pfn_by_splitblock(start_pfn, ++ &cur_splitblock_num); ++ SPLITTING_START_PFN(i) = start_pfn; ++ SPLITTING_END_PFN(i) = end_pfn; ++ } ++ SPLITTING_START_PFN(info->num_dumpfile - 1) = end_pfn; ++ SPLITTING_END_PFN(info->num_dumpfile - 1) = info->max_mapnr; ++ ++ return TRUE; ++} ++ + int + setup_splitting(void) + { +@@ -8231,12 +8290,16 @@ setup_splitting(void) + return FALSE; + + if (info->flag_cyclic) { +- for (i = 0; i < info->num_dumpfile; i++) { +- SPLITTING_START_PFN(i) = divideup(info->max_mapnr, info->num_dumpfile) * i; +- SPLITTING_END_PFN(i) = divideup(info->max_mapnr, info->num_dumpfile) * (i + 1); ++ int ret = FALSE; ++ ++ if (!prepare_bitmap2_buffer_cyclic()) { ++ free_bitmap_buffer(); ++ return ret; + } +- if (SPLITTING_END_PFN(i-1) > info->max_mapnr) +- SPLITTING_END_PFN(i-1) = info->max_mapnr; ++ ret = setup_splitting_cyclic(); ++ free_bitmap2_buffer_cyclic(); ++ ++ return ret; + } else { + initialize_2nd_bitmap(&bitmap2); + +-- +1.7.1 + diff --git a/SOURCES/kexec-tools-2.0.8-makedumpfile-Add-module-of-generating-table.patch b/SOURCES/kexec-tools-2.0.8-makedumpfile-Add-module-of-generating-table.patch new file mode 100644 index 0000000..f6e4115 --- /dev/null +++ b/SOURCES/kexec-tools-2.0.8-makedumpfile-Add-module-of-generating-table.patch @@ -0,0 +1,219 @@ +Return-Path: yishimat@redhat.com +Received: from zmta05.collab.prod.int.phx2.redhat.com (LHLO + zmta05.collab.prod.int.phx2.redhat.com) (10.5.81.12) by + zmail24.collab.prod.int.phx2.redhat.com with LMTP; Thu, 2 Jul 2015 01:08:58 + -0400 (EDT) +Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) + by zmta05.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 6922D17C114; + Thu, 2 Jul 2015 01:08:58 -0400 (EDT) +Received: from [10.3.112.13] ([10.3.112.13]) + by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t6258t32026109; + Thu, 2 Jul 2015 01:08:56 -0400 +Subject: [RHEL7.2 PATCH resend v3 3/5] Add module of generating table. +To: kexec-kdump-list@redhat.com +References: <55929D94.4020500@redhat.com> <5594C62C.3030407@redhat.com> +Cc: Minfei Huang , bhe@redhat.com, yishimat@redhat.com +From: Yasuaki Ishimatsu +Message-ID: <5594C766.5010801@redhat.com> +Date: Thu, 2 Jul 2015 01:08:54 -0400 +User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 + Thunderbird/38.0.1 +MIME-Version: 1.0 +In-Reply-To: <5594C62C.3030407@redhat.com> +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: 7bit +X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 +Content-Length: 5064 + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1182379 + +The patch is back ported directory from the following upstream commit: + +commit 28e367cb78258e5d8d89edc5435804495661d1a3 +Author: Zhou Wenjian +Date: Fri Nov 7 09:43:26 2014 +0900 + + [PATCH v5 3/5] Add module of generating table. + + Set block size and generate basic information of block table. + + Signed-off-by: Qiao Nuohan + Signed-off-by: Zhou Wenjian + +Resolves: rhbz#1182379 +Signed-off-by: Yasuaki Ishimatsu + +--- + makedumpfile-1.5.7/makedumpfile.c | 109 ++++++++++++++++++++++++++++++++++++- + makedumpfile-1.5.7/makedumpfile.h | 4 ++ + 2 files changed, 112 insertions(+), 1 deletions(-) + +diff --git a/makedumpfile-1.5.7/makedumpfile.c b/makedumpfile-1.5.7/makedumpfile.c +index 4d2f077..5ffe8e1 100644 +--- a/makedumpfile-1.5.7/makedumpfile.c ++++ b/makedumpfile-1.5.7/makedumpfile.c +@@ -5208,7 +5208,14 @@ create_dump_bitmap(void) + if (info->flag_cyclic) { + if (!prepare_bitmap2_buffer_cyclic()) + goto out; +- info->num_dumpable = get_num_dumpable_cyclic(); ++ if (info->flag_split) { ++ if (!prepare_splitblock_table()) ++ goto out; ++ ++ info->num_dumpable = get_num_dumpable_cyclic_withsplit(); ++ } else { ++ info->num_dumpable = get_num_dumpable_cyclic(); ++ } + + if (!info->flag_elf_dumpfile) + free_bitmap2_buffer_cyclic(); +@@ -5745,6 +5752,61 @@ read_from_splitblock_table(char *entry) + return value; + } + ++/* ++ * The splitblock size is specified as Kbyte with --splitblock-size option. ++ * If not specified, set default value. ++ */ ++int ++check_splitblock_size(void) ++{ ++ if (info->splitblock_size) { ++ info->splitblock_size <<= 10; ++ if (info->splitblock_size == 0) { ++ ERRMSG("The splitblock size could not be 0. %s.\n", ++ strerror(errno)); ++ return FALSE; ++ } ++ if (info->splitblock_size % info->page_size != 0) { ++ ERRMSG("The splitblock size must be align to page_size. %s.\n", ++ strerror(errno)); ++ return FALSE; ++ } ++ } else { ++ info->splitblock_size = DEFAULT_SPLITBLOCK_SIZE; ++ } ++ ++ return TRUE; ++} ++ ++int ++prepare_splitblock_table(void) ++{ ++ size_t table_size; ++ ++ if (!check_splitblock_size()) ++ return FALSE; ++ ++ if ((splitblock = calloc(1, sizeof(struct SplitBlock))) == NULL) { ++ ERRMSG("Can't allocate memory for the splitblock. %s.\n", ++ strerror(errno)); ++ return FALSE; ++ } ++ ++ splitblock->page_per_splitblock = info->splitblock_size / info->page_size; ++ splitblock->num = divideup(info->max_mapnr, splitblock->page_per_splitblock); ++ splitblock->entry_size = calculate_entry_size(); ++ table_size = splitblock->entry_size * splitblock->num; ++ ++ splitblock->table = (char *)calloc(sizeof(char), table_size); ++ if (!splitblock->table) { ++ ERRMSG("Can't allocate memory for the splitblock_table. %s.\n", ++ strerror(errno)); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ + mdf_pfn_t + get_num_dumpable(void) + { +@@ -5760,6 +5822,45 @@ get_num_dumpable(void) + return num_dumpable; + } + ++/* ++ * generate splitblock_table ++ * modified from function get_num_dumpable_cyclic ++ */ ++mdf_pfn_t ++get_num_dumpable_cyclic_withsplit(void) ++{ ++ mdf_pfn_t pfn, num_dumpable = 0; ++ mdf_pfn_t dumpable_pfn_num = 0, pfn_num = 0; ++ struct cycle cycle = {0}; ++ int pos = 0; ++ ++ pfn_memhole = info->max_mapnr; ++ ++ for_each_cycle(0, info->max_mapnr, &cycle) { ++ if (!exclude_unnecessary_pages_cyclic(&cycle)) ++ return FALSE; ++ ++ if (info->flag_mem_usage) ++ exclude_zero_pages_cyclic(&cycle); ++ ++ for (pfn = cycle.start_pfn; pfn < cycle.end_pfn; pfn++) { ++ if (is_dumpable_cyclic(info->partial_bitmap2, pfn, &cycle)) { ++ num_dumpable++; ++ dumpable_pfn_num++; ++ } ++ if (++pfn_num >= splitblock->page_per_splitblock) { ++ write_into_splitblock_table(splitblock->table + pos, ++ dumpable_pfn_num); ++ pos += splitblock->entry_size; ++ pfn_num = 0; ++ dumpable_pfn_num = 0; ++ } ++ } ++ } ++ ++ return num_dumpable; ++} ++ + mdf_pfn_t + get_num_dumpable_cyclic(void) + { +@@ -9717,6 +9818,12 @@ out: + if (info->page_buf != NULL) + free(info->page_buf); + free(info); ++ ++ if (splitblock) { ++ if (splitblock->table) ++ free(splitblock->table); ++ free(splitblock); ++ } + } + free_elf_info(); + +diff --git a/makedumpfile-1.5.7/makedumpfile.h b/makedumpfile-1.5.7/makedumpfile.h +index a263631..f9d9332 100644 +--- a/makedumpfile-1.5.7/makedumpfile.h ++++ b/makedumpfile-1.5.7/makedumpfile.h +@@ -1178,6 +1178,8 @@ extern struct DumpInfo *info; + /* + * for cyclic_splitting mode,Manage memory by splitblock + */ ++#define DEFAULT_SPLITBLOCK_SIZE (1LL << 30) ++ + struct SplitBlock { + char *table; + long long num; +@@ -1888,9 +1890,11 @@ struct elf_prstatus { + * Function Prototype. + */ + mdf_pfn_t get_num_dumpable_cyclic(void); ++mdf_pfn_t get_num_dumpable_cyclic_withsplit(void); + int get_loads_dumpfile_cyclic(void); + int initial_xen(void); + unsigned long long get_free_memory_size(void); + int calculate_cyclic_buffer_size(void); ++int prepare_splitblock_table(void); + + #endif /* MAKEDUMPFILE_H */ +-- +1.7.1 + diff --git a/SOURCES/kexec-tools-2.0.8-makedumpfile-Add-support-for-splitblock-size.patch b/SOURCES/kexec-tools-2.0.8-makedumpfile-Add-support-for-splitblock-size.patch new file mode 100644 index 0000000..31df8b8 --- /dev/null +++ b/SOURCES/kexec-tools-2.0.8-makedumpfile-Add-support-for-splitblock-size.patch @@ -0,0 +1,128 @@ +Return-Path: yishimat@redhat.com +Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO + zmta01.collab.prod.int.phx2.redhat.com) (10.5.81.8) by + zmail24.collab.prod.int.phx2.redhat.com with LMTP; Thu, 2 Jul 2015 01:10:45 + -0400 (EDT) +Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) + by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 5C0B61835A9; + Thu, 2 Jul 2015 01:10:45 -0400 (EDT) +Received: from [10.3.112.13] ([10.3.112.13]) + by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t625AhFu027595; + Thu, 2 Jul 2015 01:10:43 -0400 +Subject: [RHEL7.2 PATCH resend v3 5/5] Add support for --splitblock-size. +To: kexec-kdump-list@redhat.com +References: <55929D94.4020500@redhat.com> <5594C62C.3030407@redhat.com> +Cc: Minfei Huang , bhe@redhat.com, yishimat@redhat.com +From: Yasuaki Ishimatsu +Message-ID: <5594C7D2.8030300@redhat.com> +Date: Thu, 2 Jul 2015 01:10:42 -0400 +User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 + Thunderbird/38.0.1 +MIME-Version: 1.0 +In-Reply-To: <5594C62C.3030407@redhat.com> +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: 7bit +X-Scanned-By: MIMEDefang 2.68 on 10.5.11.26 +Content-Length: 4028 + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1182379 + +The patch is back ported directory from the following upstream commit: + +commit 33521799757a52f0e97cbfb7c6a5e24de3b8cb50 +Author: Zhou Wenjian +Date: Fri Nov 7 09:45:04 2014 +0900 + + [PATCH v5 5/5] Add support for --splitblock-size. + + Use --splitblock-size to specify splitblock size (KB) + When --split is specified in cyclic mode,splitblock table will be + generated in create_dump_bitmap(). + + Signed-off-by: Qiao Nuohan + Signed-off-by: Zhou Wenjian + +Resolves: rhbz#1182379 +Signed-off-by: Yasuaki Ishimatsu + +--- + makedumpfile-1.5.7/makedumpfile.8 | 10 ++++++++++ + makedumpfile-1.5.7/makedumpfile.c | 4 ++++ + makedumpfile-1.5.7/makedumpfile.h | 1 + + makedumpfile-1.5.7/print_info.c | 5 +++++ + 4 files changed, 20 insertions(+), 0 deletions(-) + +diff --git a/makedumpfile-1.5.7/makedumpfile.8 b/makedumpfile-1.5.7/makedumpfile.8 +index 9cb12c0..5e121fd 100644 +--- a/makedumpfile-1.5.7/makedumpfile.8 ++++ b/makedumpfile-1.5.7/makedumpfile.8 +@@ -386,6 +386,16 @@ size, so ordinary users don't need to specify this option. + # makedumpfile \-\-cyclic\-buffer 1024 \-d 31 \-x vmlinux /proc/vmcore dumpfile + + .TP ++\fB\-\-splitblock\-size\fR \fIsplitblock_size\fR ++Specify the splitblock size in kilo bytes for analysis in the cyclic mode with --split. ++If --splitblock N is specified, difference of each splitted dumpfile size is at most N ++kilo bytes. ++.br ++.B Example: ++.br ++# makedumpfile \-\-splitblock\-size 1024 \-d 31 \-x vmlinux \-\-split /proc/vmcore dumpfile1 dumpfile2 ++ ++.TP + \fB\-\-non\-cyclic\fR + Running in the non-cyclic mode, this mode uses the old filtering logic same as v1.4.4 or before. + If you feel the cyclic mode is too slow, please try this mode. +diff --git a/makedumpfile-1.5.7/makedumpfile.c b/makedumpfile-1.5.7/makedumpfile.c +index c4309af..f3e76c9 100644 +--- a/makedumpfile-1.5.7/makedumpfile.c ++++ b/makedumpfile-1.5.7/makedumpfile.c +@@ -9570,6 +9570,7 @@ static struct option longopts[] = { + {"eppic", required_argument, NULL, OPT_EPPIC}, + {"non-mmap", no_argument, NULL, OPT_NON_MMAP}, + {"mem-usage", no_argument, NULL, OPT_MEM_USAGE}, ++ {"splitblock-size", required_argument, NULL, OPT_SPLITBLOCK_SIZE}, + {0, 0, 0, 0} + }; + +@@ -9710,6 +9711,9 @@ main(int argc, char *argv[]) + case OPT_CYCLIC_BUFFER: + info->bufsize_cyclic = atoi(optarg); + break; ++ case OPT_SPLITBLOCK_SIZE: ++ info->splitblock_size = atoi(optarg); ++ break; + case '?': + MSG("Commandline parameter is invalid.\n"); + MSG("Try `makedumpfile --help' for more information.\n"); +diff --git a/makedumpfile-1.5.7/makedumpfile.h b/makedumpfile-1.5.7/makedumpfile.h +index f9d9332..0cb54a3 100644 +--- a/makedumpfile-1.5.7/makedumpfile.h ++++ b/makedumpfile-1.5.7/makedumpfile.h +@@ -1885,6 +1885,7 @@ struct elf_prstatus { + #define OPT_EPPIC OPT_START+12 + #define OPT_NON_MMAP OPT_START+13 + #define OPT_MEM_USAGE OPT_START+14 ++#define OPT_SPLITBLOCK_SIZE OPT_START+15 + + /* + * Function Prototype. +diff --git a/makedumpfile-1.5.7/print_info.c b/makedumpfile-1.5.7/print_info.c +index f6342d3..efdf578 100644 +--- a/makedumpfile-1.5.7/print_info.c ++++ b/makedumpfile-1.5.7/print_info.c +@@ -203,6 +203,11 @@ print_usage(void) + MSG(" By default, BUFFER_SIZE will be calculated automatically depending on\n"); + MSG(" system memory size, so ordinary users don't need to specify this option.\n"); + MSG("\n"); ++ MSG(" [--splitblock-size SPLITBLOCK_SIZE]:\n"); ++ MSG(" Specify the splitblock size in kilo bytes for analysis in the cyclic mode\n"); ++ MSG(" with --split. If --splitblock N is specified, difference of each splitted\n"); ++ MSG(" dumpfile size is at most N kilo bytes.\n"); ++ MSG("\n"); + MSG(" [--non-cyclic]:\n"); + MSG(" Running in the non-cyclic mode, this mode uses the old filtering logic\n"); + MSG(" same as v1.4.4 or before.\n"); +-- +1.7.1 + diff --git a/SOURCES/kexec-tools-2.0.8-makedumpfile-Add-support-for-splitblock.patch b/SOURCES/kexec-tools-2.0.8-makedumpfile-Add-support-for-splitblock.patch new file mode 100644 index 0000000..12e0514 --- /dev/null +++ b/SOURCES/kexec-tools-2.0.8-makedumpfile-Add-support-for-splitblock.patch @@ -0,0 +1,146 @@ +Return-Path: yishimat@redhat.com +Received: from zmta05.collab.prod.int.phx2.redhat.com (LHLO + zmta05.collab.prod.int.phx2.redhat.com) (10.5.81.12) by + zmail24.collab.prod.int.phx2.redhat.com with LMTP; Thu, 2 Jul 2015 01:06:36 + -0400 (EDT) +Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) + by zmta05.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 9A5FA17C114; + Thu, 2 Jul 2015 01:06:36 -0400 (EDT) +Received: from [10.3.112.13] ([10.3.112.13]) + by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t6256Wbm025889; + Thu, 2 Jul 2015 01:06:33 -0400 +Subject: [RHEL7.2 PATCH resend v3 1/5] Add support for splitblock. +To: kexec-kdump-list@redhat.com +References: <55929D94.4020500@redhat.com> <5594C62C.3030407@redhat.com> +Cc: Minfei Huang , bhe@redhat.com, yishimat@redhat.com +From: Yasuaki Ishimatsu +Message-ID: <5594C6D8.5060601@redhat.com> +Date: Thu, 2 Jul 2015 01:06:32 -0400 +User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 + Thunderbird/38.0.1 +MIME-Version: 1.0 +In-Reply-To: <5594C62C.3030407@redhat.com> +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: 7bit +X-Scanned-By: MIMEDefang 2.68 on 10.5.11.26 +Content-Length: 3498 + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1182379 + +The patch is back ported directory from the following upstream commit: + +commit c7825d45999daf09bd89a08d08219261023dcf11 +Author: Zhou Wenjian +Date: Fri Nov 7 09:42:18 2014 +0900 + + [PATCH v5 1/5] Add support for splitblock. + + When --split option is specified, fair I/O workloads shoud be assigned + for each process. So the start and end pfn of each dumpfile should be + calculated with excluding unnecessary pages. However, it costs a lot of + time to execute excluding for the whole memory. That is why struct + SplitBlock exists. Struct SplitBlock is designed to manage memory, main + for recording the number of dumpable pages. We can use the number of + dumpable pages to calculate start and end pfn instead of execute exclud + for the whole memory. + + The char array *table in struct SplitBlock is used to record the number + dumpable pages. + The table entry size is calculated as + divideup(log2(splitblock_size / page_size), 8) + The table entry size is calculated, so that the + space table taken will be small enough. And the code will also have a + good performence when the number of pages in one splitblock is big enou + + Signed-off-by: Qiao Nuohan + Signed-off-by: Zhou Wenjian + +Resolves: rhbz#1182379 +Signed-off-by: Yasuaki Ishimatsu + +--- + makedumpfile-1.5.7/makedumpfile.c | 31 +++++++++++++++++++++++++++++++ + makedumpfile-1.5.7/makedumpfile.h | 14 ++++++++++++++ + 2 files changed, 45 insertions(+), 0 deletions(-) + +diff --git a/makedumpfile-1.5.7/makedumpfile.c b/makedumpfile-1.5.7/makedumpfile.c +index b4d43d8..a4c3eee 100644 +--- a/makedumpfile-1.5.7/makedumpfile.c ++++ b/makedumpfile-1.5.7/makedumpfile.c +@@ -34,6 +34,7 @@ struct srcfile_table srcfile_table; + + struct vm_table vt = { 0 }; + struct DumpInfo *info = NULL; ++struct SplitBlock *splitblock = NULL; + + char filename_stdout[] = FILENAME_STDOUT; + +@@ -5685,6 +5686,36 @@ out: + return ret; + } + ++/* ++ * cyclic_split mode: ++ * manage memory by splitblocks, ++ * divide memory into splitblocks ++ * use splitblock_table to record numbers of dumpable pages in each ++ * splitblock ++ */ ++ ++/* ++ * calculate entry size based on the amount of pages in one splitblock ++ */ ++int ++calculate_entry_size(void) ++{ ++ int entry_num = 1; ++ int count = 1; ++ int entry_size; ++ ++ while (entry_num < splitblock->page_per_splitblock) { ++ entry_num = entry_num << 1; ++ count++; ++ } ++ ++ entry_size = count / BITPERBYTE; ++ if (count % BITPERBYTE) ++ entry_size++; ++ ++ return entry_size; ++} ++ + mdf_pfn_t + get_num_dumpable(void) + { +diff --git a/makedumpfile-1.5.7/makedumpfile.h b/makedumpfile-1.5.7/makedumpfile.h +index 96830b0..a263631 100644 +--- a/makedumpfile-1.5.7/makedumpfile.h ++++ b/makedumpfile-1.5.7/makedumpfile.h +@@ -1168,10 +1168,24 @@ struct DumpInfo { + */ + int (*page_is_buddy)(unsigned long flags, unsigned int _mapcount, + unsigned long private, unsigned int _count); ++ /* ++ * for cyclic_splitting mode, setup splitblock_size ++ */ ++ long long splitblock_size; + }; + extern struct DumpInfo *info; + + /* ++ * for cyclic_splitting mode,Manage memory by splitblock ++ */ ++struct SplitBlock { ++ char *table; ++ long long num; ++ long long page_per_splitblock; ++ int entry_size; /* counted by byte */ ++}; ++ ++/* + * kernel VM-related data + */ + struct vm_table { +-- +1.7.1 + diff --git a/SOURCES/kexec-tools-2.0.8-makedumpfile-Add-tools-for-reading-and-writing-from-.patch b/SOURCES/kexec-tools-2.0.8-makedumpfile-Add-tools-for-reading-and-writing-from-.patch new file mode 100644 index 0000000..cd5a144 --- /dev/null +++ b/SOURCES/kexec-tools-2.0.8-makedumpfile-Add-tools-for-reading-and-writing-from-.patch @@ -0,0 +1,94 @@ +Return-Path: yishimat@redhat.com +Received: from zmta05.collab.prod.int.phx2.redhat.com (LHLO + zmta05.collab.prod.int.phx2.redhat.com) (10.5.81.12) by + zmail24.collab.prod.int.phx2.redhat.com with LMTP; Thu, 2 Jul 2015 01:08:13 + -0400 (EDT) +Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) + by zmta05.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 7D03B17C114; + Thu, 2 Jul 2015 01:08:13 -0400 (EDT) +Received: from [10.3.112.13] ([10.3.112.13]) + by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t6258AD6015893; + Thu, 2 Jul 2015 01:08:11 -0400 +Subject: [RHEL7.2 PATCH resend v3 2/5] Add tools for reading and writing from + splitblock table. +To: kexec-kdump-list@redhat.com +References: <55929D94.4020500@redhat.com> <5594C62C.3030407@redhat.com> +Cc: Minfei Huang , bhe@redhat.com, yishimat@redhat.com +From: Yasuaki Ishimatsu +Message-ID: <5594C73A.6080509@redhat.com> +Date: Thu, 2 Jul 2015 01:08:10 -0400 +User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 + Thunderbird/38.0.1 +MIME-Version: 1.0 +In-Reply-To: <5594C62C.3030407@redhat.com> +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: 7bit +X-Scanned-By: MIMEDefang 2.68 on 10.5.11.24 +Content-Length: 1602 + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1182379 + +The patch is back ported directory from the following upstream commit: + +commit 11dcbfe2ebd1dec37c3a00dc8ee522504c7ed35c +Author: Zhou Wenjian +Date: Fri Nov 7 09:42:25 2014 +0900 + + [PATCH v5 2/5] Add tools for reading and writing from splitblock table. + + gdded in this patch, is used for writing and reading value + from the char array in struct SplitBlock. + + Signed-off-by: Qiao Nuohan + Signed-off-by: Zhou Wenjian + +Resolves: rhbz#1182379 +Signed-off-by: Yasuaki Ishimatsu + +--- + makedumpfile-1.5.7/makedumpfile.c | 29 +++++++++++++++++++++++++++++ + 1 files changed, 29 insertions(+), 0 deletions(-) + +diff --git a/makedumpfile-1.5.7/makedumpfile.c b/makedumpfile-1.5.7/makedumpfile.c +index a4c3eee..4d2f077 100644 +--- a/makedumpfile-1.5.7/makedumpfile.c ++++ b/makedumpfile-1.5.7/makedumpfile.c +@@ -5716,6 +5716,35 @@ calculate_entry_size(void) + return entry_size; + } + ++void ++write_into_splitblock_table(char *entry, ++ unsigned long long value) ++{ ++ char temp; ++ int i = 0; ++ ++ while (i++ < splitblock->entry_size) { ++ temp = value & 0xff; ++ value = value >> BITPERBYTE; ++ *entry = temp; ++ entry++; ++ } ++} ++ ++unsigned long long ++read_from_splitblock_table(char *entry) ++{ ++ unsigned long long value = 0; ++ int i; ++ ++ for (i = splitblock->entry_size; i > 0; i--) { ++ value = value << BITPERBYTE; ++ value += *(entry + i - 1) & 0xff; ++ } ++ ++ return value; ++} ++ + mdf_pfn_t + get_num_dumpable(void) + { +-- +1.7.1 + diff --git a/SOURCES/kexec-tools-2.0.8-makedumpfile-Fix-reassemble_kdump_header.patch b/SOURCES/kexec-tools-2.0.8-makedumpfile-Fix-reassemble_kdump_header.patch new file mode 100644 index 0000000..39c5c48 --- /dev/null +++ b/SOURCES/kexec-tools-2.0.8-makedumpfile-Fix-reassemble_kdump_header.patch @@ -0,0 +1,73 @@ +Return-Path: yishimat@redhat.com +Received: from zmta02.collab.prod.int.phx2.redhat.com (LHLO + zmta02.collab.prod.int.phx2.redhat.com) (10.5.81.9) by + zmail24.collab.prod.int.phx2.redhat.com with LMTP; Thu, 2 Jul 2015 01:16:42 + -0400 (EDT) +Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) + by zmta02.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 9997C122359; + Thu, 2 Jul 2015 01:16:42 -0400 (EDT) +Received: from [10.3.112.13] ([10.3.112.13]) + by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t625Geo3028836; + Thu, 2 Jul 2015 01:16:41 -0400 +Subject: [RHEL7.2 PATCH resend v3 4/4] Fix reassemble_kdump_header(). +To: kexec-kdump-list@redhat.com +References: <55929BD5.7050709@redhat.com> <5594C856.6050503@redhat.com> +Cc: Minfei Huang , bhe@redhat.com, yishimat@redhat.com +From: Yasuaki Ishimatsu +Message-ID: <5594C937.2060303@redhat.com> +Date: Thu, 2 Jul 2015 01:16:39 -0400 +User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 + Thunderbird/38.0.1 +MIME-Version: 1.0 +In-Reply-To: <5594C856.6050503@redhat.com> +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: 7bit +X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 +Content-Length: 1349 + +https://bugzilla.redhat.com/show_bug.cgi?id=1182377 + +The patch is back ported directory from the following upstream commit: + +commit 45a1885e747c3833d5df770d0f2c5571a838f55a +Author: Zhou Wenjian +Date: Mon Oct 20 13:40:10 2014 +0900 + + [PATCH v4 4/4] Fix reassemble_kdump_header(). + + Fix it to take over incomplete flags of all dump file. + + Singed-of-by: Zhou Wenjian + +Resolves: rhbz#1182377 +Signed-off-by: Yasuaki Ishimatsu +Acked-by: Minfei Huang + +--- + makedumpfile-1.5.7/makedumpfile.c | 10 ++++++++-- + 1 files changed, 8 insertions(+), 2 deletions(-) + +diff --git a/makedumpfile-1.5.7/makedumpfile.c b/makedumpfile-1.5.7/makedumpfile.c +index 4dba83e..f072069 100644 +--- a/makedumpfile-1.5.7/makedumpfile.c ++++ b/makedumpfile-1.5.7/makedumpfile.c +@@ -8695,8 +8695,14 @@ reassemble_kdump_header(void) + /* + * Write common header. + */ +- if (!read_disk_dump_header(&dh, SPLITTING_DUMPFILE(0))) +- return FALSE; ++ int i; ++ for ( i = 0; i < info->num_dumpfile; i++){ ++ if (!read_disk_dump_header(&dh, SPLITTING_DUMPFILE(i))) ++ return FALSE; ++ int status = dh.status & DUMP_DH_COMPRESSED_INCOMPLETE; ++ if (status) ++ break; ++ } + + if (lseek(info->fd_dumpfile, 0x0, SEEK_SET) < 0) { + ERRMSG("Can't seek a file(%s). %s\n", +-- +1.7.1 + diff --git a/SOURCES/kexec-tools-2.0.8-makedumpfile-Implementation-of-dealing-with-kdump-co.patch b/SOURCES/kexec-tools-2.0.8-makedumpfile-Implementation-of-dealing-with-kdump-co.patch new file mode 100644 index 0000000..2d56069 --- /dev/null +++ b/SOURCES/kexec-tools-2.0.8-makedumpfile-Implementation-of-dealing-with-kdump-co.patch @@ -0,0 +1,184 @@ +Return-Path: yishimat@redhat.com +Received: from zmta01.collab.prod.int.phx2.redhat.com (LHLO + zmta01.collab.prod.int.phx2.redhat.com) (10.5.81.8) by + zmail24.collab.prod.int.phx2.redhat.com with LMTP; Thu, 2 Jul 2015 01:15:32 + -0400 (EDT) +Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) + by zmta01.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id C144F1835B7; + Thu, 2 Jul 2015 01:15:32 -0400 (EDT) +Received: from [10.3.112.13] ([10.3.112.13]) + by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t625FTop028995; + Thu, 2 Jul 2015 01:15:30 -0400 +Subject: [RHEL7.2 PATCH resend v3 3/4] Implementation of dealing with + kdump-compressed dumpfile with ENOSPC error. +To: kexec-kdump-list@redhat.com +References: <55929BD5.7050709@redhat.com> <5594C856.6050503@redhat.com> +Cc: Minfei Huang , bhe@redhat.com, yishimat@redhat.com +From: Yasuaki Ishimatsu +Message-ID: <5594C8F1.3070006@redhat.com> +Date: Thu, 2 Jul 2015 01:15:29 -0400 +User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 + Thunderbird/38.0.1 +MIME-Version: 1.0 +In-Reply-To: <5594C856.6050503@redhat.com> +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: 7bit +X-Scanned-By: MIMEDefang 2.68 on 10.5.11.26 +Content-Length: 4314 + +https://bugzilla.redhat.com/show_bug.cgi?id=1182377 + +The patch is back ported directory from the following upstream commit: + +commit 76025d3ca228affdd124b874b06d7a69573391e9 +Author: Wang Xiao +Date: Mon Oct 20 13:39:16 2014 +0900 + + [PATCH v4 3/4] Implementation of dealing with kdump-compressed dumpfile with ENOSPC error. + + kdump-compressed: + Dump the bitmap before any page header and page data. This format use + "status" of "disk_dump_header" to indicate that it has been modified. + + Signed-of-by: Wang Xiao + +Resolves: rhbz#1182377 +Signed-off-by: Yasuaki Ishimatsu +Acked-by: Minfei Huang num_dumpfile]; ++ ++ for (i = 0; i < info->num_dumpfile; i++) { ++ if ((pid = fork()) < 0) { ++ return FALSE; ++ ++ } else if (pid == 0) { /* Child */ ++ if (!check_and_modify_kdump_headers(SPLITTING_DUMPFILE(i))) ++ exit(1); ++ exit(0); ++ } ++ array_pid[i] = pid; ++ } ++ ++ for (i = 0; i < info->num_dumpfile; i++) { ++ waitpid(array_pid[i], &status, WUNTRACED); ++ if (!WIFEXITED(status) || WEXITSTATUS(status) == 1) { ++ ERRMSG("Check and modify the incomplete dumpfile(%s) failed.\n", ++ SPLITTING_DUMPFILE(i)); ++ ret = FALSE; ++ } ++ } ++ ++ return ret; ++} ++ ++int + check_and_modify_headers() + { + if (info->flag_elf_dumpfile) + return check_and_modify_elf_headers(info->name_dumpfile); ++ else ++ if(info->flag_split) ++ return check_and_modify_multiple_kdump_headers(); ++ else ++ return check_and_modify_kdump_headers(info->name_dumpfile); + return FALSE; + } + +@@ -7123,11 +7193,11 @@ write_kdump_pages_and_bitmap_cyclic(struct cache_data *cd_header, struct cache_d + if (!exclude_unnecessary_pages_cyclic(&cycle)) + return FALSE; + +- if (!write_kdump_pages_cyclic(cd_header, cd_page, &pd_zero, +- &offset_data, &cycle)) ++ if (!write_kdump_bitmap2_cyclic(&cycle)) + return FALSE; + +- if (!write_kdump_bitmap2_cyclic(&cycle)) ++ if (!write_kdump_pages_cyclic(cd_header, cd_page, &pd_zero, ++ &offset_data, &cycle)) + return FALSE; + } + +@@ -8127,12 +8197,12 @@ writeout_dumpfile(void) + } else { + if (!write_kdump_header()) + goto out; ++ if (!write_kdump_bitmap()) ++ goto out; + if (!write_kdump_pages(&cd_header, &cd_page)) + goto out; + if (!write_kdump_eraseinfo(&cd_page)) + goto out; +- if (!write_kdump_bitmap()) +- goto out; + } + if (info->flag_flatten) { + if (!write_end_flat_header()) +-- +1.7.1 + diff --git a/SOURCES/kexec-tools-2.0.8-makedumpfile-Make-get_elf64_phdr-get_elf32_phdr-publ.patch b/SOURCES/kexec-tools-2.0.8-makedumpfile-Make-get_elf64_phdr-get_elf32_phdr-publ.patch new file mode 100644 index 0000000..5599dbc --- /dev/null +++ b/SOURCES/kexec-tools-2.0.8-makedumpfile-Make-get_elf64_phdr-get_elf32_phdr-publ.patch @@ -0,0 +1,160 @@ +Return-Path: yishimat@redhat.com +Received: from zmta04.collab.prod.int.phx2.redhat.com (LHLO + zmta04.collab.prod.int.phx2.redhat.com) (10.5.81.11) by + zmail24.collab.prod.int.phx2.redhat.com with LMTP; Thu, 2 Jul 2015 01:14:06 + -0400 (EDT) +Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) + by zmta04.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 08529DA114; + Thu, 2 Jul 2015 01:14:06 -0400 (EDT) +Received: from [10.3.112.13] ([10.3.112.13]) + by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t625E1nH006506; + Thu, 2 Jul 2015 01:14:03 -0400 +Subject: [RHEL7.2 PATCH resend v3 1/4] Make get_elf64_phdr()/get_elf32_phdr() + public. +To: kexec-kdump-list@redhat.com +References: <55929BD5.7050709@redhat.com> <5594C856.6050503@redhat.com> +Cc: Minfei Huang , bhe@redhat.com, yishimat@redhat.com +From: Yasuaki Ishimatsu +Message-ID: <5594C899.1070106@redhat.com> +Date: Thu, 2 Jul 2015 01:14:01 -0400 +User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 + Thunderbird/38.0.1 +MIME-Version: 1.0 +In-Reply-To: <5594C856.6050503@redhat.com> +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: 7bit +X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 +Content-Length: 3805 + +https://bugzilla.redhat.com/show_bug.cgi?id=1182377 + +The patch is back ported directory from the following upstream commit: + +commit 3182be907d27584cd04dfb03d0ec5bf7134da87f +Author: Wang Xiao +Date: Mon Oct 20 13:38:45 2014 +0900 + + [PATCH v4 1/4] Make get_elf64_phdr()/get_elf32_phdr() public. + + Move the following two functions from internal function to external + function. + + get_elf64_phdr(int fd, char *filename, int index, Elf64_Phdr *phdr) + get_elf32_phdr(int fd, char *filename, int index, Elf32_Phdr *phdr) + + Signed-of-by: Wang Xiao + +Resolves: rhbz#1182377 +Signed-off-by: Yasuaki Ishimatsu +Acked-by: Minfei Huang + +--- + makedumpfile-1.5.7/elf_info.c | 71 ++++++++++++++++++++--------------------- + makedumpfile-1.5.7/elf_info.h | 2 + + 2 files changed, 37 insertions(+), 36 deletions(-) + +diff --git a/makedumpfile-1.5.7/elf_info.c b/makedumpfile-1.5.7/elf_info.c +index 5be1990..24936d4 100644 +--- a/makedumpfile-1.5.7/elf_info.c ++++ b/makedumpfile-1.5.7/elf_info.c +@@ -95,42 +95,6 @@ static unsigned long size_xen_crash_info; + * Internal functions. + */ + static int +-get_elf64_phdr(int fd, char *filename, int index, Elf64_Phdr *phdr) +-{ +- off_t offset; +- +- offset = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr) * index; +- +- if (lseek(fd, offset, SEEK_SET) < 0) { +- ERRMSG("Can't seek %s. %s\n", filename, strerror(errno)); +- return FALSE; +- } +- if (read(fd, phdr, sizeof(Elf64_Phdr)) != sizeof(Elf64_Phdr)) { +- ERRMSG("Can't read %s. %s\n", filename, strerror(errno)); +- return FALSE; +- } +- return TRUE; +-} +- +-static int +-get_elf32_phdr(int fd, char *filename, int index, Elf32_Phdr *phdr) +-{ +- off_t offset; +- +- offset = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr) * index; +- +- if (lseek(fd, offset, SEEK_SET) < 0) { +- ERRMSG("Can't seek %s. %s\n", filename, strerror(errno)); +- return FALSE; +- } +- if (read(fd, phdr, sizeof(Elf32_Phdr)) != sizeof(Elf32_Phdr)) { +- ERRMSG("Can't read %s. %s\n", filename, strerror(errno)); +- return FALSE; +- } +- return TRUE; +-} +- +-static int + check_elf_format(int fd, char *filename, int *phnum, unsigned int *num_load) + { + int i; +@@ -446,6 +410,41 @@ int set_kcore_vmcoreinfo(uint64_t vmcoreinfo_addr, uint64_t vmcoreinfo_len) + /* + * External functions. + */ ++int ++get_elf64_phdr(int fd, char *filename, int index, Elf64_Phdr *phdr) ++{ ++ off_t offset; ++ ++ offset = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr) * index; ++ ++ if (lseek(fd, offset, SEEK_SET) < 0) { ++ ERRMSG("Can't seek %s. %s\n", filename, strerror(errno)); ++ return FALSE; ++ } ++ if (read(fd, phdr, sizeof(Elf64_Phdr)) != sizeof(Elf64_Phdr)) { ++ ERRMSG("Can't read %s. %s\n", filename, strerror(errno)); ++ return FALSE; ++ } ++ return TRUE; ++} ++ ++int ++get_elf32_phdr(int fd, char *filename, int index, Elf32_Phdr *phdr) ++{ ++ off_t offset; ++ ++ offset = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr) * index; ++ ++ if (lseek(fd, offset, SEEK_SET) < 0) { ++ ERRMSG("Can't seek %s. %s\n", filename, strerror(errno)); ++ return FALSE; ++ } ++ if (read(fd, phdr, sizeof(Elf32_Phdr)) != sizeof(Elf32_Phdr)) { ++ ERRMSG("Can't read %s. %s\n", filename, strerror(errno)); ++ return FALSE; ++ } ++ return TRUE; ++} + + /* + * Convert Physical Address to File Offset. +diff --git a/makedumpfile-1.5.7/elf_info.h b/makedumpfile-1.5.7/elf_info.h +index cbabf8a..e712253 100644 +--- a/makedumpfile-1.5.7/elf_info.h ++++ b/makedumpfile-1.5.7/elf_info.h +@@ -27,6 +27,8 @@ + + #define MAX_SIZE_NHDR MAX(sizeof(Elf64_Nhdr), sizeof(Elf32_Nhdr)) + ++int get_elf64_phdr(int fd, char *filename, int index, Elf64_Phdr *phdr); ++int get_elf32_phdr(int fd, char *filename, int index, Elf32_Phdr *phdr); + + off_t paddr_to_offset(unsigned long long paddr); + off_t paddr_to_offset2(unsigned long long paddr, off_t hint); +-- +1.7.1 + diff --git a/SOURCES/kexec-tools-2.0.8-makedumpfile-Make-the-incomplete-dumpfile-generated-.patch b/SOURCES/kexec-tools-2.0.8-makedumpfile-Make-the-incomplete-dumpfile-generated-.patch new file mode 100644 index 0000000..e53fa33 --- /dev/null +++ b/SOURCES/kexec-tools-2.0.8-makedumpfile-Make-the-incomplete-dumpfile-generated-.patch @@ -0,0 +1,230 @@ +Return-Path: yishimat@redhat.com +Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO + zmta03.collab.prod.int.phx2.redhat.com) (10.5.81.10) by + zmail24.collab.prod.int.phx2.redhat.com with LMTP; Thu, 2 Jul 2015 01:14:45 + -0400 (EDT) +Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) + by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id 4A6B242574; + Thu, 2 Jul 2015 01:14:45 -0400 (EDT) +Received: from [10.3.112.13] ([10.3.112.13]) + by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t625EgU7006706; + Thu, 2 Jul 2015 01:14:43 -0400 +Subject: [RHEL7.2 PATCH resend v3 2/4] Make the incomplete dumpfile generated + by ENOSPC error analyzable. +To: kexec-kdump-list@redhat.com +References: <55929BD5.7050709@redhat.com> <5594C856.6050503@redhat.com> +Cc: Minfei Huang , bhe@redhat.com, yishimat@redhat.com +From: Yasuaki Ishimatsu +Message-ID: <5594C8C2.8080603@redhat.com> +Date: Thu, 2 Jul 2015 01:14:42 -0400 +User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 + Thunderbird/38.0.1 +MIME-Version: 1.0 +In-Reply-To: <5594C856.6050503@redhat.com> +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: 7bit +X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 +Content-Length: 5485 + +https://bugzilla.redhat.com/show_bug.cgi?id=1182377 + +The patch is back ported directory from the following upstream commit: + +commit e39216fce9f73759509ec158e39c289e6c211125 +Author: Wang Xiao +Date: Mon Oct 20 13:39:03 2014 +0900 + + [PATCH v4 2/4] Make the incomplete dumpfile generated by ENOSPC error analyzable. + + Since the incomplete dumpfile generated by ENOSPC error can't be anylyzed + by crash utility, but sometimes this file may contain important information + and the panic problem won't be reproduced, then we came up with an idea to + modify the exist data of the incomplete dumpfile to make it analyzable by + crash utility. And each of those dumpfiles has a flag to indicate that it + has been modified. As there are two formats of these dumpfiles, different + methods and flags are needed to deal with each of them, + + elf: + This format use the "e_flags" of "elf header" to indicate that it has been + modified. + + The method of dealing with "kdump-compressed" format dumpfiles is + implemented + in the next patch. + + Signed-of-by: Wang Xiao + +Resolves: rhbz#1182377 +Signed-off-by: Yasuaki Ishimatsu +Acked-by: Minfei Huang + +--- + makedumpfile-1.5.7/makedumpfile.c | 115 +++++++++++++++++++++++++++++++++++- + 1 files changed, 111 insertions(+), 4 deletions(-) + +diff --git a/makedumpfile-1.5.7/makedumpfile.c b/makedumpfile-1.5.7/makedumpfile.c +index b4d43d8..141d290 100644 +--- a/makedumpfile-1.5.7/makedumpfile.c ++++ b/makedumpfile-1.5.7/makedumpfile.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + struct symbol_table symbol_table; + struct size_table size_table; +@@ -3768,6 +3769,93 @@ read_flat_data_header(struct makedumpfile_data_header *fdh) + } + + int ++reserve_diskspace(int fd, off_t start_offset, off_t end_offset, char *file_name) ++{ ++ size_t buf_size; ++ char *buf = NULL; ++ ++ int ret = FALSE; ++ ++ assert(start_offset < end_offset); ++ buf_size = end_offset - start_offset; ++ ++ if ((buf = malloc(buf_size)) == NULL) { ++ ERRMSG("Can't allocate memory for the size of reserved diskspace. %s\n", ++ strerror(errno)); ++ return FALSE; ++ } ++ ++ memset(buf, 0, buf_size); ++ if (!write_buffer(fd, start_offset, buf, buf_size, file_name)) ++ goto out; ++ ++ ret = TRUE; ++out: ++ if (buf != NULL) { ++ free(buf); ++ } ++ ++ return ret; ++} ++ ++#define DUMP_ELF_INCOMPLETE 0x1 ++int ++check_and_modify_elf_headers(char *filename) ++{ ++ int fd, ret = FALSE; ++ Elf64_Ehdr ehdr64; ++ Elf32_Ehdr ehdr32; ++ ++ if ((fd = open(filename, O_RDWR)) < 0) { ++ ERRMSG("Can't open the dump file(%s). %s\n", ++ filename, strerror(errno)); ++ return FALSE; ++ } ++ ++ /* ++ * the is_elf64_memory() function still can be used. ++ */ ++ /* ++ * Set the incomplete flag to the e_flags of elf header. ++ */ ++ if (is_elf64_memory()) { /* ELF64 */ ++ if (!get_elf64_ehdr(fd, filename, &ehdr64)) { ++ ERRMSG("Can't get ehdr64.\n"); ++ goto out_close_file; ++ } ++ ehdr64.e_flags |= DUMP_ELF_INCOMPLETE; ++ if (!write_buffer(fd, 0, &ehdr64, sizeof(Elf64_Ehdr), filename)) ++ goto out_close_file; ++ ++ } else { /* ELF32 */ ++ if (!get_elf32_ehdr(fd, filename, &ehdr32)) { ++ ERRMSG("Can't get ehdr32.\n"); ++ goto out_close_file; ++ } ++ ehdr32.e_flags |= DUMP_ELF_INCOMPLETE; ++ if (!write_buffer(fd, 0, &ehdr32, sizeof(Elf32_Ehdr), filename)) ++ goto out_close_file; ++ ++ } ++ ret = TRUE; ++out_close_file: ++ if (close(fd) < 0) { ++ ERRMSG("Can't close the dump file(%s). %s\n", ++ filename, strerror(errno)); ++ } ++ return ret; ++} ++ ++int ++check_and_modify_headers() ++{ ++ if (info->flag_elf_dumpfile) ++ return check_and_modify_elf_headers(info->name_dumpfile); ++ return FALSE; ++} ++ ++ ++int + rearrange_dumpdata(void) + { + int read_size, tmp_read_size; +@@ -5498,6 +5586,13 @@ write_elf_header(struct cache_data *cd_header) + size_note = note.p_filesz; + + /* ++ * Reserve a space to store the whole program headers. ++ */ ++ if (!reserve_diskspace(cd_header->fd, cd_header->offset, ++ offset_note_dumpfile, cd_header->file_name)) ++ goto out; ++ ++ /* + * Modify the note size in PT_NOTE header to accomodate eraseinfo data. + * Eraseinfo will be written later. + */ +@@ -8015,10 +8110,10 @@ writeout_dumpfile(void) + goto out; + if (info->flag_cyclic) { + if (!write_elf_pages_cyclic(&cd_header, &cd_page)) +- goto out; ++ goto write_cache_enospc; + } else { + if (!write_elf_pages(&cd_header, &cd_page)) +- goto out; ++ goto write_cache_enospc; + } + if (!write_elf_eraseinfo(&cd_header)) + goto out; +@@ -8045,6 +8140,11 @@ writeout_dumpfile(void) + } + + ret = TRUE; ++write_cache_enospc: ++ if ((ret == FALSE) && info->flag_nospace && !info->flag_flatten) { ++ if (!write_cache_bufsz(&cd_header)) ++ ERRMSG("This dumpfile may lost some important data.\n"); ++ } + out: + free_cache_data(&cd_header); + free_cache_data(&cd_page); +@@ -8237,8 +8337,15 @@ retry: + * to create a dumpfile with it again. + */ + num_retry++; +- if ((info->dump_level = get_next_dump_level(num_retry)) < 0) +- return FALSE; ++ if ((info->dump_level = get_next_dump_level(num_retry)) < 0) { ++ if (!info->flag_flatten) { ++ if (check_and_modify_headers()) ++ MSG("This is an incomplete dumpfile," ++ " but might analyzable.\n"); ++ } ++ ++ return FALSE; ++ } + MSG("Retry to create a dumpfile by dump_level(%d).\n", + info->dump_level); + if (!delete_dumpfile()) +-- +1.7.1 + diff --git a/SOURCES/kexec-tools-2.0.8-ppc64-erase-unnecessary-segment-info-printing.patch b/SOURCES/kexec-tools-2.0.8-ppc64-erase-unnecessary-segment-info-printing.patch new file mode 100644 index 0000000..8f6a286 --- /dev/null +++ b/SOURCES/kexec-tools-2.0.8-ppc64-erase-unnecessary-segment-info-printing.patch @@ -0,0 +1,30 @@ +In ppc64 loading, it will print the segment information. This is not +wanted since other Archs don't have this. People even think there's +something wrong. So erase it to make it be consistent with other Archs. + +And if people really want to check these info, they can specify "-d" +option. They are printed in print_segments() too. + +Signed-off-by: Baoquan He +--- + kexec/arch/ppc64/kexec-elf-ppc64.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/kexec/arch/ppc64/kexec-elf-ppc64.c b/kexec/arch/ppc64/kexec-elf-ppc64.c +index ce10367..4a1540e 100644 +--- a/kexec/arch/ppc64/kexec-elf-ppc64.c ++++ b/kexec/arch/ppc64/kexec-elf-ppc64.c +@@ -377,10 +377,6 @@ int elf_ppc64_load(int argc, char **argv, const char *buf, off_t len, + dbgprintf("opal_base is %llx\n", (unsigned long long) my_opal_base); + dbgprintf("opal_entry is %llx\n", (unsigned long long) my_opal_entry); + +- for (i = 0; i < info->nr_segments; i++) +- fprintf(stderr, "segment[%d].mem:%p memsz:%zu\n", i, +- info->segment[i].mem, info->segment[i].memsz); +- + return 0; + } + +-- +1.9.0 + diff --git a/SOURCES/mkdumprd b/SOURCES/mkdumprd index 8297600..dd6ce8a 100644 --- a/SOURCES/mkdumprd +++ b/SOURCES/mkdumprd @@ -17,7 +17,7 @@ SAVE_PATH=$(grep ^path $conf_file| cut -d' ' -f2) SAVE_PATH=$(echo $SAVE_PATH | tr -s /) extra_modules="" -dracut_args=("--hostonly" "--hostonly-cmdline" "-o" "plymouth dash resume") +dracut_args=("--hostonly" "--hostonly-cmdline" "--hostonly-i18n" "-o" "plymouth dash resume ifcfg") OVERRIDE_RESETTABLE=0 perror_exit() { @@ -117,6 +117,9 @@ to_mount() { _fstype=$(findmnt -k -f -n -r -o FSTYPE $_dev) _options=$(findmnt --fstab -f -n -r -o OPTIONS $_dev) [ -z "$_options" ] && _options=$(findmnt -k -f -n -r -o OPTIONS $_dev) + # with 'noauto' in fstab nfs and non-root disk mount will fail in 2nd + # kernel, filter it out here. + _options=$(echo $_options | sed 's/noauto//') _options=${_options/#ro/rw} #mount fs target as rw in 2nd kernel # "x-initrd.mount" mount failure will trigger isolate emergency service # W/o this, systemd won't isolate, thus we won't get to emergency. diff --git a/SPECS/kexec-tools.spec b/SPECS/kexec-tools.spec index 16112e7..f12a449 100644 --- a/SPECS/kexec-tools.spec +++ b/SPECS/kexec-tools.spec @@ -1,6 +1,6 @@ Name: kexec-tools Version: 2.0.7 -Release: 19%{?dist}.2 +Release: 38%{?dist} License: GPLv2 Group: Applications/System Summary: The kexec/kdump userspace component. @@ -20,14 +20,16 @@ Source14: 98-kexec.rules Source15: kdump.conf.5 Source16: kdump.service Source18: kdump.sysconfig.s390x -Source19: eppic_030413.tar.gz +Source19: eppic_050615.tar.gz Source20: kdump-lib.sh Source21: kdump-in-cluster-environment.txt Source22: supported-kdump-targets.txt Source23: kdump-dep-generator.sh Source24: kdump-lib-initramfs.sh -Source25: kdump-anaconda-addon-003-11-g7f70211.tar.gz +Source25: kdump-anaconda-addon-003-19-gda64a86.tar.gz Source26: kdump.sysconfig.ppc64le +Source27: kdump.sysconfig.aarch64 +Source28: kdumpctl.8 ####################################### # These are sources for mkdumpramfs @@ -45,17 +47,15 @@ Requires(post): systemd-units Requires(preun): systemd-units Requires(postun): systemd-units Requires(pre): coreutils sed zlib -Requires: dracut >= 033-145 +Requires: dracut >= 033-346 Requires: dracut-network, ethtool BuildRequires: zlib-devel zlib zlib-static elfutils-devel-static glib2-devel bzip2-devel ncurses-devel bison flex lzo-devel snappy-devel BuildRequires: pkgconfig intltool gettext BuildRequires: systemd-units -%ifarch %{ix86} x86_64 ppc64 ia64 ppc s390x ppc64le +%ifarch %{ix86} x86_64 ppc64 ia64 ppc s390x ppc64le aarch64 Obsoletes: diskdumputils netdump %endif -ExcludeArch: aarch64 - #START INSERT @@ -78,6 +78,7 @@ Patch101: kexec-tools-2.0.7-Provide-an-option-to-use-new-kexec-system-call.patch Patch301: kexec-tools-2.0.7-kexec-ppc64-disabling-exception-handling-when-buildi.patch Patch302: kexec-tools-2.0.7-kexec-ppc64-move-to-device-tree-version-17.patch Patch303: kexec-tools-2.0.7-ppc64-kdump-Fix-ELF-header-endianess.patch +Patch304: kexec-tools-2.0.8-ppc64-erase-unnecessary-segment-info-printing.patch # # Patches 401 through 500 are meant for s390 kexec-tools enablement @@ -91,6 +92,39 @@ Patch303: kexec-tools-2.0.7-ppc64-kdump-Fix-ELF-header-endianess.patch # Patch601: kexec-tools-2.0.3-disable-kexec-test.patch Patch602: kexec-tools-2.0.7-makedumpfile-sadump-Support-more-than-16TB-physical-memory.patch +Patch603: kexec-tools-2.0.7-makedumpfile-Support-ARM64.patch + +Patch650: kexec-tools-2.0.8-add-aarch64-to-configure.patch +Patch651: kexec-tools-2.0.8-kexec-Add-common-device-tree-routines.patch +Patch652: kexec-tools-2.0.8-arm64-Add-arm64-kexec-support.patch +Patch653: kexec-tools-2.0.8-arm64-Add-support-for-reuse-cmdline-option.patch +Patch654: kexec-tools-2.0.8-arm64-Add-support-for-kexec-lite-option.patch +Patch655: kexec-tools-2.0.8-arm64-Kexec-Add-support-for-binary-image.patch +Patch656: kexec-tools-2.0.8-bugfix-calc-correct-end-address-of-memory-ranges-in-.patch +Patch657: kexec-tools-2.0.8-arm64-fix-elf-related-header-issues.patch +Patch658: kexec-tools-2.0.8-arm64-kdump-create-elf-core-header.patch +Patch659: kexec-tools-2.0.8-arm64-kdump-append-kdump-specific-parameter-to-comma.patch +Patch660: kexec-tools-2.0.8-arm64-kdump-copy-dtb-file-into-crash-kernel-memory.patch +Patch661: kexec-tools-2.0.8-arm64-pass-mem-parameter-to-a-crash-dump-kernel.patch +Patch662: kexec-tools-2.0.8-arm64-clean-up-on-crash-dump.patch +Patch663: kexec-tools-2.0.8-arm64-remove-restriction-on-the-segments-order.patch +Patch664: kexec-tools-2.0.8-arm64-kdump-Add-support-for-binary-image.patch +Patch665: kexec-tools-2.0.8-arm64-wait-for-transmit-completion-before-next-chara.patch +Patch667: kexec-tools-2.0.8-Don-t-bail-out-if-check_cpu_nodes-fails.patch +Patch668: kexec-tools-2.0.8-arm64-Add-enable-disable-d-cache-support-for-purgato.patch +Patch669: kexec-tools-2.0.8-arm64-Pass-RAM-boundary-to-purgatory.patch +Patch670: kexec-tools-2.0.8-arm64-Enable-disable-D-cache-before-after-sha-verifi.patch + +Patch671: kexec-tools-2.0.8-makedumpfile-Make-get_elf64_phdr-get_elf32_phdr-publ.patch +Patch672: kexec-tools-2.0.8-makedumpfile-Make-the-incomplete-dumpfile-generated-.patch +Patch673: kexec-tools-2.0.8-makedumpfile-Implementation-of-dealing-with-kdump-co.patch +Patch674: kexec-tools-2.0.8-makedumpfile-Fix-reassemble_kdump_header.patch + +Patch675: kexec-tools-2.0.8-makedumpfile-Add-support-for-splitblock.patch +Patch676: kexec-tools-2.0.8-makedumpfile-Add-tools-for-reading-and-writing-from-.patch +Patch677: kexec-tools-2.0.8-makedumpfile-Add-module-of-generating-table.patch +Patch678: kexec-tools-2.0.8-makedumpfile-Add-module-of-calculating-start_pfn-and.patch +Patch679: kexec-tools-2.0.8-makedumpfile-Add-support-for-splitblock-size.patch # # Patch 701 through 800 are meant for kdump anaconda addon @@ -103,7 +137,7 @@ normal or a panic reboot. This package contains the /sbin/kexec binary and ancillary utilities that together form the userspace component of the kernel's kexec feature. -%ifarch %{ix86} x86_64 ia64 ppc64 s390x ppc64le +%ifarch %{ix86} x86_64 ia64 ppc64 s390x ppc64le aarch64 %package eppic Requires: %{name} = %{version}-%{release} Summary: Additional eppic_makedumpfile.so shared object @@ -134,8 +168,39 @@ tar -z -x -v -f %{SOURCE25} %patch301 -p1 %patch302 -p1 %patch303 -p1 +%patch304 -p1 %patch601 -p1 %patch602 -p1 +%patch603 -p1 +%patch650 -p1 +%patch651 -p1 +%patch652 -p1 +%patch653 -p1 +%patch654 -p1 +%patch655 -p1 +%patch656 -p1 +%patch657 -p1 +%patch658 -p1 +%patch659 -p1 +%patch660 -p1 +%patch661 -p1 +%patch662 -p1 +%patch663 -p1 +%patch664 -p1 +%patch665 -p1 +%patch667 -p1 +%patch668 -p1 +%patch669 -p1 +%patch670 -p1 +%patch671 -p1 +%patch672 -p1 +%patch673 -p1 +%patch674 -p1 +%patch675 -p1 +%patch676 -p1 +%patch677 -p1 +%patch678 -p1 +%patch679 -p1 %ifarch ppc @@ -143,12 +208,13 @@ tar -z -x -v -f %{SOURCE25} %endif %build -%ifarch ia64 +%ifarch ia64 aarch64 # ia64 gcc seems to have a problem adding -fexception -fstack-protect and -# -param ssp-protect-size, like the %configure macro does +# -param ssp-protect-size, like the configure macro does # while that shouldn't be a problem, and it still builds fine, it results in # the kdump kernel hanging on kexec boot. I don't yet know why, but since those # options aren't critical, I'm just overrideing them here for ia64 +# aarch64 does not like -fexception as well, so overwrite it. export CFLAGS="-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2" %endif @@ -169,7 +235,7 @@ cp %{SOURCE21} . cp %{SOURCE22} . make -%ifarch %{ix86} x86_64 ia64 ppc64 s390x ppc64le +%ifarch %{ix86} x86_64 ia64 ppc64 s390x ppc64le aarch64 make -C eppic/libeppic make -C makedumpfile-1.5.7 LINKTYPE=dynamic USELZO=on USESNAPPY=on make -C makedumpfile-1.5.7 LDFLAGS="-I../eppic/libeppic -L../eppic/libeppic" eppic_makedumpfile.so @@ -200,6 +266,7 @@ install -m 755 %{SOURCE7} $RPM_BUILD_ROOT/sbin/mkdumprd install -m 644 %{SOURCE8} $RPM_BUILD_ROOT%{_sysconfdir}/kdump.conf install -m 644 kexec/kexec.8 $RPM_BUILD_ROOT%{_mandir}/man8/kexec.8 install -m 644 %{SOURCE12} $RPM_BUILD_ROOT%{_mandir}/man8/mkdumprd.8 +install -m 644 %{SOURCE28} $RPM_BUILD_ROOT%{_mandir}/man8/kdumpctl.8 install -m 755 %{SOURCE20} $RPM_BUILD_ROOT%{_prefix}/lib/kdump/kdump-lib.sh install -m 755 %{SOURCE24} $RPM_BUILD_ROOT%{_prefix}/lib/kdump/kdump-lib-initramfs.sh %ifnarch s390x @@ -211,7 +278,7 @@ install -m 644 %{SOURCE15} $RPM_BUILD_ROOT%{_mandir}/man5/kdump.conf.5 install -m 644 %{SOURCE16} $RPM_BUILD_ROOT%{_unitdir}/kdump.service install -m 755 -D %{SOURCE23} $RPM_BUILD_ROOT%{_prefix}/lib/systemd/system-generators/kdump-dep-generator.sh -%ifarch %{ix86} x86_64 ia64 ppc64 s390x ppc64le +%ifarch %{ix86} x86_64 ia64 ppc64 s390x ppc64le aarch64 install -m 755 makedumpfile-1.5.7/makedumpfile $RPM_BUILD_ROOT/sbin/makedumpfile install -m 644 makedumpfile-1.5.7/makedumpfile.8.gz $RPM_BUILD_ROOT/%{_mandir}/man8/makedumpfile.8.gz install -m 644 makedumpfile-1.5.7/makedumpfile.conf.5.gz $RPM_BUILD_ROOT/%{_mandir}/man5/makedumpfile.conf.5.gz @@ -323,7 +390,7 @@ done %{_bindir}/* %{_datadir}/kdump %{_prefix}/lib/kdump -%ifarch %{ix86} x86_64 ia64 ppc64 s390x ppc64le +%ifarch %{ix86} x86_64 ia64 ppc64 s390x ppc64le aarch64 %{_sysconfdir}/makedumpfile.conf.sample %endif %config(noreplace,missingok) %{_sysconfdir}/sysconfig/kdump @@ -344,7 +411,7 @@ done %doc kdump-in-cluster-environment.txt %doc supported-kdump-targets.txt -%ifarch %{ix86} x86_64 ia64 ppc64 s390x ppc64le +%ifarch %{ix86} x86_64 ia64 ppc64 s390x ppc64le aarch64 %files eppic %{_libdir}/eppic_makedumpfile.so /usr/share/makedumpfile/eppic_scripts/ @@ -352,10 +419,74 @@ done %files anaconda-addon -f kdump-anaconda-addon.lang %{_datadir}/anaconda/addons/com_redhat_kdump +%{_datadir}/icons/hicolor/scalable/apps/kdump.svg %doc %changelog -* Tue Apr 21 2015 Baoquan He - 2.0.7-19.2 +* Wed Oct 21 2015 Minfei Huang - 2.0.7-38 +- pc64/ppc64le: drop cpu online rule in 40-redhat.rules in kdump initramfs + +* Fri Sep 18 2015 Minfei Huang - 2.0.7-37 +- mkdumprd: install only local i18n files + +* Wed Sep 9 2015 Minfei Huang - 2.0.7-36 +- Update kdump anaconda addon + +* Wed Aug 19 2015 Minfei Huang - 2.0.7-35 +- kdumpctl: Add man page for kdumpctl + +* Fri Aug 14 2015 Baoquan He - 2.0.7-34 +arm64: Overwrite CFLAGS and remove -fno-exceptions from kexec purgatory code +Fix comment to exclude keyword %configure +Revert "arm64: move -fno-exceptions from purgatory code to spec file" + +* Fri Aug 14 2015 Baoquan He - 2.0.7-33 +mkdumprd: Remove ifcfg from dracut's modules +arm64: move -fno-exceptions from purgatory code to spec file +module-setup: Choose the first matched gateway in kdump_static_ip + +* Fri Aug 7 2015 Minfei Huang - 2.0.7-32 +- Enhance Kdump to support ipv6 protocol + +* Wed Aug 5 2015 Minfei Huang - 2.0.7-31 +- ppc64: Erase unnecessary segment info printing +- Update kdump addon + +* Tue Jul 28 2015 Minfei Huang - 2.0.7-30 +- watchdog: load iTCO_wdt early in cmdline hook + +* Thu Jul 23 2015 Minfei Huang - 2.0.7-29 +- Update kdump addon tarball + +* Mon Jul 13 2015 Minfei Huang - 2.0.7-28 +- eppic: update to include ARM64 support +- Update kdump addon icon + +* Tue Jul 7 2015 Minfei Huang - 2.0.7-27 +- dracut-module-setup: Apply the manual DNS to the 2nd kernel +- makedumpfile: --split: assign fair I/O workloads in appropriate time +- makedumpfile: Support producing a consistent dump file even if disk space is insufficient +- Disable transparent hugepages in second kernel + +* Tue Jun 23 2015 Minfei Huang - 2.0.7-26 +- kdumpctl: Add the command "kdumpctl showmem" to show the reserved memory +- Enhance kdump.conf "default" parameters check. +- Filtered out "noauto" options in 2nd kernel fstab +- make kdump work when kernel crash after shutdown + +* Wed Jun 10 2015 Dave Young - 2.0.7-25 +- Update kdump addon tarball + +* Mon May 18 2015 Minfei Huang - 2.0.7-24 +- Enhance kdump to support ARM64 arch + +* Mon May 18 2015 Minfei Huang - 2.0.7-23 +- Fix the date for the changelog + +* Mon May 18 2015 Minfei Huang - 2.0.7-22 +- remove panic_on_warn from 2nd kernel cmdline + +* Tue Apr 21 2015 Baoquan He - 2.0.7-21 - dracut-module-setup: Enhance kdump to support the bind mounted feature in Atomic - Fix the warning if the target path is bind mount in Atomic - Get the mount point correctly, if the device has several mount point @@ -363,8 +494,9 @@ done - kdump-lib: Add the new function to enhance bind mounted judgement - Remove duplicate slash in save path - dracut-module-setup.sh: change the insecure use of /tmp/*$$* filenames +- make kdump saving directory name consistent with RHEL6 -* Fri Apr 10 2015 Baoquan He - 2.0.7-19.1 +* Thu Apr 09 2015 Baoquan He - 2.0.7-20 - sadump: Support more than 16TB physical memory space. * Fri Feb 6 2015 Dave Young - 2.0.7-19