• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/bin/sh -e
2# SPDX-License-Identifier: GPL-2.0-only
3
4# hyp-trace-test - Tracefs for pKVM hypervisor test
5#
6# Copyright (C) 2024 - Google LLC
7# Author: Vincent Donnefort <vdonnefort@google.com>
8#
9
10log_and_die()
11{
12    echo "$1"
13
14    exit 1
15}
16
17host_clock()
18{
19    # BOOTTIME clock
20    awk '/now/ { printf "%.6f\n", $3 / 1000000000 }' /proc/timer_list
21}
22
23page_size()
24{
25    echo "$(awk '/KernelPageSize/ {print $2; exit}' /proc/self/smaps) * 1024" | bc
26}
27
28goto_hyp_trace()
29{
30    if [ -d "/sys/kernel/debug/tracing/hypervisor" ]; then
31        cd /sys/kernel/debug/tracing/hypervisor
32        return
33    fi
34
35    if [ -d "/sys/kernel/tracing/hypervisor" ]; then
36        cd /sys/kernel/tracing/hypervisor
37        return
38    fi
39
40    echo "ERROR: hyp tracing folder not found!"
41
42    exit 1
43}
44
45reset_hyp_trace()
46{
47    echo 0 > tracing_on
48    echo 0 > trace
49    for event in events/hypervisor/*; do
50        echo 0 > $event/enable
51    done
52}
53
54setup_hyp_trace()
55{
56    reset_hyp_trace
57
58    echo 16 > buffer_size_kb
59    echo 1 > events/hypervisor/selftest/enable
60    echo 1 > tracing_on
61}
62
63stop_hyp_trace()
64{
65    echo 0 > tracing_on
66}
67
68hyp_trace_loaded()
69{
70    grep -q "(loaded)" buffer_size_kb
71}
72
73write_events()
74{
75    local num="$1"
76    local func="$2"
77
78    for i in $(seq 1 $num); do
79        echo 1 > selftest_event
80        [ -z "$func" -o $i -eq $num ] || eval $func
81    done
82}
83
84consuming_read()
85{
86    local output=$1
87
88    cat trace_pipe > $output &
89
90    echo $!
91}
92
93run_test_consuming()
94{
95    local nr_events=$1
96    local func=$2
97    local tmp="$(mktemp)"
98    local start_ts=0
99    local end_ts=0
100    local pid=0
101
102    echo "Output trace file: $tmp"
103
104    setup_hyp_trace
105    pid=$(consuming_read $tmp)
106
107    start_ts=$(host_clock)
108    write_events $nr_events $func
109    stop_hyp_trace
110    end_ts=$(host_clock)
111
112    kill $pid
113    validate_test $tmp $nr_events $start_ts $end_ts
114
115    rm $tmp
116}
117
118validate_test()
119{
120    local output=$1
121    local expected_events=$2
122    local start_ts=$3
123    local end_ts=$4
124    local prev_ts=$3
125    local ts=0
126    local num_events=0
127
128    IFS=$'\n'
129    for line in $(cat $output); do
130        echo "$line" | grep -q -E "^# " && continue
131        ts=$(echo "$line" | awk '{print $2}' | cut -d ':' -f1)
132        if [ $(echo "$ts<$prev_ts" | bc) -eq 1 ]; then
133            log_and_die "Error event @$ts < $prev_ts"
134        fi
135        prev_ts=$ts
136        num_events=$((num_events + 1))
137    done
138
139    if [ $(echo "$ts>$end_ts" | bc) -eq 1 ]; then
140        log_and_die "Error event @$ts > $end_ts"
141    fi
142
143    if [ $num_events -ne $expected_events ]; then
144        log_and_die "Expected $expected_events events, got $num_events"
145    fi
146}
147
148test_ts()
149{
150    echo "Test Timestamps..."
151
152    run_test_consuming 1000
153
154    echo "done."
155}
156
157test_extended_ts()
158{
159    echo "Test Extended Timestamps..."
160
161    run_test_consuming 1000 "sleep 0.1"
162
163    echo "done."
164}
165
166assert_loaded()
167{
168    hyp_trace_loaded || log_and_die "Expected loaded buffer"
169}
170
171assert_unloaded()
172{
173    ! hyp_trace_loaded || log_and_die "Expected unloaded buffer"
174}
175
176test_unloading()
177{
178    local tmp="$(mktemp)"
179
180    echo "Test unloading..."
181
182    setup_hyp_trace
183    assert_loaded
184
185    echo 0 > tracing_on
186    assert_unloaded
187
188    pid=$(consuming_read $tmp)
189    sleep 1
190    assert_loaded
191    kill $pid
192    assert_unloaded
193
194    echo 1 > tracing_on
195    write_events 1
196    echo 0 > trace
197    assert_loaded
198    echo 0 > tracing_on
199    assert_unloaded
200
201    echo "done."
202}
203
204test_reset()
205{
206    local tmp="$(mktemp)"
207
208    echo "Test Reset..."
209
210    setup_hyp_trace
211    write_events 1000
212    echo 0 > trace
213    clock_before=$(host_clock)
214    write_events 5
215
216    pid=$(consuming_read $tmp)
217    sleep 1
218    stop_hyp_trace
219    kill $pid
220
221    validate_test $tmp 5 $clock_before $(host_clock)
222
223    rm $tmp
224
225    echo "done."
226}
227
228test_big_bpacking()
229{
230    local hyp_buffer_page_size=48
231    local page_size=$(page_size)
232    local min_buf_size=$(echo "$page_size * $page_size / ($hyp_buffer_page_size * $(nproc))" | bc)
233
234    min_buf_size=$(echo "$min_buf_size * 2 / 1024" | bc)
235
236    echo "Test loading $min_buf_size kB buffer..."
237
238    reset_hyp_trace
239    echo $min_buf_size > buffer_size_kb
240    echo 1 > tracing_on
241
242    stop_hyp_trace
243
244    echo "done."
245}
246
247validate_event()
248{
249    local line="$1"
250    local expect_event="$2"
251    local expect_arg="$3"
252    local event="$(echo "$line" | awk '{print $3}')"
253    local arg="$(echo "$line" | awk '{print $4}')"
254
255    [ $event == $expect_event ] || log_and_die "Expected event '$expect_event', got: '$event'"
256    [ $arg == $expect_arg ] || log_and_die "Expected arg '$expect_arg', got: '$arg'"
257}
258
259setup_hyp_ftrace()
260{
261    reset_hyp_trace
262    echo 1 > events/hypervisor/func/enable
263    echo 1 > events/hypervisor/func_ret/enable
264}
265
266run_test_ftrace()
267{
268    local output="$2"
269
270    setup_hyp_ftrace
271
272    echo 1 > tracing_on
273    write_events 1
274    echo 0 > tracing_on
275
276    pid=$(consuming_read $tmp)
277    sleep 1
278    kill $pid
279
280}
281
282test_ftrace_nofilter()
283{
284    local func="__kvm_nvhe_handle___pkvm_selftest_event"
285    local tmp="$(mktemp)"
286
287    echo "Test ftrace..."
288
289    echo "*" > set_ftrace_filter
290
291    run_test_ftrace $tmp
292
293    grep -qE "func *$func" $tmp || \
294        log_and_die "Couldn't find 'func' event with arg '$func'"
295    grep -q "func_ret $func" $tmp || \
296        log_and_die "Couldn't find 'func_ret' event with arg '$func'"
297
298    rm $tmp
299}
300
301test_ftrace_filter()
302{
303    local func="__kvm_nvhe_handle___pkvm_selftest_event"
304    local tmp="$(mktemp)"
305
306    echo "Test ftrace filtering..."
307
308    echo "$func" > set_ftrace_filter
309
310    [ "$(cat set_ftrace_filter)" == "$func" ] || \
311        log_and_die "Failed to set set_ftrace_filter"
312
313    run_test_ftrace $tmp
314
315    validate_event "$(awk 'NR==1 {print}' $tmp)" "func" "$func"
316    validate_event "$(awk 'NR==2 {print}' $tmp)" "func_ret" "$func"
317
318    rm $tmp
319}
320
321goto_hyp_trace
322
323test_reset
324test_unloading
325test_big_bpacking
326test_ts
327test_extended_ts
328test_ftrace_nofilter
329test_ftrace_filter
330
331exit 0
332