1 /* Copyright 2012 The ChromiumOS Authors
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 */
5
6 #include <stdbool.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <stddef.h>
10 #include <stdlib.h>
11 #ifndef HAVE_MACOS
12 #include <linux/fs.h>
13 #include <linux/gpio.h>
14 #endif
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <sys/param.h>
18 #include <sys/ioctl.h>
19 #include <sys/wait.h>
20 #include <dirent.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <unistd.h>
24 #include <netinet/in.h>
25
26 #include "crossystem_arch.h"
27 #include "crossystem.h"
28 #include "crossystem_vbnv.h"
29 #include "host_common.h"
30
31 /* Base name for firmware FDT files */
32 #define FDT_BASE_PATH "/proc/device-tree"
33 /* The /firmware/chromeos path in FDT */
34 #define FDT_CHROMEOS "firmware/chromeos/"
35 /* Path to compatible FDT entry */
36 #define FDT_COMPATIBLE_PATH "/proc/device-tree/compatible"
37 /* Path to the chromeos_arm platform device (deprecated) */
38 #define PLATFORM_DEV_PATH "/sys/devices/platform/chromeos_arm"
39 /* These should match the Linux GPIO name (i.e., 'gpio-line-names'). */
40 #define GPIO_NAME_RECOVERY_SW_L "RECOVERY_SW_L"
41 #define GPIO_NAME_RECOVERY_SW "RECOVERY_SW"
42 #define GPIO_NAME_WP_L "AP_FLASH_WP_L"
43 #define GPIO_NAME_WP "AP_FLASH_WP"
44 /* Device for NVCTX write */
45 #define NVCTX_PATH "/dev/mmcblk%d"
46 /* Base name for GPIO files */
47 #define GPIO_BASE_PATH "/sys/class/gpio"
48 #define GPIO_EXPORT_PATH GPIO_BASE_PATH "/export"
49 /* Name of NvStorage type property */
50 #define FDT_NVSTORAGE_TYPE_PROP FDT_CHROMEOS "nonvolatile-context-storage"
51 /* Errors */
52 #define E_FAIL -1
53 #define E_FILEOP -2
54 #define E_MEM -3
55 /* Common constants */
56 #define FNAME_SIZE 80
57 #define SECTOR_SIZE 512
58 #define MAX_NMMCBLK 9
59
FindEmmcDev(void)60 static int FindEmmcDev(void)
61 {
62 int mmcblk;
63 unsigned value;
64 char filename[FNAME_SIZE];
65 for (mmcblk = 0; mmcblk < MAX_NMMCBLK; mmcblk++) {
66 /* Get first non-removable mmc block device */
67 snprintf(filename, sizeof(filename),
68 "/sys/block/mmcblk%d/removable", mmcblk);
69 if (ReadFileInt(filename, &value) < 0)
70 continue;
71 if (value == 0)
72 return mmcblk;
73 }
74 /* eMMC not found */
75 return E_FAIL;
76 }
77
ReadFdtValue(const char * property,int * value)78 static int ReadFdtValue(const char *property, int *value)
79 {
80 char filename[FNAME_SIZE];
81 FILE *file;
82 int data = 0;
83
84 snprintf(filename, sizeof(filename), FDT_BASE_PATH "/%s", property);
85 file = fopen(filename, "rb");
86 if (!file) {
87 fprintf(stderr, "Unable to open FDT property %s\n", property);
88 return E_FILEOP;
89 }
90
91 if (fread(&data, 1, sizeof(data), file) != sizeof(data)) {
92 fprintf(stderr, "Unable to read FDT property %s\n", property);
93 return E_FILEOP;
94 }
95 fclose(file);
96
97 if (value)
98 *value = ntohl(data); /* FDT is network byte order */
99
100 return 0;
101 }
102
ReadFdtInt(const char * property)103 static int ReadFdtInt(const char *property)
104 {
105 int value = 0;
106 if (ReadFdtValue(property, &value))
107 return E_FAIL;
108 return value;
109 }
110
GetFdtPropertyPath(const char * property,char * path,size_t size)111 static void GetFdtPropertyPath(const char *property, char *path, size_t size)
112 {
113 if (property[0] == '/')
114 StrCopy(path, property, size);
115 else
116 snprintf(path, size, FDT_BASE_PATH "/%s", property);
117 }
118
FdtPropertyExist(const char * property)119 static int FdtPropertyExist(const char *property)
120 {
121 char filename[FNAME_SIZE];
122 struct stat file_status;
123
124 GetFdtPropertyPath(property, filename, sizeof(filename));
125 if (!stat(filename, &file_status))
126 return 1; // It exists!
127 else
128 return 0; // It does not exist or some error happened.
129 }
130
ReadFdtBlock(const char * property,void ** block,size_t * size)131 static int ReadFdtBlock(const char *property, void **block, size_t *size)
132 {
133 char filename[FNAME_SIZE];
134 FILE *file;
135 size_t property_size;
136 char *data;
137
138 if (!block)
139 return E_FAIL;
140
141 GetFdtPropertyPath(property, filename, sizeof(filename));
142 file = fopen(filename, "rb");
143 if (!file) {
144 fprintf(stderr, "Unable to open FDT property %s\n", property);
145 return E_FILEOP;
146 }
147
148 fseek(file, 0, SEEK_END);
149 property_size = ftell(file);
150 rewind(file);
151
152 data = malloc(property_size +1);
153 if (!data) {
154 fclose(file);
155 return E_MEM;
156 }
157 data[property_size] = 0;
158
159 if (1 != fread(data, property_size, 1, file)) {
160 fprintf(stderr, "Unable to read from property %s\n", property);
161 fclose(file);
162 free(data);
163 return E_FILEOP;
164 }
165
166 fclose(file);
167 *block = data;
168 if (size)
169 *size = property_size;
170
171 return 0;
172 }
173
ReadFdtString(const char * property)174 static char * ReadFdtString(const char *property)
175 {
176 void *str = NULL;
177 /* Do not need property size */
178 ReadFdtBlock(property, &str, 0);
179 return (char *)str;
180 }
181
VbGetPlatformGpioStatus(const char * name)182 static int VbGetPlatformGpioStatus(const char* name)
183 {
184 char gpio_name[FNAME_SIZE];
185 unsigned value;
186
187 snprintf(gpio_name, sizeof(gpio_name), "%s/%s/value",
188 PLATFORM_DEV_PATH, name);
189 if (ReadFileInt(gpio_name, &value) < 0)
190 return -1;
191
192 return (int)value;
193 }
194
195 #ifndef HAVE_MACOS
gpioline_read_value(int chip_fd,int idx,bool active_low)196 static int gpioline_read_value(int chip_fd, int idx, bool active_low)
197 {
198 struct gpiohandle_request request = {
199 .lineoffsets = { idx },
200 .flags = GPIOHANDLE_REQUEST_INPUT | \
201 (active_low ? GPIOHANDLE_REQUEST_ACTIVE_LOW : 0),
202 .lines = 1,
203 };
204 struct gpiohandle_data data;
205 int trynum;
206 int ret;
207
208 /*
209 * If two callers try to read the same GPIO at the same time then
210 * one of the two will get back EBUSY. There's no great way to
211 * solve this, so we'll just retry a bunch with a small sleep in
212 * between.
213 */
214 for (trynum = 0; true; trynum++) {
215 ret = ioctl(chip_fd, GPIO_GET_LINEHANDLE_IOCTL, &request);
216
217 /*
218 * Not part of the loop condition so usleep doesn't clobber
219 * errno (implicitly used by perror).
220 */
221 if (ret >= 0 || errno != EBUSY || trynum >= 50)
222 break;
223
224 usleep(trynum * 1000);
225 }
226
227 if (ret < 0) {
228 perror("GPIO_GET_LINEHANDLE_IOCTL");
229 return -1;
230 }
231
232 if (request.fd < 0) {
233 fprintf(stderr, "bad LINEHANDLE fd %d\n", request.fd);
234 return -1;
235 }
236
237 ret = ioctl(request.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data);
238 if (ret < 0) {
239 perror("GPIOHANDLE_GET_LINE_VALUES_IOCTL");
240 close(request.fd);
241 return -1;
242 }
243 close(request.fd);
244 return data.values[0];
245 }
246
247 /* Return 1 if @idx line matches name; 0 if no match; negative if error. */
gpioline_name_match(int chip_fd,int idx,const char * name)248 static int gpioline_name_match(int chip_fd, int idx, const char *name)
249 {
250 struct gpioline_info info = {
251 .line_offset = idx,
252 };
253 int ret;
254
255 ret = ioctl(chip_fd, GPIO_GET_LINEINFO_IOCTL, &info);
256 if (ret < 0) {
257 perror("GPIO_GET_LINEINFO_IOCTL");
258 return -1;
259 }
260
261 return strncmp(info.name, name, sizeof(info.name)) == 0;
262 }
263
264 /* Return value of gpio, if found. Negative for error codes. */
gpiochip_read_value(int chip_fd,const char * name,bool active_low)265 static int gpiochip_read_value(int chip_fd, const char *name, bool active_low)
266 {
267 struct gpiochip_info info;
268 int i, ret;
269
270 ret = ioctl(chip_fd, GPIO_GET_CHIPINFO_IOCTL, &info);
271 if (ret < 0) {
272 perror("GPIO_GET_CHIPINFO_IOCTL");
273 return -1;
274 }
275
276 for (i = 0; i < info.lines; i++) {
277 if (gpioline_name_match(chip_fd, i, name) != 1)
278 continue;
279 return gpioline_read_value(chip_fd, i, active_low);
280 }
281
282 return -1;
283 }
284
285 /* Return nonzero for entries with a 'gpiochip'-prefixed name. */
gpiochip_scan_filter(const struct dirent * d)286 static int gpiochip_scan_filter(const struct dirent *d)
287 {
288 const char prefix[] = "gpiochip";
289 return !strncmp(prefix, d->d_name, strlen(prefix));
290 }
291
292 /*
293 * Read a named GPIO via the Linux /dev/gpiochip* API, supported in recent
294 * kernels (e.g., ChromeOS kernel 4.14+). This method is preferred over the
295 * downstream chromeos_arm driver.
296 *
297 * Returns -1 for errors (e.g., API not supported, or @name not found); 1 for
298 * active; 0 for inactive.
299 */
gpiod_read(const char * name,bool active_low)300 static int gpiod_read(const char *name, bool active_low)
301 {
302 struct dirent **list;
303 int i, max, ret;
304
305 ret = scandir("/dev", &list, gpiochip_scan_filter, alphasort);
306 if (ret < 0) {
307 perror("scandir");
308 return -1;
309 }
310 max = ret;
311 /* No /dev/gpiochip* -- API not supported. */
312 if (!max)
313 return -1;
314
315 for (i = 0; i < max; i++) {
316 char buf[5 + NAME_MAX + 1];
317 int fd;
318
319 snprintf(buf, sizeof(buf), "/dev/%s", list[i]->d_name);
320 ret = open(buf, O_RDWR);
321 if (ret < 0) {
322 perror("open");
323 break;
324 }
325 fd = ret;
326
327 ret = gpiochip_read_value(fd, name, active_low);
328 close(fd);
329 if (ret >= 0)
330 break;
331 }
332
333 for (i = 0; i < max; i++)
334 free(list[i]);
335 free(list);
336
337 return ret >= 0 ? ret : -1;
338 }
339 #else
gpiod_read(const char * name,bool active_low)340 static int gpiod_read(const char *name, bool active_low)
341 {
342 return -1;
343 }
344 #endif /* HAVE_MACOS */
345
vb2_read_nv_storage_disk(struct vb2_context * ctx)346 static int vb2_read_nv_storage_disk(struct vb2_context *ctx)
347 {
348 int nvctx_fd = -1;
349 uint8_t sector[SECTOR_SIZE];
350 int rv = -1;
351 char nvctx_path[FNAME_SIZE];
352 int emmc_dev;
353 int lba = ReadFdtInt(FDT_CHROMEOS "nonvolatile-context-lba");
354 int offset = ReadFdtInt(FDT_CHROMEOS "nonvolatile-context-offset");
355 int size = ReadFdtInt(FDT_CHROMEOS "nonvolatile-context-size");
356
357 emmc_dev = FindEmmcDev();
358 if (emmc_dev < 0)
359 return E_FAIL;
360 snprintf(nvctx_path, sizeof(nvctx_path), NVCTX_PATH, emmc_dev);
361
362 if (size != vb2_nv_get_size(ctx) || (size + offset > SECTOR_SIZE))
363 return E_FAIL;
364
365 nvctx_fd = open(nvctx_path, O_RDONLY);
366 if (nvctx_fd == -1) {
367 fprintf(stderr, "%s: failed to open %s\n", __FUNCTION__,
368 nvctx_path);
369 goto out;
370 }
371 lseek(nvctx_fd, lba * SECTOR_SIZE, SEEK_SET);
372
373 rv = read(nvctx_fd, sector, SECTOR_SIZE);
374 if (size <= 0) {
375 fprintf(stderr, "%s: failed to read nvctx from device %s\n",
376 __FUNCTION__, nvctx_path);
377 goto out;
378 }
379 memcpy(ctx->nvdata, sector+offset, size);
380 rv = 0;
381
382 out:
383 if (nvctx_fd > 0)
384 close(nvctx_fd);
385
386 return rv;
387 }
388
vb2_write_nv_storage_disk(struct vb2_context * ctx)389 static int vb2_write_nv_storage_disk(struct vb2_context *ctx)
390 {
391 int nvctx_fd = -1;
392 uint8_t sector[SECTOR_SIZE];
393 int rv = -1;
394 char nvctx_path[FNAME_SIZE];
395 int emmc_dev;
396 int lba = ReadFdtInt(FDT_CHROMEOS "nonvolatile-context-lba");
397 int offset = ReadFdtInt(FDT_CHROMEOS "nonvolatile-context-offset");
398 int size = ReadFdtInt(FDT_CHROMEOS "nonvolatile-context-size");
399
400 emmc_dev = FindEmmcDev();
401 if (emmc_dev < 0)
402 return E_FAIL;
403 snprintf(nvctx_path, sizeof(nvctx_path), NVCTX_PATH, emmc_dev);
404
405 if (size != vb2_nv_get_size(ctx) || (size + offset > SECTOR_SIZE))
406 return E_FAIL;
407
408 do {
409 nvctx_fd = open(nvctx_path, O_RDWR);
410 if (nvctx_fd == -1) {
411 fprintf(stderr, "%s: failed to open %s\n",
412 __FUNCTION__, nvctx_path);
413 break;
414 }
415 lseek(nvctx_fd, lba * SECTOR_SIZE, SEEK_SET);
416 rv = read(nvctx_fd, sector, SECTOR_SIZE);
417 if (rv <= 0) {
418 fprintf(stderr,
419 "%s: failed to read nvctx from device %s\n",
420 __FUNCTION__, nvctx_path);
421 break;
422 }
423 memcpy(sector+offset, ctx->nvdata, size);
424 lseek(nvctx_fd, lba * SECTOR_SIZE, SEEK_SET);
425 rv = write(nvctx_fd, sector, SECTOR_SIZE);
426 if (rv <= 0) {
427 fprintf(stderr,
428 "%s: failed to write nvctx to device %s\n",
429 __FUNCTION__, nvctx_path);
430 break;
431 }
432 #ifndef HAVE_MACOS
433 /* Must flush buffer cache here to make sure it goes to disk */
434 rv = ioctl(nvctx_fd, BLKFLSBUF, 0);
435 if (rv < 0) {
436 fprintf(stderr,
437 "%s: failed to flush nvctx to device %s\n",
438 __FUNCTION__, nvctx_path);
439 break;
440 }
441 #endif
442 rv = 0;
443 } while (0);
444
445 if (nvctx_fd > 0)
446 close(nvctx_fd);
447
448 return rv;
449 }
450
vb2_read_nv_storage(struct vb2_context * ctx)451 int vb2_read_nv_storage(struct vb2_context *ctx)
452 {
453 /* Default to disk for older firmware which does not provide storage
454 * type */
455 char *media;
456 if (!FdtPropertyExist(FDT_NVSTORAGE_TYPE_PROP))
457 return vb2_read_nv_storage_disk(ctx);
458 media = ReadFdtString(FDT_NVSTORAGE_TYPE_PROP);
459 if (!strcmp(media, "disk"))
460 return vb2_read_nv_storage_disk(ctx);
461 if (!strcmp(media, "flash"))
462 return vb2_read_nv_storage_flashrom(ctx);
463 return -1;
464 }
465
vb2_write_nv_storage(struct vb2_context * ctx)466 int vb2_write_nv_storage(struct vb2_context *ctx)
467 {
468 /* Default to disk for older firmware which does not provide storage
469 * type */
470 char *media;
471 if (!FdtPropertyExist(FDT_NVSTORAGE_TYPE_PROP))
472 return vb2_write_nv_storage_disk(ctx);
473 media = ReadFdtString(FDT_NVSTORAGE_TYPE_PROP);
474 if (!strcmp(media, "disk"))
475 return vb2_write_nv_storage_disk(ctx);
476 if (!strcmp(media, "flash"))
477 return vb2_write_nv_storage_flashrom(ctx);
478 return -1;
479 }
480
VbSharedDataRead(void)481 VbSharedDataHeader *VbSharedDataRead(void)
482 {
483 void *block = NULL;
484 size_t size = 0;
485 if (ReadFdtBlock(FDT_CHROMEOS "vboot-shared-data", &block, &size))
486 return NULL;
487 VbSharedDataHeader *p = (VbSharedDataHeader *)block;
488 if (p->magic != VB_SHARED_DATA_MAGIC) {
489 fprintf(stderr, "%s: failed to validate magic in "
490 "VbSharedDataHeader (%x != %x)\n",
491 __FUNCTION__, p->magic, VB_SHARED_DATA_MAGIC);
492 return NULL;
493 }
494 return (VbSharedDataHeader *)block;
495 }
496
VbGetArchPropertyInt(const char * name)497 int VbGetArchPropertyInt(const char* name)
498 {
499 if (!strcasecmp(name, "devsw_cur")) {
500 /* Systems with virtual developer switches return at-boot
501 * value */
502 return VbGetSystemPropertyInt("devsw_boot");
503 } else if (!strcasecmp(name, "recoverysw_cur")) {
504 int value;
505 /* Try GPIO chardev API first. */
506 value = gpiod_read(GPIO_NAME_RECOVERY_SW_L, true);
507 if (value != -1)
508 return value;
509 value = gpiod_read(GPIO_NAME_RECOVERY_SW, false);
510 if (value != -1)
511 return value;
512 /* Try the deprecated chromeos_arm platform device next. */
513 return VbGetPlatformGpioStatus("recovery");
514 } else if (!strcasecmp(name, "wpsw_cur")) {
515 int value;
516 /* Try GPIO chardev API first. */
517 value = gpiod_read(GPIO_NAME_WP_L, true);
518 if (value != -1)
519 return value;
520 value = gpiod_read(GPIO_NAME_WP, false);
521 if (value != -1)
522 return value;
523 /* Try the deprecated chromeos_arm platform device next. */
524 return VbGetPlatformGpioStatus("write-protect");
525 } else if (!strcasecmp(name, "recoverysw_ec_boot")) {
526 /* TODO: read correct value using ectool */
527 return 0;
528 } else if (!strcasecmp(name, "board_id")) {
529 return ReadFdtInt("firmware/coreboot/board-id");
530 } else {
531 return -1;
532 }
533 }
534
VbGetArchPropertyString(const char * name,char * dest,size_t size)535 const char* VbGetArchPropertyString(const char* name, char* dest,
536 size_t size)
537 {
538 char *str = NULL;
539 char *rv = NULL;
540 const char *prop = NULL;
541
542 if (!strcasecmp(name,"arch"))
543 return StrCopy(dest, "arm", size);
544
545 /* Properties from fdt */
546 if (!strcasecmp(name, "ro_fwid"))
547 prop = FDT_CHROMEOS "readonly-firmware-version";
548 else if (!strcasecmp(name, "hwid"))
549 prop = FDT_CHROMEOS "hardware-id";
550 else if (!strcasecmp(name, "fwid"))
551 prop = FDT_CHROMEOS "firmware-version";
552 else if (!strcasecmp(name, "mainfw_type"))
553 prop = FDT_CHROMEOS "firmware-type";
554 else if (!strcasecmp(name, "ecfw_act"))
555 prop = FDT_CHROMEOS "active-ec-firmware";
556 if (prop)
557 str = ReadFdtString(prop);
558
559 if (str) {
560 rv = StrCopy(dest, str, size);
561 free(str);
562 return rv;
563 }
564 return NULL;
565 }
566
VbSetArchPropertyInt(const char * name,int value)567 int VbSetArchPropertyInt(const char* name, int value)
568 {
569 /* All is handled in arch independent fashion */
570 return -1;
571 }
572
VbSetArchPropertyString(const char * name,const char * value)573 int VbSetArchPropertyString(const char* name, const char* value)
574 {
575 /* All is handled in arch independent fashion */
576 return -1;
577 }
578