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
open_close(void)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
get_splpar(void)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
get_bad_parameter(void)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
check_efault_common(unsigned long cmd)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
check_efault_get(void)89 static int check_efault_get(void)
90 {
91 return check_efault_common(PAPR_SYSPARM_IOC_GET);
92 }
93
check_efault_set(void)94 static int check_efault_set(void)
95 {
96 return check_efault_common(PAPR_SYSPARM_IOC_SET);
97 }
98
set_hmc0(void)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
set_with_ro_fd(void)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
main(void)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