1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright 2014, Michael Ellerman, IBM Corp. |
4 | */ |
5 | |
6 | #include <signal.h> |
7 | #include <stdio.h> |
8 | #include <stdlib.h> |
9 | #include <stdbool.h> |
10 | #include <sys/types.h> |
11 | #include <sys/wait.h> |
12 | #include <unistd.h> |
13 | #include <setjmp.h> |
14 | |
15 | #include "ebb.h" |
16 | |
17 | |
18 | /* |
19 | * Test that a fork clears the PMU state of the child. eg. BESCR/EBBHR/EBBRR |
20 | * are cleared, and MMCR0_PMCC is reset, preventing the child from accessing |
21 | * the PMU. |
22 | */ |
23 | |
24 | static struct event event; |
25 | |
26 | static int child(void) |
27 | { |
28 | /* Even though we have EBE=0 we can still see the EBB regs */ |
29 | FAIL_IF(mfspr(SPRN_BESCR) != 0); |
30 | FAIL_IF(mfspr(SPRN_EBBHR) != 0); |
31 | FAIL_IF(mfspr(SPRN_EBBRR) != 0); |
32 | |
33 | FAIL_IF(catch_sigill(func: write_pmc1)); |
34 | |
35 | /* We can still read from the event, though it is on our parent */ |
36 | FAIL_IF(event_read(e: &event)); |
37 | |
38 | return 0; |
39 | } |
40 | |
41 | /* Tests that fork clears EBB state */ |
42 | int fork_cleanup(void) |
43 | { |
44 | pid_t pid; |
45 | |
46 | SKIP_IF(!ebb_is_supported()); |
47 | |
48 | event_init_named(e: &event, config: 0x1001e, name: "cycles" ); |
49 | event_leader_ebb_init(e: &event); |
50 | |
51 | FAIL_IF(event_open(e: &event)); |
52 | |
53 | ebb_enable_pmc_counting(pmc: 1); |
54 | setup_ebb_handler(standard_ebb_callee); |
55 | ebb_global_enable(); |
56 | |
57 | FAIL_IF(ebb_event_enable(e: &event)); |
58 | |
59 | mtspr(SPRN_MMCR0, MMCR0_FC); |
60 | mtspr(SPRN_PMC1, pmc_sample_period(value: sample_period)); |
61 | |
62 | /* Don't need to actually take any EBBs */ |
63 | |
64 | pid = fork(); |
65 | if (pid == 0) |
66 | exit(child()); |
67 | |
68 | /* Child does the actual testing */ |
69 | FAIL_IF(wait_for_child(child_pid: pid)); |
70 | |
71 | /* After fork */ |
72 | event_close(e: &event); |
73 | |
74 | return 0; |
75 | } |
76 | |
77 | int main(void) |
78 | { |
79 | return test_harness(fork_cleanup, "fork_cleanup" ); |
80 | } |
81 | |