1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * Perform Set Clock tests 4 * 5 * Copyright IBM Corp. 2022 6 * 7 * Authors: 8 * Nico Boehr <nrb@linux.ibm.com> 9 */ 10 #include <libcflat.h> 11 #include <uv.h> 12 #include <asm/interrupt.h> 13 #include <asm/time.h> 14 15 static inline int sck(uint64_t *time) 16 { 17 int cc; 18 19 asm volatile( 20 " sck %[time]\n" 21 " ipm %[cc]\n" 22 " srl %[cc],28\n" 23 : [cc] "=d"(cc) 24 : [time] "Q"(*time) 25 : "cc" 26 ); 27 28 return cc; 29 } 30 31 static inline int stck(uint64_t *time) 32 { 33 int cc; 34 35 asm volatile( 36 " stck %[time]\n" 37 " ipm %[cc]\n" 38 " srl %[cc],28\n" 39 : [cc] "=d" (cc), [time] "=Q" (*time) 40 : 41 : "cc", "memory" 42 ); 43 44 return cc; 45 } 46 47 static void test_priv(void) 48 { 49 uint64_t time_to_set_privileged = 0xfacef00dcafe0000, 50 time_to_set_nonprivileged = 0xcafe0000, 51 time_verify; 52 int cc; 53 54 report_prefix_push("privileged"); 55 cc = sck(&time_to_set_privileged); 56 report(!cc, "set clock cc=%d", cc); 57 58 cc = stck(&time_verify); 59 report(!cc, "store clock cc=%d", cc); 60 report(time_verify > time_to_set_privileged, 61 "privileged set affected the clock"); 62 report_prefix_pop(); 63 64 report_prefix_push("unprivileged"); 65 expect_pgm_int(); 66 enter_pstate(); 67 sck(&time_to_set_nonprivileged); 68 leave_pstate(); 69 check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); 70 71 cc = stck(&time_verify); 72 report(!cc, "store clock cc=%d", cc); 73 report(time_verify > time_to_set_privileged, 74 "unprivileged set did not affect the clock"); 75 report_prefix_pop(); 76 } 77 78 static void test_align(void) 79 { 80 const int align_to = 8; 81 char unalign[sizeof(uint64_t) + align_to] __attribute__((aligned(8))); 82 83 report_prefix_push("Unaligned operand"); 84 for (int i = 1; i < align_to; i *= 2) { 85 report_prefix_pushf("%d", i); 86 expect_pgm_int(); 87 sck((uint64_t *)(unalign + i)); 88 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 89 report_prefix_pop(); 90 } 91 report_prefix_pop(); 92 } 93 94 static void test_set(void) 95 { 96 uint64_t start = 0, end = 0, time = 0xcafef00dbeef; 97 const uint64_t ticks_per_ms = 1000 << 12, ms_to_wait = 5; 98 int cc; 99 100 report_prefix_push("set"); 101 102 cc = sck(&time); 103 report(!cc, "set clock cc=%d", cc); 104 105 cc = stck(&start); 106 report(!cc, "store start clock cc=%d", cc); 107 report(start >= time, "start >= set value"); 108 109 mdelay(ms_to_wait); 110 111 cc = stck(&end); 112 report(!cc, "store end clock cc=%d", cc); 113 report(end > time, "end > set value"); 114 115 report(end - start > (ticks_per_ms * ms_to_wait), "Advances"); 116 117 report_prefix_pop(); 118 } 119 120 int main(void) 121 { 122 report_prefix_push("sck"); 123 124 if (uv_os_is_guest()) { 125 report_skip("Test unsupported under PV"); 126 goto out; 127 } 128 129 test_align(); 130 test_set(); 131 test_priv(); 132 133 out: 134 report_prefix_pop(); 135 return report_summary(); 136 } 137