~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/powerpc/papr_vpd/papr_vpd.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 #define _GNU_SOURCE
  3 #include <errno.h>
  4 #include <fcntl.h>
  5 #include <stdlib.h>
  6 #include <string.h>
  7 #include <sys/ioctl.h>
  8 #include <unistd.h>
  9 
 10 #include <asm/papr-vpd.h>
 11 
 12 #include "utils.h"
 13 
 14 #define DEVPATH "/dev/papr-vpd"
 15 
 16 static int dev_papr_vpd_open_close(void)
 17 {
 18         const int devfd = open(DEVPATH, O_RDONLY);
 19 
 20         SKIP_IF_MSG(devfd < 0 && errno == ENOENT,
 21                     DEVPATH " not present");
 22 
 23         FAIL_IF(devfd < 0);
 24         FAIL_IF(close(devfd) != 0);
 25 
 26         return 0;
 27 }
 28 
 29 static int dev_papr_vpd_get_handle_all(void)
 30 {
 31         const int devfd = open(DEVPATH, O_RDONLY);
 32         struct papr_location_code lc = { .str = "", };
 33         off_t size;
 34         int fd;
 35 
 36         SKIP_IF_MSG(devfd < 0 && errno == ENOENT,
 37                     DEVPATH " not present");
 38 
 39         FAIL_IF(devfd < 0);
 40 
 41         errno = 0;
 42         fd = ioctl(devfd, PAPR_VPD_IOC_CREATE_HANDLE, &lc);
 43         FAIL_IF(errno != 0);
 44         FAIL_IF(fd < 0);
 45 
 46         FAIL_IF(close(devfd) != 0);
 47 
 48         size = lseek(fd, 0, SEEK_END);
 49         FAIL_IF(size <= 0);
 50 
 51         void *buf = malloc((size_t)size);
 52         FAIL_IF(!buf);
 53 
 54         ssize_t consumed = pread(fd, buf, size, 0);
 55         FAIL_IF(consumed != size);
 56 
 57         /* Ensure EOF */
 58         FAIL_IF(read(fd, buf, size) != 0);
 59         FAIL_IF(close(fd));
 60 
 61         /* Verify that the buffer looks like VPD */
 62         static const char needle[] = "System VPD";
 63         FAIL_IF(!memmem(buf, size, needle, strlen(needle)));
 64 
 65         return 0;
 66 }
 67 
 68 static int dev_papr_vpd_get_handle_byte_at_a_time(void)
 69 {
 70         const int devfd = open(DEVPATH, O_RDONLY);
 71         struct papr_location_code lc = { .str = "", };
 72         int fd;
 73 
 74         SKIP_IF_MSG(devfd < 0 && errno == ENOENT,
 75                     DEVPATH " not present");
 76 
 77         FAIL_IF(devfd < 0);
 78 
 79         errno = 0;
 80         fd = ioctl(devfd, PAPR_VPD_IOC_CREATE_HANDLE, &lc);
 81         FAIL_IF(errno != 0);
 82         FAIL_IF(fd < 0);
 83 
 84         FAIL_IF(close(devfd) != 0);
 85 
 86         size_t consumed = 0;
 87         while (1) {
 88                 ssize_t res;
 89                 char c;
 90 
 91                 errno = 0;
 92                 res = read(fd, &c, sizeof(c));
 93                 FAIL_IF(res > sizeof(c));
 94                 FAIL_IF(res < 0);
 95                 FAIL_IF(errno != 0);
 96                 consumed += res;
 97                 if (res == 0)
 98                         break;
 99         }
100 
101         FAIL_IF(consumed != lseek(fd, 0, SEEK_END));
102 
103         FAIL_IF(close(fd));
104 
105         return 0;
106 }
107 
108 
109 static int dev_papr_vpd_unterm_loc_code(void)
110 {
111         const int devfd = open(DEVPATH, O_RDONLY);
112         struct papr_location_code lc = {};
113         int fd;
114 
115         SKIP_IF_MSG(devfd < 0 && errno == ENOENT,
116                     DEVPATH " not present");
117 
118         FAIL_IF(devfd < 0);
119 
120         /*
121          * Place a non-null byte in every element of loc_code; the
122          * driver should reject this input.
123          */
124         memset(lc.str, 'x', ARRAY_SIZE(lc.str));
125 
126         errno = 0;
127         fd = ioctl(devfd, PAPR_VPD_IOC_CREATE_HANDLE, &lc);
128         FAIL_IF(fd != -1);
129         FAIL_IF(errno != EINVAL);
130 
131         FAIL_IF(close(devfd) != 0);
132         return 0;
133 }
134 
135 static int dev_papr_vpd_null_handle(void)
136 {
137         const int devfd = open(DEVPATH, O_RDONLY);
138         int rc;
139 
140         SKIP_IF_MSG(devfd < 0 && errno == ENOENT,
141                     DEVPATH " not present");
142 
143         FAIL_IF(devfd < 0);
144 
145         errno = 0;
146         rc = ioctl(devfd, PAPR_VPD_IOC_CREATE_HANDLE, NULL);
147         FAIL_IF(rc != -1);
148         FAIL_IF(errno != EFAULT);
149 
150         FAIL_IF(close(devfd) != 0);
151         return 0;
152 }
153 
154 static int papr_vpd_close_handle_without_reading(void)
155 {
156         const int devfd = open(DEVPATH, O_RDONLY);
157         struct papr_location_code lc = { .str = "", };
158         int fd;
159 
160         SKIP_IF_MSG(devfd < 0 && errno == ENOENT,
161                     DEVPATH " not present");
162 
163         FAIL_IF(devfd < 0);
164 
165         errno = 0;
166         fd = ioctl(devfd, PAPR_VPD_IOC_CREATE_HANDLE, &lc);
167         FAIL_IF(errno != 0);
168         FAIL_IF(fd < 0);
169 
170         /* close the handle without reading it */
171         FAIL_IF(close(fd) != 0);
172 
173         FAIL_IF(close(devfd) != 0);
174         return 0;
175 }
176 
177 static int papr_vpd_reread(void)
178 {
179         const int devfd = open(DEVPATH, O_RDONLY);
180         struct papr_location_code lc = { .str = "", };
181         int fd;
182 
183         SKIP_IF_MSG(devfd < 0 && errno == ENOENT,
184                     DEVPATH " not present");
185 
186         FAIL_IF(devfd < 0);
187 
188         errno = 0;
189         fd = ioctl(devfd, PAPR_VPD_IOC_CREATE_HANDLE, &lc);
190         FAIL_IF(errno != 0);
191         FAIL_IF(fd < 0);
192 
193         FAIL_IF(close(devfd) != 0);
194 
195         const off_t size = lseek(fd, 0, SEEK_END);
196         FAIL_IF(size <= 0);
197 
198         char *bufs[2];
199 
200         for (size_t i = 0; i < ARRAY_SIZE(bufs); ++i) {
201                 bufs[i] = malloc(size);
202                 FAIL_IF(!bufs[i]);
203                 ssize_t consumed = pread(fd, bufs[i], size, 0);
204                 FAIL_IF(consumed != size);
205         }
206 
207         FAIL_IF(memcmp(bufs[0], bufs[1], size));
208 
209         FAIL_IF(close(fd) != 0);
210 
211         return 0;
212 }
213 
214 static int get_system_loc_code(struct papr_location_code *lc)
215 {
216         static const char system_id_path[] = "/sys/firmware/devicetree/base/system-id";
217         static const char model_path[] = "/sys/firmware/devicetree/base/model";
218         char *system_id;
219         char *model;
220         int err = -1;
221 
222         if (read_file_alloc(model_path, &model, NULL))
223                 return err;
224 
225         if (read_file_alloc(system_id_path, &system_id, NULL))
226                 goto free_model;
227 
228         char *mtm;
229         int sscanf_ret = sscanf(model, "IBM,%ms", &mtm);
230         if (sscanf_ret != 1)
231                 goto free_system_id;
232 
233         char *plant_and_seq;
234         if (sscanf(system_id, "IBM,%*c%*c%ms", &plant_and_seq) != 1)
235                 goto free_mtm;
236         /*
237          * Replace - with . to build location code.
238          */
239         char *sep = strchr(mtm, '-');
240         if (!sep)
241                 goto free_mtm;
242         else
243                 *sep = '.';
244 
245         snprintf(lc->str, sizeof(lc->str),
246                  "U%s.%s", mtm, plant_and_seq);
247         err = 0;
248 
249         free(plant_and_seq);
250 free_mtm:
251         free(mtm);
252 free_system_id:
253         free(system_id);
254 free_model:
255         free(model);
256         return err;
257 }
258 
259 static int papr_vpd_system_loc_code(void)
260 {
261         struct papr_location_code lc;
262         const int devfd = open(DEVPATH, O_RDONLY);
263         off_t size;
264         int fd;
265 
266         SKIP_IF_MSG(devfd < 0 && errno == ENOENT,
267                     DEVPATH " not present");
268         SKIP_IF_MSG(get_system_loc_code(&lc),
269                     "Cannot determine system location code");
270 
271         FAIL_IF(devfd < 0);
272 
273         errno = 0;
274         fd = ioctl(devfd, PAPR_VPD_IOC_CREATE_HANDLE, &lc);
275         FAIL_IF(errno != 0);
276         FAIL_IF(fd < 0);
277 
278         FAIL_IF(close(devfd) != 0);
279 
280         size = lseek(fd, 0, SEEK_END);
281         FAIL_IF(size <= 0);
282 
283         void *buf = malloc((size_t)size);
284         FAIL_IF(!buf);
285 
286         ssize_t consumed = pread(fd, buf, size, 0);
287         FAIL_IF(consumed != size);
288 
289         /* Ensure EOF */
290         FAIL_IF(read(fd, buf, size) != 0);
291         FAIL_IF(close(fd));
292 
293         /* Verify that the buffer looks like VPD */
294         static const char needle[] = "System VPD";
295         FAIL_IF(!memmem(buf, size, needle, strlen(needle)));
296 
297         return 0;
298 }
299 
300 struct vpd_test {
301         int (*function)(void);
302         const char *description;
303 };
304 
305 static const struct vpd_test vpd_tests[] = {
306         {
307                 .function = dev_papr_vpd_open_close,
308                 .description = "open/close " DEVPATH,
309         },
310         {
311                 .function = dev_papr_vpd_unterm_loc_code,
312                 .description = "ensure EINVAL on unterminated location code",
313         },
314         {
315                 .function = dev_papr_vpd_null_handle,
316                 .description = "ensure EFAULT on bad handle addr",
317         },
318         {
319                 .function = dev_papr_vpd_get_handle_all,
320                 .description = "get handle for all VPD"
321         },
322         {
323                 .function = papr_vpd_close_handle_without_reading,
324                 .description = "close handle without consuming VPD"
325         },
326         {
327                 .function = dev_papr_vpd_get_handle_byte_at_a_time,
328                 .description = "read all VPD one byte at a time"
329         },
330         {
331                 .function = papr_vpd_reread,
332                 .description = "ensure re-read yields same results"
333         },
334         {
335                 .function = papr_vpd_system_loc_code,
336                 .description = "get handle for system VPD"
337         },
338 };
339 
340 int main(void)
341 {
342         size_t fails = 0;
343 
344         for (size_t i = 0; i < ARRAY_SIZE(vpd_tests); ++i) {
345                 const struct vpd_test *t = &vpd_tests[i];
346 
347                 if (test_harness(t->function, t->description))
348                         ++fails;
349         }
350 
351         return fails == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
352 }
353 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php