Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright 2014, Michael Ellerman, IBM Corp.
0004  */
0005 
0006 #include <sched.h>
0007 #include <signal.h>
0008 #include <stdio.h>
0009 #include <stdlib.h>
0010 #include <sys/mman.h>
0011 
0012 #include "ebb.h"
0013 
0014 
0015 /*
0016  * Test that tries to trigger CPU_FTR_PMAO_BUG. Which is a hardware defect
0017  * where an exception triggers but we context switch before it is delivered and
0018  * lose the exception.
0019  */
0020 
0021 static int test_body(void)
0022 {
0023     int i, orig_period, max_period;
0024     struct event event;
0025 
0026     SKIP_IF(!ebb_is_supported());
0027 
0028     /* We use PMC4 to make sure the kernel switches all counters correctly */
0029     event_init_named(&event, 0x40002, "instructions");
0030     event_leader_ebb_init(&event);
0031 
0032     event.attr.exclude_kernel = 1;
0033     event.attr.exclude_hv = 1;
0034     event.attr.exclude_idle = 1;
0035 
0036     FAIL_IF(event_open(&event));
0037 
0038     ebb_enable_pmc_counting(4);
0039     setup_ebb_handler(standard_ebb_callee);
0040     ebb_global_enable();
0041     FAIL_IF(ebb_event_enable(&event));
0042 
0043     /*
0044      * We want a low sample period, but we also want to get out of the EBB
0045      * handler without tripping up again.
0046      *
0047      * This value picked after much experimentation.
0048      */
0049     orig_period = max_period = sample_period = 400;
0050 
0051     mtspr(SPRN_PMC4, pmc_sample_period(sample_period));
0052 
0053     while (ebb_state.stats.ebb_count < 1000000) {
0054         /*
0055          * We are trying to get the EBB exception to race exactly with
0056          * us entering the kernel to do the syscall. We then need the
0057          * kernel to decide our timeslice is up and context switch to
0058          * the other thread. When we come back our EBB will have been
0059          * lost and we'll spin in this while loop forever.
0060          */
0061 
0062         for (i = 0; i < 100000; i++)
0063             sched_yield();
0064 
0065         /* Change the sample period slightly to try and hit the race */
0066         if (sample_period >= (orig_period + 200))
0067             sample_period = orig_period;
0068         else
0069             sample_period++;
0070 
0071         if (sample_period > max_period)
0072             max_period = sample_period;
0073     }
0074 
0075     ebb_freeze_pmcs();
0076     ebb_global_disable();
0077 
0078     mtspr(SPRN_PMC4, 0xdead);
0079 
0080     dump_summary_ebb_state();
0081     dump_ebb_hw_state();
0082 
0083     event_close(&event);
0084 
0085     FAIL_IF(ebb_state.stats.ebb_count == 0);
0086 
0087     /* We vary our sample period so we need extra fudge here */
0088     FAIL_IF(!ebb_check_count(4, orig_period, 2 * (max_period - orig_period)));
0089 
0090     return 0;
0091 }
0092 
0093 static int lost_exception(void)
0094 {
0095     return eat_cpu(test_body);
0096 }
0097 
0098 int main(void)
0099 {
0100     test_harness_set_timeout(300);
0101     return test_harness(lost_exception, "lost_exception");
0102 }