1 /* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
13 #include <sys/types.h>
15 #include <sys/param.h>
16 #include <sys/ioctl.h>
20 #include <netinet/in.h>
22 #include "vboot_common.h"
23 #include "vboot_nvstorage.h"
24 #include "host_common.h"
25 #include "crossystem.h"
26 #include "crossystem_arch.h"
27 #include "crossystem_vbnv.h"
29 /* Base name for firmware FDT files */
30 #define FDT_BASE_PATH "/proc/device-tree/firmware/chromeos"
31 /* Path to compatible FDT entry */
32 #define FDT_COMPATIBLE_PATH "/proc/device-tree/compatible"
33 /* Path to the chromeos_arm platform device */
34 #define PLATFORM_DEV_PATH "/sys/devices/platform/chromeos_arm"
35 /* Device for NVCTX write */
36 #define NVCTX_PATH "/dev/mmcblk%d"
37 /* Base name for GPIO files */
38 #define GPIO_BASE_PATH "/sys/class/gpio"
39 #define GPIO_EXPORT_PATH GPIO_BASE_PATH "/export"
40 /* Name of NvStorage type property */
41 #define FDT_NVSTORAGE_TYPE_PROP "nonvolatile-context-storage"
46 /* Common constants */
48 #define SECTOR_SIZE 512
51 static int FindEmmcDev(void) {
54 char filename[FNAME_SIZE];
55 for (mmcblk = 0; mmcblk < MAX_NMMCBLK; mmcblk++) {
56 /* Get first non-removable mmc block device */
57 snprintf(filename, sizeof(filename), "/sys/block/mmcblk%d/removable",
59 if (ReadFileInt(filename, &value) < 0)
68 static int ReadFdtValue(const char *property, int *value) {
69 char filename[FNAME_SIZE];
73 snprintf(filename, sizeof(filename), FDT_BASE_PATH "/%s", property);
74 file = fopen(filename, "rb");
76 fprintf(stderr, "Unable to open FDT property %s\n", property);
80 if (fread(&data, 1, sizeof(data), file) != sizeof(data)) {
81 fprintf(stderr, "Unable to read FDT property %s\n", property);
87 *value = ntohl(data); /* FDT is network byte order */
92 static int ReadFdtInt(const char *property) {
94 if (ReadFdtValue(property, &value))
99 static void GetFdtPropertyPath(const char *property, char *path, size_t size) {
100 if (property[0] == '/')
101 StrCopy(path, property, size);
103 snprintf(path, size, FDT_BASE_PATH "/%s", property);
106 static int FdtPropertyExist(const char *property) {
107 char filename[FNAME_SIZE];
108 struct stat file_status;
110 GetFdtPropertyPath(property, filename, sizeof(filename));
111 if (!stat(filename, &file_status))
112 return 1; // It exists!
114 return 0; // It does not exist or some error happened.
117 static int ReadFdtBlock(const char *property, void **block, size_t *size) {
118 char filename[FNAME_SIZE];
120 size_t property_size;
126 GetFdtPropertyPath(property, filename, sizeof(filename));
127 file = fopen(filename, "rb");
129 fprintf(stderr, "Unable to open FDT property %s\n", property);
133 fseek(file, 0, SEEK_END);
134 property_size = ftell(file);
137 data = malloc(property_size +1);
142 data[property_size] = 0;
144 if (1 != fread(data, property_size, 1, file)) {
145 fprintf(stderr, "Unable to read from property %s\n", property);
154 *size = property_size;
159 static char * ReadFdtString(const char *property) {
161 /* Do not need property size */
162 ReadFdtBlock(property, &str, 0);
166 static int VbGetPlatformGpioStatus(const char* name) {
167 char gpio_name[FNAME_SIZE];
170 snprintf(gpio_name, sizeof(gpio_name), "%s/%s/value",
171 PLATFORM_DEV_PATH, name);
172 if (ReadFileInt(gpio_name, &value) < 0)
178 static int VbGetGpioStatus(unsigned gpio_number) {
179 char gpio_name[FNAME_SIZE];
182 snprintf(gpio_name, sizeof(gpio_name), "%s/gpio%d/value",
183 GPIO_BASE_PATH, gpio_number);
184 if (ReadFileInt(gpio_name, &value) < 0) {
185 /* Try exporting the GPIO */
186 FILE* f = fopen(GPIO_EXPORT_PATH, "wt");
189 fprintf(f, "%d", gpio_number);
192 /* Try re-reading the GPIO value */
193 if (ReadFileInt(gpio_name, &value) < 0)
200 static int VbGetVarGpio(const char* name) {
207 /* TODO: This should at some point in the future use the phandle
208 * to find the gpio chip and thus the base number. Assume 0 now,
209 * which isn't 100% future-proof (i.e. if one of the switches gets
210 * moved to an offchip gpio controller.
213 ret = ReadFdtBlock(name, &pp, &proplen);
214 if (ret || !pp || proplen != 12) {
219 gpio_num = ntohl(prop[1]);
222 * TODO(chrome-os-partner:11296): Use gpio_num == 0 to denote non-exist
223 * GPIO for now, at the risk that one day we might actually want to read
224 * from a GPIO port 0. We should figure out how to represent "non-exist"
228 ret = VbGetGpioStatus(gpio_num);
239 static int VbReadNvStorage_disk(VbNvContext* vnc) {
241 uint8_t sector[SECTOR_SIZE];
243 char nvctx_path[FNAME_SIZE];
245 int lba = ReadFdtInt("nonvolatile-context-lba");
246 int offset = ReadFdtInt("nonvolatile-context-offset");
247 int size = ReadFdtInt("nonvolatile-context-size");
249 emmc_dev = FindEmmcDev();
252 snprintf(nvctx_path, sizeof(nvctx_path), NVCTX_PATH, emmc_dev);
254 if (size != sizeof(vnc->raw) || (size + offset > SECTOR_SIZE))
257 nvctx_fd = open(nvctx_path, O_RDONLY);
258 if (nvctx_fd == -1) {
259 fprintf(stderr, "%s: failed to open %s\n", __FUNCTION__, nvctx_path);
262 lseek(nvctx_fd, lba * SECTOR_SIZE, SEEK_SET);
264 rv = read(nvctx_fd, sector, SECTOR_SIZE);
266 fprintf(stderr, "%s: failed to read nvctx from device %s\n",
267 __FUNCTION__, nvctx_path);
270 Memcpy(vnc->raw, sector+offset, size);
280 static int VbWriteNvStorage_disk(VbNvContext* vnc) {
282 uint8_t sector[SECTOR_SIZE];
284 char nvctx_path[FNAME_SIZE];
286 int lba = ReadFdtInt("nonvolatile-context-lba");
287 int offset = ReadFdtInt("nonvolatile-context-offset");
288 int size = ReadFdtInt("nonvolatile-context-size");
290 emmc_dev = FindEmmcDev();
293 snprintf(nvctx_path, sizeof(nvctx_path), NVCTX_PATH, emmc_dev);
295 if (size != sizeof(vnc->raw) || (size + offset > SECTOR_SIZE))
299 nvctx_fd = open(nvctx_path, O_RDWR);
300 if (nvctx_fd == -1) {
301 fprintf(stderr, "%s: failed to open %s\n", __FUNCTION__, nvctx_path);
304 lseek(nvctx_fd, lba * SECTOR_SIZE, SEEK_SET);
305 rv = read(nvctx_fd, sector, SECTOR_SIZE);
307 fprintf(stderr, "%s: failed to read nvctx from device %s\n",
308 __FUNCTION__, nvctx_path);
311 Memcpy(sector+offset, vnc->raw, size);
312 lseek(nvctx_fd, lba * SECTOR_SIZE, SEEK_SET);
313 rv = write(nvctx_fd, sector, SECTOR_SIZE);
315 fprintf(stderr, "%s: failed to write nvctx to device %s\n",
316 __FUNCTION__, nvctx_path);
320 /* Must flush buffer cache here to make sure it goes to disk */
321 rv = ioctl(nvctx_fd, BLKFLSBUF, 0);
323 fprintf(stderr, "%s: failed to flush nvctx to device %s\n",
324 __FUNCTION__, nvctx_path);
337 int VbReadNvStorage(VbNvContext* vnc) {
338 /* Default to disk for older firmware which does not provide storage type */
340 if (!FdtPropertyExist(FDT_NVSTORAGE_TYPE_PROP))
341 return VbReadNvStorage_disk(vnc);
342 media = ReadFdtString(FDT_NVSTORAGE_TYPE_PROP);
343 if (!strcmp(media, "disk"))
344 return VbReadNvStorage_disk(vnc);
345 if (!strcmp(media, "cros-ec") || !strcmp(media, "mkbp") ||
346 !strcmp(media, "flash"))
347 return VbReadNvStorage_mosys(vnc);
351 int VbWriteNvStorage(VbNvContext* vnc) {
352 /* Default to disk for older firmware which does not provide storage type */
354 if (!FdtPropertyExist(FDT_NVSTORAGE_TYPE_PROP))
355 return VbWriteNvStorage_disk(vnc);
356 media = ReadFdtString(FDT_NVSTORAGE_TYPE_PROP);
357 if (!strcmp(media, "disk"))
358 return VbWriteNvStorage_disk(vnc);
359 if (!strcmp(media, "cros-ec") || !strcmp(media, "mkbp") ||
360 !strcmp(media, "flash"))
361 return VbWriteNvStorage_mosys(vnc);
365 VbSharedDataHeader *VbSharedDataRead(void) {
368 if (ReadFdtBlock("vboot-shared-data", &block, &size))
370 VbSharedDataHeader *p = (VbSharedDataHeader *)block;
371 if (p->magic != VB_SHARED_DATA_MAGIC) {
372 fprintf(stderr, "%s: failed to validate magic in "
373 "VbSharedDataHeader (%x != %x)\n",
374 __FUNCTION__, p->magic, VB_SHARED_DATA_MAGIC);
377 return (VbSharedDataHeader *)block;
380 int VbGetArchPropertyInt(const char* name) {
381 if (!strcasecmp(name, "fmap_base")) {
382 return ReadFdtInt("fmap-offset");
383 } else if (!strcasecmp(name, "devsw_cur")) {
384 /* Systems with virtual developer switches return at-boot value */
385 int flags = VbGetSystemPropertyInt("vdat_flags");
386 if ((flags != -1) && (flags & VBSD_HONOR_VIRT_DEV_SWITCH))
387 return VbGetSystemPropertyInt("devsw_boot");
389 return VbGetVarGpio("developer-switch");
390 } else if (!strcasecmp(name, "recoverysw_cur")) {
392 value = VbGetPlatformGpioStatus("recovery");
396 return VbGetVarGpio("recovery-switch");
397 } else if (!strcasecmp(name, "wpsw_cur")) {
399 /* Try finding the GPIO through the chromeos_arm platform device first. */
400 value = VbGetPlatformGpioStatus("write-protect");
403 return VbGetVarGpio("write-protect-switch");
404 } else if (!strcasecmp(name, "recoverysw_ec_boot")) {
405 /* TODO: read correct value using ectool */
407 } else if (!strcasecmp(name, "inside_vm")) {
408 /* No ARM VMs currently. */
415 const char* VbGetArchPropertyString(const char* name, char* dest,
421 if (!strcasecmp(name,"arch"))
422 return StrCopy(dest, "arm", size);
424 /* Properties from fdt */
425 if (!strcasecmp(name, "ro_fwid"))
426 prop = "readonly-firmware-version";
427 else if (!strcasecmp(name, "hwid"))
428 prop = "hardware-id";
429 else if (!strcasecmp(name, "fwid"))
430 prop = "firmware-version";
431 else if (!strcasecmp(name, "mainfw_type"))
432 prop = "firmware-type";
433 else if (!strcasecmp(name, "ecfw_act"))
434 prop = "active-ec-firmware";
437 str = ReadFdtString(prop);
440 rv = StrCopy(dest, str, size);
447 int VbSetArchPropertyInt(const char* name, int value) {
448 /* All is handled in arch independent fashion */
452 int VbSetArchPropertyString(const char* name, const char* value) {
453 /* All is handled in arch independent fashion */