1 // SPDX-License-Identifier: GPL-2.0-only 2 #include <errno.h> 3 #include <fcntl.h> 4 #include <stdlib.h> 5 #include <sys/ioctl.h> 6 #include <unistd.h> 7 #include <asm/papr-sysparm.h> 8 9 #include "utils.h" 10 11 #define DEVPATH "/dev/papr-sysparm" 12 13 static int open_close(void) 14 { 15 const int devfd = open(DEVPATH, O_RDONLY); 16 17 SKIP_IF_MSG(devfd < 0 && errno == ENOENT, 18 DEVPATH " not present"); 19 20 FAIL_IF(devfd < 0); 21 FAIL_IF(close(devfd) != 0); 22 23 return 0; 24 } 25 26 static int get_splpar(void) 27 { 28 struct papr_sysparm_io_block sp = { 29 .parameter = 20, // SPLPAR characteristics 30 }; 31 const int devfd = open(DEVPATH, O_RDONLY); 32 33 SKIP_IF_MSG(devfd < 0 && errno == ENOENT, 34 DEVPATH " not present"); 35 36 FAIL_IF(devfd < 0); 37 FAIL_IF(ioctl(devfd, PAPR_SYSPARM_IOC_GET, &sp) != 0); 38 FAIL_IF(sp.length == 0); 39 FAIL_IF(sp.length > sizeof(sp.data)); 40 FAIL_IF(close(devfd) != 0); 41 42 return 0; 43 } 44 45 static int get_bad_parameter(void) 46 { 47 struct papr_sysparm_io_block sp = { 48 .parameter = UINT32_MAX, // there are only ~60 specified parameters 49 }; 50 const int devfd = open(DEVPATH, O_RDONLY); 51 52 SKIP_IF_MSG(devfd < 0 && errno == ENOENT, 53 DEVPATH " not present"); 54 55 FAIL_IF(devfd < 0); 56 57 // Ensure expected error 58 FAIL_IF(ioctl(devfd, PAPR_SYSPARM_IOC_GET, &sp) != -1); 59 FAIL_IF(errno != EOPNOTSUPP); 60 61 // Ensure the buffer is unchanged 62 FAIL_IF(sp.length != 0); 63 for (size_t i = 0; i < ARRAY_SIZE(sp.data); ++i) 64 FAIL_IF(sp.data[i] != 0); 65 66 FAIL_IF(close(devfd) != 0); 67 68 return 0; 69 } 70 71 static int check_efault_common(unsigned long cmd) 72 { 73 const int devfd = open(DEVPATH, O_RDWR); 74 75 SKIP_IF_MSG(devfd < 0 && errno == ENOENT, 76 DEVPATH " not present"); 77 78 FAIL_IF(devfd < 0); 79 80 // Ensure expected error 81 FAIL_IF(ioctl(devfd, cmd, NULL) != -1); 82 FAIL_IF(errno != EFAULT); 83 84 FAIL_IF(close(devfd) != 0); 85 86 return 0; 87 } 88 89 static int check_efault_get(void) 90 { 91 return check_efault_common(PAPR_SYSPARM_IOC_GET); 92 } 93 94 static int check_efault_set(void) 95 { 96 return check_efault_common(PAPR_SYSPARM_IOC_SET); 97 } 98 99 static int set_hmc0(void) 100 { 101 struct papr_sysparm_io_block sp = { 102 .parameter = 0, // HMC0, not a settable parameter 103 }; 104 const int devfd = open(DEVPATH, O_RDWR); 105 106 SKIP_IF_MSG(devfd < 0 && errno == ENOENT, 107 DEVPATH " not present"); 108 109 FAIL_IF(devfd < 0); 110 111 // Ensure expected error 112 FAIL_IF(ioctl(devfd, PAPR_SYSPARM_IOC_SET, &sp) != -1); 113 SKIP_IF_MSG(errno == EOPNOTSUPP, "operation not supported"); 114 FAIL_IF(errno != EPERM); 115 116 FAIL_IF(close(devfd) != 0); 117 118 return 0; 119 } 120 121 static int set_with_ro_fd(void) 122 { 123 struct papr_sysparm_io_block sp = { 124 .parameter = 0, // HMC0, not a settable parameter. 125 }; 126 const int devfd = open(DEVPATH, O_RDONLY); 127 128 SKIP_IF_MSG(devfd < 0 && errno == ENOENT, 129 DEVPATH " not present"); 130 131 FAIL_IF(devfd < 0); 132 133 // Ensure expected error 134 FAIL_IF(ioctl(devfd, PAPR_SYSPARM_IOC_SET, &sp) != -1); 135 SKIP_IF_MSG(errno == EOPNOTSUPP, "operation not supported"); 136 137 // HMC0 isn't a settable parameter and we would normally 138 // expect to get EPERM on attempts to modify it. However, when 139 // the file is open read-only, we expect the driver to prevent 140 // the attempt with a distinct error. 141 FAIL_IF(errno != EBADF); 142 143 FAIL_IF(close(devfd) != 0); 144 145 return 0; 146 } 147 148 struct sysparm_test { 149 int (*function)(void); 150 const char *description; 151 }; 152 153 static const struct sysparm_test sysparm_tests[] = { 154 { 155 .function = open_close, 156 .description = "open and close " DEVPATH " without issuing commands", 157 }, 158 { 159 .function = get_splpar, 160 .description = "retrieve SPLPAR characteristics", 161 }, 162 { 163 .function = get_bad_parameter, 164 .description = "verify EOPNOTSUPP for known-bad parameter", 165 }, 166 { 167 .function = check_efault_get, 168 .description = "PAPR_SYSPARM_IOC_GET returns EFAULT on bad address", 169 }, 170 { 171 .function = check_efault_set, 172 .description = "PAPR_SYSPARM_IOC_SET returns EFAULT on bad address", 173 }, 174 { 175 .function = set_hmc0, 176 .description = "ensure EPERM on attempt to update HMC0", 177 }, 178 { 179 .function = set_with_ro_fd, 180 .description = "PAPR_IOC_SYSPARM_SET returns EACCES on read-only fd", 181 }, 182 }; 183 184 int main(void) 185 { 186 size_t fails = 0; 187 188 for (size_t i = 0; i < ARRAY_SIZE(sysparm_tests); ++i) { 189 const struct sysparm_test *t = &sysparm_tests[i]; 190 191 if (test_harness(t->function, t->description)) 192 ++fails; 193 } 194 195 return fails == 0 ? EXIT_SUCCESS : EXIT_FAILURE; 196 } 197