• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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