1#!/bin/bash 2# 3# Test script for KVM RAS 4# 5# This program is free software; you can redistribute it and/or 6# modify it under the terms of the GNU General Public 7# License as published by the Free Software Foundation; version 8# 2. 9# 10# This program is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13# General Public License for more details. 14# 15# You should find a copy of v2 of the GNU General Public License somewhere 16# on your Linux system; if not, write to the Free Software Foundation, 17# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18# 19# Copyright (C) 2010, Intel Corp. 20# Author: Jiajia Zheng <jiajia.zheng@intel.com> 21# 22 23image="" 24mce_inject_file="" 25 26HOST_DIR=`pwd` 27GUEST_DIR="/test" 28early_kill="1" 29RAM_size="" 30 31kernel="" 32initrd="" 33root="" 34 35usage() 36{ 37 echo "Usage: ./host_run.sh [-options] [arguments]" 38 echo "================Below are the must have options===============" 39 echo -e "\t-i image\t: guest image" 40 echo -e "\t-f mcefile\t: which mce data file to inject" 41 echo "================Below are the optional options================" 42 echo -e "\t-d hostdir\t: where you put the test scripts on host system" 43 echo -e "\t\t\tBe careful to change it" 44 echo -e "\t-g guestdir\t: where you put the test scripts on guest system" 45 echo -e "\t\t\tBy default, guestdir is set to $GUEST_DIR" 46 echo -e "\t-o offset\t: guest image offset" 47 echo -e "\t\t\tBy default, offset is calculated by kpartx " 48 echo -e "\t-l\t\t: late kill, disable early kill in guest system" 49 echo -e "\t\t\tBy default, earlykill is enabled " 50 echo -e "\t-m ramsize\t: virtual RAM size of guest system" 51 echo -e "\t\t\tBy default, qemu-kvm defaults to 512M bytes" 52 echo -e "\t-h\t\t: show this help" 53 echo "============If you want to specify the guest kernel===========" 54 echo "============please set below options all together=============" 55 echo -e "\t-k kernel\t: guest kernel" 56 echo -e "\t-n initrd\t: guest initrd" 57 echo -e "\t-r root\t\t: guest root partition" 58 exit 0 59} 60 61while getopts "i:f:d:g:o:b:p:k:n:r:hlm:" option 62do 63 case $option in 64 i) image=$OPTARG;; 65 f) mce_inject_file=$OPTARG;; 66 d) HOST_DIR=$OPTARG;; 67 g) GUEST_DIR=$OPTARG;; 68 o) offset=$OPTARG;; 69 l) early_kill="0";; 70 k) kernel=$OPTARG;; 71 n) initrd=$OPTARG;; 72 r) root=$OPTARG;; 73 m) RAM_size=$OPTARG;; 74 h) usage;; 75 *) echo 'invalid option!'; usage;; 76 esac 77done 78 79 80guest_script=$GUEST_DIR/guest_run.sh 81guest_tmp=$GUEST_DIR/guest_tmp 82guest_page=$GUEST_DIR/guest_page 83GUEST_PHY="" 84 85host_key_pub=$HOST_DIR/id_rsa.pub 86host_key_priv=$HOST_DIR/id_rsa 87guest_init=$HOST_DIR/guest_init 88host_start=$HOST_DIR/host_start 89pid_file=$HOST_DIR/pid_file 90monitor_console_output=$HOST_DIR/monitor_console_output 91serial_console_output=$HOST_DIR/serial_console_output 92host_tmp=$HOST_DIR/host_tmp 93mce_inject_data=$HOST_DIR/mce_inject_data 94monitor_console="" 95serial_console="" 96 97 98invalid() 99{ 100 echo $1 101 echo "Try ./host_run.sh -h for more information." 102 exit 0 103} 104 105check_env() 106{ 107 if [ "`whoami`" != "root" ]; then 108 echo "Must run as root" 109 exit 1 110 fi 111 112 if modinfo mce_inject &> /dev/null; then 113 if ! lsmod | grep -q mce_inject; then 114 if ! modprobe mce_inject; then 115 invalid "module mce_inject isn't supported ?" 116 fi 117 fi 118 fi 119 120 which kpartx &>/dev/null 121 [ ! $? -eq 0 ] && invalid "please install kpartx tool!" 122 which mce-inject &>/dev/null 123 [ ! $? -eq 0 ] && invalid "please install mce-inject tool!" 124 125 [ -z $RAM_size ] && RAM_size=512 126 [ -z $image ] && invalid "please input the guest image!" 127 [ ! -e $image ] && invalid "guest image $image does not exist!" 128 [ -z $mce_inject_file ] && invalid "please input the mce data file!" 129 [ ! -e $mce_inject_file ] && invalid "mce data file $mce_inject_file does not exist!" 130 131 [ ! -e $host_key_pub ] && invalid "host public key does not exist!" 132 [ ! -e $host_key_priv ] && invalid "host privite key does not exist!" 133 chmod 600 $host_key_pub 134 chmod 600 $host_key_priv 135} 136 137mount_image() 138{ 139 mnt=`mktemp -d` 140 offset=`kpartx -l $image | awk '/loop deleted/ {next}; \ 141 {offset=$NF*512}; END {print offset}'` 142 mount_err=`mount -oloop,offset=$offset $image $mnt 2>&1` 143 if [ $? -eq 0 ]; then 144 fs_type=unset 145 echo "mount image to $mnt" 146 return 0 147 fi 148 149 #See if we're dealing with a LVM filesystem type 150 fs_type=`echo $mount_err | awk '/^mount: unknown filesystem type/ {print $NF}'` 151 if [ $fs_type != "'LVM2_member'" ]; then 152 echo unknown filesystem type 153 rm -rf $mnt 154 return 1 155 fi 156 157 which losetup &>/dev/null 158 [ ! $? -eq 0 ] && invalid "please install losetup tool!" 159 which pvdisplay &>/dev/null 160 [ ! $? -eq 0 ] && invalid "please install pvdisplay tool!" 161 which vgchange &>/dev/null 162 [ ! $? -eq 0 ] && invalid "please install vgchange tool!" 163 164 #Try mounting the LVM image 165 loop_dev=`losetup -o ${offset} -f --show ${image}` 166 if [ -z ${loop_dev} ]; then 167 echo no available loop device 168 rm -rf $mnt 169 return 1 170 fi 171 vg=`pvdisplay ${loop_dev} | awk '/ VG Name/ {print $NF}'` 172 lv=lv_root 173 vgchange -a ey ${vg} 174 if [ ! -b /dev/mapper/${vg}-${lv} ]; then 175 echo '! block special' 176 losetup -d ${loop_dev} 177 rm -rf $mnt 178 return 1 179 fi 180 mount /dev/mapper/${vg}-${lv} $mnt 181 if [ $? -ne 0 ]; then 182 vgchange -a en ${vg} 183 losetup -d ${loop_dev} 184 rm -rf $mnt 185 return 1 186 fi 187 echo "mount LVM image to $mnt" 188 return 0 189} 190 191umount_image() 192{ 193 umount $mnt 194 sleep 2 195 if [ $fs_type = "'LVM2_member'" ]; then 196 vgchange -a en ${vg} 197 losetup -d ${loop_dev} 198 fi 199 rm -rf $mnt 200} 201 202#Guest Image Preparation 203image_prepare() 204{ 205 local i 206 207 mount_image 208 if [ $? -ne 0 ]; then 209 echo 'mount of image failed!' 210 return 1 211 fi 212 i=`grep id:.*:initdefault $mnt/etc/inittab |cut -d':' -f2` 213 rm -f $mnt/etc/rc${i}.d/S99kvm_ras 214 rm -f $mnt/$guest_tmp $mnt/$guest_page 215 216 if [ ! -d $mnt/root/.ssh ]; then 217 mkdir $mnt/root/.ssh 218 chmod 700 $mnt/root/.ssh 219 fi 220 mkdir -p $mnt/$GUEST_DIR 221 cp ../guest/guest_run.sh $mnt/$GUEST_DIR 222 gcc -o simple_process ../../tools/simple_process/simple_process.c 223 gcc -o page-types ../../tools/page-types.c 224 cp simple_process $mnt/$GUEST_DIR 225 cp page-types $mnt/$GUEST_DIR 226 sed -i -e "s#GUEST_DIR#$GUEST_DIR#g" $mnt/$guest_script 227 cat $host_key_pub >> $mnt/root/.ssh/authorized_keys 228 kvm_ras=/etc/init.d/kvm_ras 229 sed -e "s#EARLYKILL#$early_kill#g" \ 230 -e "s#GUESTRUN#$guest_script#g" $guest_init > $mnt/$kvm_ras 231 chmod a+x $mnt/$kvm_ras 232 ln -s $kvm_ras $mnt/etc/rc${i}.d/S99kvm_ras 233 sleep 2 234 umount_image 235 return 0 236} 237 238#Start guest system 239start_guest() 240{ 241 if [ ! -z $kernel ]; then 242 if [ ! -z $initrd ]; then 243 if [ ! -z $root ]; then 244 append="root=$root ro loglevel=8 mce=3 console=ttyS0,115200n8 console=tty0" 245 qemu-system-x86_64 -hda $image -kernel $kernel -initrd $initrd --append "$append" \ 246 -m $RAM_size -net nic,model=rtl8139 -net user,hostfwd=tcp::5555-:22 \ 247 -monitor pty -serial pty -pidfile $pid_file > $host_start 2>&1 & 248 sleep 5 249 else 250 invalid "please specify the guest root partition!" 251 fi 252 else 253 invalid "please specify the guest initrd!" 254 fi 255 else 256 echo "Start the default kernel on guest system" 257 qemu-system-x86_64 -hda $image \ 258 -m $RAM_size -net nic,model=rtl8139 -net user,hostfwd=tcp::5555-:22 \ 259 -monitor pty -serial pty -pidfile $pid_file > $host_start 2>&1 & 260 sleep 5 261 fi 262 monitor_console=`awk '{print $NF}' $host_start | sed -n -e '1p'` 263 serial_console=`awk '{print $NF}' $host_start | sed -n -e '2p'` 264 QEMU_PID=`cat $pid_file` 265 echo "monitor console is $monitor_console" 266 echo "serial console is $serial_console" 267 echo "Waiting for guest system start up..." 268} 269 270check_guest_alive() 271{ 272 for i in 1 2 3 4 5 6 7 8 9 273 do 274 sleep 10 275 ssh -i $host_key_priv -o StrictHostKeyChecking=no localhost -p 5555 echo "" > /dev/null 2>&1 276 if [ $? -eq 0 ]; then 277 return 0 278 else 279 echo "Waiting..." 280 fi 281 done 282 return 1 283} 284 285addr_translate() 286{ 287 #Get Guest physical address 288 scp -o StrictHostKeyChecking=no -i $host_key_priv -P 5555 \ 289 localhost:$guest_tmp $HOST_DIR/guest_tmp > /dev/null 2>&1 290 if [ $? -ne 0 ]; then 291 echo "Failed to get Guest physical address, quit testing!" 292 kill -9 $QEMU_PID 293 exit 0 294 fi 295 sleep 2 296 GUEST_PHY=`awk '{print $NF}' $HOST_DIR/guest_tmp` 297 echo "Guest physical address is $GUEST_PHY" 298 sleep 2 299 300 #Get Host virtual address 301 echo x-gpa2hva $GUEST_PHY > $monitor_console 302 cat $monitor_console > $monitor_console_output & 303 sleep 5 304 HOST_VIRT=`awk '/qemu|QEMU/{next} {print $NF}' $monitor_console_output |cut -b 3-11` 305 echo "Host virtual address is $HOST_VIRT" 306 307 #Get Host physical address 308 ./page-types -p $QEMU_PID -LN -b anon | grep $HOST_VIRT > $host_tmp 309 sleep 5 310 ADDR=`cat $host_tmp | awk '{print "0x"$2"000"}' ` 311 echo "Host physical address is $ADDR" 312} 313 314error_inj() 315{ 316 #Inject SRAO error 317 cat $mce_inject_file > $mce_inject_data 318 echo "ADDR $ADDR" >> $mce_inject_data 319 echo "calling mce-inject $mce_inject_data" 320 mce-inject $mce_inject_data 321} 322 323 324get_guest_klog() 325{ 326 cat $serial_console > $serial_console_output & 327} 328 329check_guest_klog() 330{ 331 GUEST_PHY_KLOG=`echo $GUEST_PHY | sed 's/000$//'` 332 echo "Guest physical klog address is $GUEST_PHY_KLOG" 333 cat $serial_console_output | grep "MCE $GUEST_PHY_KLOG" 334 if [ $? -ne 0 ]; then 335 return 1 336 fi 337 return 0 338} 339 340 341 342check_env 343image_prepare 344if [ $? -ne 0 ]; then 345 echo 'Mount Guest image failed, quit testing!' 346else 347 start_guest 348 get_guest_klog 349 check_guest_alive 350 if [ $? -ne 0 ]; then 351 echo 'Start Guest system failed, quit testing!' 352 else 353 sleep 5 354 addr_translate 355 error_inj 356 sleep 5 357 check_guest_klog 358 if [ $? -ne 0 ]; then 359 echo 'FAIL: Did not get expected log!' 360 kill -9 $QEMU_PID 361 exit 1 362 else 363 echo 'PASS: Inject error into guest!' 364 fi 365 sleep 10 366 check_guest_alive 367 if [ $? -ne 0 ]; then 368 echo 'FAIL: Guest System could have died!' 369 else 370 echo 'PASS: Guest System alive!' 371 fi 372 fi 373fi 374 375rm -f guest_tmp $host_start $monitor_console_output $serail_console_output $host_tmp $pid_file $mce_inject_data 376rm -f ./simple_process ./page-types 377