blob: e17852beddf3ddd278e54688ab8e194e9310017e [file] [log] [blame]
Randall Spanglerda8d32d2012-08-03 12:48:24 -07001/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Randall Spanglereb591952011-04-07 10:02:00 -07002 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 */
5
Bill Richardson1a4d03d2011-08-31 12:01:13 -07006#include <ctype.h>
7#include <dirent.h>
Gabe Black29efa172011-11-08 22:57:38 -08008#include <errno.h>
9#include <linux/nvram.h>
J. Richard Barnettea3d70a32013-10-30 11:36:45 -070010#include <stddef.h>
Bill Richardson0c3ba242013-03-29 11:09:30 -070011#include <stdint.h>
Randall Spanglereb591952011-04-07 10:02:00 -070012#include <stdio.h>
13#include <string.h>
Gabe Black29efa172011-11-08 22:57:38 -080014#include <sys/ioctl.h>
Randall Spanglereb591952011-04-07 10:02:00 -070015#include <sys/stat.h>
Bill Richardson1a4d03d2011-08-31 12:01:13 -070016#include <sys/types.h>
Randall Spanglereb591952011-04-07 10:02:00 -070017#include <unistd.h>
Randall Spanglereb591952011-04-07 10:02:00 -070018
Randall Spanglereb591952011-04-07 10:02:00 -070019#include "crossystem.h"
20#include "crossystem_arch.h"
Duncan Laurieeb0c8cc2016-03-30 09:38:54 -070021#include "crossystem_vbnv.h"
Bill Richardson0c3ba242013-03-29 11:09:30 -070022#include "host_common.h"
Randall Spanglereb591952011-04-07 10:02:00 -070023#include "utility.h"
24#include "vboot_common.h"
25#include "vboot_nvstorage.h"
26#include "vboot_struct.h"
27
28
29/* ACPI constants from Chrome OS Main Processor Firmware Spec */
30/* Boot reasons from BINF.0, from early H2C firmware */
31/* Unknown */
32#define BINF0_UNKNOWN 0
33/* Normal boot to Chrome OS */
34#define BINF0_NORMAL 1
35/* Developer mode boot (developer mode warning displayed) */
36#define BINF0_DEVELOPER 2
37/* Recovery initiated by user, using recovery button */
38#define BINF0_RECOVERY_BUTTON 3
39/* Recovery initiated by user pressing a key at developer mode warning
40 * screen */
41#define BINF0_RECOVERY_DEV_SCREEN_KEY 4
42/* Recovery caused by BIOS failed signature check (neither rewritable
43 * firmware was valid) */
44#define BINF0_RECOVERY_RW_FW_BAD 5
45/* Recovery caused by no OS kernel detected */
46#define BINF0_RECOVERY_NO_OS 6
47/* Recovery caused by OS kernel failed signature check */
48#define BINF0_RECOVERY_BAD_OS 7
49/* Recovery initiated by OS */
50#define BINF0_RECOVERY_OS_INITIATED 8
51/* OS-initiated S3 diagnostic path (debug mode boot) */
52#define BINF0_S3_DIAGNOSTIC_PATH 9
53/* S3 resume failed */
54#define BINF0_S3_RESUME_FAILED 10
55/* Recovery caused by TPM error */
56#define BINF0_RECOVERY_TPM_ERROR 11
Randall Spanglereb591952011-04-07 10:02:00 -070057/* CHSW bitflags */
58#define CHSW_RECOVERY_BOOT 0x00000002
59#define CHSW_RECOVERY_EC_BOOT 0x00000004
60#define CHSW_DEV_BOOT 0x00000020
61#define CHSW_WP_BOOT 0x00000200
62/* CMOS reboot field bitflags */
63#define CMOSRF_RECOVERY 0x80
64#define CMOSRF_DEBUG_RESET 0x40
65#define CMOSRF_TRY_B 0x20
66/* GPIO signal types */
67#define GPIO_SIGNAL_TYPE_RECOVERY 1
68#define GPIO_SIGNAL_TYPE_DEV 2
69#define GPIO_SIGNAL_TYPE_WP 3
70
71/* Base name for ACPI files */
72#define ACPI_BASE_PATH "/sys/devices/platform/chromeos_acpi"
73/* Paths for frequently used ACPI files */
74#define ACPI_BINF_PATH ACPI_BASE_PATH "/BINF"
75#define ACPI_CHNV_PATH ACPI_BASE_PATH "/CHNV"
76#define ACPI_CHSW_PATH ACPI_BASE_PATH "/CHSW"
77#define ACPI_FMAP_PATH ACPI_BASE_PATH "/FMAP"
78#define ACPI_GPIO_PATH ACPI_BASE_PATH "/GPIO"
79#define ACPI_VBNV_PATH ACPI_BASE_PATH "/VBNV"
80#define ACPI_VDAT_PATH ACPI_BASE_PATH "/VDAT"
81
82/* Base name for GPIO files */
83#define GPIO_BASE_PATH "/sys/class/gpio"
84#define GPIO_EXPORT_PATH GPIO_BASE_PATH "/export"
85
86/* Filename for NVRAM file */
87#define NVRAM_PATH "/dev/nvram"
88
Randall Spangler07f34842011-04-11 13:35:06 -070089/* Filename for legacy firmware update tries */
90#define NEED_FWUPDATE_PATH "/mnt/stateful_partition/.need_firmware_update"
91
Bernie Thompson0b5789f2011-12-28 07:40:48 -080092/* Filenames for PCI Vendor and Device IDs */
93#define PCI_VENDOR_ID_PATH "/sys/bus/pci/devices/0000:00:00.0/vendor"
94#define PCI_DEVICE_ID_PATH "/sys/bus/pci/devices/0000:00:00.0/device"
95
John Zhao5f16cce2015-04-02 10:24:51 -070096typedef struct {
Randall Spanglerfb267152016-10-11 15:28:16 -070097 unsigned int base;
98 unsigned int uid;
John Zhao5f16cce2015-04-02 10:24:51 -070099} Basemapping;
100
Randall Spanglerfb267152016-10-11 15:28:16 -0700101static void VbFixCmosChecksum(FILE* file)
102{
103 int fd = fileno(file);
104 ioctl(fd, NVRAM_SETCKS);
Gabe Black29efa172011-11-08 22:57:38 -0800105}
106
107
Randall Spanglerfb267152016-10-11 15:28:16 -0700108static int VbCmosRead(unsigned offs, size_t size, void *ptr)
109{
110 size_t res;
111 FILE* f;
Gabe Black29efa172011-11-08 22:57:38 -0800112
Randall Spanglerfb267152016-10-11 15:28:16 -0700113 f = fopen(NVRAM_PATH, "rb");
114 if (!f)
115 return -1;
Gabe Black29efa172011-11-08 22:57:38 -0800116
Randall Spanglerfb267152016-10-11 15:28:16 -0700117 if (0 != fseek(f, offs, SEEK_SET)) {
118 fclose(f);
119 return -1;
120 }
Gabe Black29efa172011-11-08 22:57:38 -0800121
Randall Spanglerfb267152016-10-11 15:28:16 -0700122 res = fread(ptr, size, 1, f);
123 if (1 != res && errno == EIO && ferror(f)) {
124 VbFixCmosChecksum(f);
125 res = fread(ptr, size, 1, f);
126 }
Gabe Black29efa172011-11-08 22:57:38 -0800127
Randall Spanglerfb267152016-10-11 15:28:16 -0700128 fclose(f);
129 return (1 == res) ? 0 : -1;
Gabe Black29efa172011-11-08 22:57:38 -0800130}
131
132
Randall Spanglerfb267152016-10-11 15:28:16 -0700133static int VbCmosWrite(unsigned offs, size_t size, const void *ptr)
134{
135 size_t res;
136 FILE* f;
Gabe Black29efa172011-11-08 22:57:38 -0800137
Randall Spanglerfb267152016-10-11 15:28:16 -0700138 f = fopen(NVRAM_PATH, "w+b");
139 if (!f)
140 return -1;
Gabe Black29efa172011-11-08 22:57:38 -0800141
Randall Spanglerfb267152016-10-11 15:28:16 -0700142 if (0 != fseek(f, offs, SEEK_SET)) {
143 fclose(f);
144 return -1;
145 }
Hung-Te Lin6a6f85d2011-11-16 17:31:19 +0800146
Randall Spanglerfb267152016-10-11 15:28:16 -0700147 res = fwrite(ptr, size, 1, f);
148 if (1 != res && errno == EIO && ferror(f)) {
149 VbFixCmosChecksum(f);
150 res = fwrite(ptr, size, 1, f);
151 }
Gabe Black29efa172011-11-08 22:57:38 -0800152
Randall Spanglerfb267152016-10-11 15:28:16 -0700153 fclose(f);
154 return (1 == res) ? 0 : -1;
Gabe Black29efa172011-11-08 22:57:38 -0800155}
156
157
Randall Spanglerfb267152016-10-11 15:28:16 -0700158int VbReadNvStorage(VbNvContext* vnc)
159{
160 unsigned offs, blksz;
Randall Spanglereb591952011-04-07 10:02:00 -0700161
Randall Spanglerfb267152016-10-11 15:28:16 -0700162 /* Get the byte offset from VBNV */
163 if (ReadFileInt(ACPI_VBNV_PATH ".0", &offs) < 0)
164 return -1;
165 if (ReadFileInt(ACPI_VBNV_PATH ".1", &blksz) < 0)
166 return -1;
167 if (VBNV_BLOCK_SIZE > blksz)
168 return -1; /* NV storage block is too small */
Randall Spanglereb591952011-04-07 10:02:00 -0700169
Randall Spanglerfb267152016-10-11 15:28:16 -0700170 if (0 != VbCmosRead(offs, VBNV_BLOCK_SIZE, vnc->raw))
171 return -1;
Randall Spanglereb591952011-04-07 10:02:00 -0700172
Randall Spanglerfb267152016-10-11 15:28:16 -0700173 return 0;
Randall Spanglereb591952011-04-07 10:02:00 -0700174}
175
176
Randall Spanglerd8a9ede2016-09-02 12:25:27 -0700177int VbWriteNvStorage(VbNvContext* vnc)
178{
Randall Spanglerfb267152016-10-11 15:28:16 -0700179 unsigned offs, blksz;
Randall Spanglereb591952011-04-07 10:02:00 -0700180
Randall Spanglerfb267152016-10-11 15:28:16 -0700181 if (!vnc->raw_changed)
182 return 0; /* Nothing changed, so no need to write */
Randall Spanglereb591952011-04-07 10:02:00 -0700183
Randall Spanglerfb267152016-10-11 15:28:16 -0700184 /* Get the byte offset from VBNV */
185 if (ReadFileInt(ACPI_VBNV_PATH ".0", &offs) < 0)
186 return -1;
187 if (ReadFileInt(ACPI_VBNV_PATH ".1", &blksz) < 0)
188 return -1;
189 if (VBNV_BLOCK_SIZE > blksz)
190 return -1; /* NV storage block is too small */
Randall Spanglereb591952011-04-07 10:02:00 -0700191
Randall Spanglerfb267152016-10-11 15:28:16 -0700192 if (0 != VbCmosWrite(offs, VBNV_BLOCK_SIZE, vnc->raw))
193 return -1;
Randall Spanglereb591952011-04-07 10:02:00 -0700194
Randall Spanglerfb267152016-10-11 15:28:16 -0700195 /* Also attempt to write using mosys if using vboot2 */
196 VbSharedDataHeader *sh = VbSharedDataRead();
197 if (sh) {
198 if (sh->flags & VBSD_BOOT_FIRMWARE_VBOOT2)
199 VbWriteNvStorage_mosys(vnc);
200 free(sh);
201 }
Duncan Laurieeb0c8cc2016-03-30 09:38:54 -0700202
Randall Spanglerfb267152016-10-11 15:28:16 -0700203 return 0;
Randall Spanglereb591952011-04-07 10:02:00 -0700204}
205
206
207/*
208 * Get buffer data from ACPI.
209 *
210 * Buffer data is expected to be represented by a file which is a text dump of
211 * the buffer, representing each byte by two hex numbers, space and newline
212 * separated.
213 *
214 * On success, stores the amount of data read in bytes to *buffer_size; on
215 * erros, sets *buffer_size=0.
216 *
217 * Input - ACPI file name to get data from.
218 *
219 * Output: a pointer to AcpiBuffer structure containing the binary
220 * representation of the data. The caller is responsible for
221 * deallocating the pointer, this will take care of both the structure
222 * and the buffer. Null in case of error.
223 */
Randall Spanglerfb267152016-10-11 15:28:16 -0700224static uint8_t* VbGetBuffer(const char* filename, int* buffer_size)
225{
226 FILE* f = NULL;
227 char* file_buffer = NULL;
228 uint8_t* output_buffer = NULL;
229 uint8_t* return_value = NULL;
Randall Spanglereb591952011-04-07 10:02:00 -0700230
Randall Spanglerfb267152016-10-11 15:28:16 -0700231 /* Assume error until proven otherwise */
232 if (buffer_size)
233 *buffer_size = 0;
Randall Spanglereb591952011-04-07 10:02:00 -0700234
Randall Spanglerfb267152016-10-11 15:28:16 -0700235 do {
236 struct stat fs;
237 uint8_t* output_ptr;
238 int rv, i, real_size;
239 int parsed_size = 0;
Randall Spanglereb591952011-04-07 10:02:00 -0700240
Randall Spanglerfb267152016-10-11 15:28:16 -0700241 rv = stat(filename, &fs);
242 if (rv || !S_ISREG(fs.st_mode))
243 break;
Randall Spanglereb591952011-04-07 10:02:00 -0700244
Randall Spanglerfb267152016-10-11 15:28:16 -0700245 f = fopen(filename, "r");
246 if (!f)
247 break;
Randall Spanglereb591952011-04-07 10:02:00 -0700248
Randall Spanglerfb267152016-10-11 15:28:16 -0700249 file_buffer = malloc(fs.st_size + 1);
250 if (!file_buffer)
251 break;
Randall Spanglereb591952011-04-07 10:02:00 -0700252
Randall Spanglerfb267152016-10-11 15:28:16 -0700253 real_size = fread(file_buffer, 1, fs.st_size, f);
254 if (!real_size)
255 break;
256 file_buffer[real_size] = '\0';
Randall Spanglereb591952011-04-07 10:02:00 -0700257
Randall Spanglerfb267152016-10-11 15:28:16 -0700258 /* Each byte in the output will replace two characters and a
259 * space in the input, so the output size does not exceed input
260 * side/3 (a little less if account for newline characters). */
261 output_buffer = malloc(real_size/3);
262 if (!output_buffer)
263 break;
264 output_ptr = output_buffer;
Randall Spanglereb591952011-04-07 10:02:00 -0700265
Randall Spanglerfb267152016-10-11 15:28:16 -0700266 /* process the file contents */
267 for (i = 0; i < real_size; i++) {
268 char* base, *end;
Randall Spanglereb591952011-04-07 10:02:00 -0700269
Randall Spanglerfb267152016-10-11 15:28:16 -0700270 base = file_buffer + i;
Randall Spanglereb591952011-04-07 10:02:00 -0700271
Randall Spanglerfb267152016-10-11 15:28:16 -0700272 if (!isxdigit(*base))
273 continue;
Randall Spanglereb591952011-04-07 10:02:00 -0700274
Randall Spanglerfb267152016-10-11 15:28:16 -0700275 output_ptr[parsed_size++] =
276 strtol(base, &end, 16) & 0xff;
Randall Spanglereb591952011-04-07 10:02:00 -0700277
Randall Spanglerfb267152016-10-11 15:28:16 -0700278 if ((end - base) != 2)
279 /* Input file format error */
280 break;
Randall Spanglereb591952011-04-07 10:02:00 -0700281
Randall Spanglerfb267152016-10-11 15:28:16 -0700282 /* skip the second character and the following space */
283 i += 2;
284 }
Randall Spanglereb591952011-04-07 10:02:00 -0700285
Randall Spanglerfb267152016-10-11 15:28:16 -0700286 if (i == real_size) {
287 /* all is well */
288 return_value = output_buffer;
289 output_buffer = NULL; /* prevent it from deallocating */
290 if (buffer_size)
291 *buffer_size = parsed_size;
292 }
293 } while(0);
Randall Spanglereb591952011-04-07 10:02:00 -0700294
Randall Spanglerfb267152016-10-11 15:28:16 -0700295 /* wrap up */
296 if (f)
297 fclose(f);
Randall Spanglereb591952011-04-07 10:02:00 -0700298
Randall Spanglerfb267152016-10-11 15:28:16 -0700299 if (file_buffer)
300 free(file_buffer);
Randall Spanglereb591952011-04-07 10:02:00 -0700301
Randall Spanglerfb267152016-10-11 15:28:16 -0700302 if (output_buffer)
303 free(output_buffer);
Randall Spanglereb591952011-04-07 10:02:00 -0700304
Randall Spanglerfb267152016-10-11 15:28:16 -0700305 return return_value;
Randall Spanglereb591952011-04-07 10:02:00 -0700306}
307
308
Randall Spanglerfb267152016-10-11 15:28:16 -0700309VbSharedDataHeader* VbSharedDataRead(void)
310{
311 VbSharedDataHeader* sh;
312 int got_size = 0;
313 int expect_size;
Randall Spanglereb591952011-04-07 10:02:00 -0700314
Randall Spanglerfb267152016-10-11 15:28:16 -0700315 sh = (VbSharedDataHeader*)VbGetBuffer(ACPI_VDAT_PATH, &got_size);
316 if (!sh)
317 return NULL;
Randall Spangler7adcc602011-06-24 16:11:45 -0700318
Randall Spanglerfb267152016-10-11 15:28:16 -0700319 /* Make sure the size is sufficient for the struct version we got.
320 * Check supported old versions first. */
321 if (1 == sh->struct_version)
322 expect_size = VB_SHARED_DATA_HEADER_SIZE_V1;
323 else {
324 /* There'd better be enough data for the current header size. */
325 expect_size = sizeof(VbSharedDataHeader);
326 }
Randall Spangler7adcc602011-06-24 16:11:45 -0700327
Randall Spanglerfb267152016-10-11 15:28:16 -0700328 if (got_size < expect_size) {
329 free(sh);
330 return NULL;
331 }
332 if (sh->data_size > got_size)
333 sh->data_size = got_size; /* Truncated read */
Randall Spanglereb591952011-04-07 10:02:00 -0700334
Randall Spanglerfb267152016-10-11 15:28:16 -0700335 return sh;
Randall Spanglereb591952011-04-07 10:02:00 -0700336}
337
338
339/* Read the CMOS reboot field in NVRAM.
340 *
341 * Returns 0 if the mask is clear in the field, 1 if set, or -1 if error. */
Randall Spanglerfb267152016-10-11 15:28:16 -0700342static int VbGetCmosRebootField(uint8_t mask)
343{
344 unsigned chnv;
345 uint8_t nvbyte;
Randall Spanglereb591952011-04-07 10:02:00 -0700346
Randall Spanglerfb267152016-10-11 15:28:16 -0700347 /* Get the byte offset from CHNV */
348 if (ReadFileInt(ACPI_CHNV_PATH, &chnv) < 0)
349 return -1;
Randall Spanglereb591952011-04-07 10:02:00 -0700350
Randall Spanglerfb267152016-10-11 15:28:16 -0700351 if (0 != VbCmosRead(chnv, 1, &nvbyte))
352 return -1;
Randall Spanglereb591952011-04-07 10:02:00 -0700353
Randall Spanglerfb267152016-10-11 15:28:16 -0700354 return (nvbyte & mask ? 1 : 0);
Randall Spanglereb591952011-04-07 10:02:00 -0700355}
356
357
358/* Write the CMOS reboot field in NVRAM.
359 *
360 * Sets (value=0) or clears (value!=0) the mask in the byte.
361 *
362 * Returns 0 if success, or -1 if error. */
Randall Spanglerfb267152016-10-11 15:28:16 -0700363static int VbSetCmosRebootField(uint8_t mask, int value)
364{
365 unsigned chnv;
366 uint8_t nvbyte;
Randall Spanglereb591952011-04-07 10:02:00 -0700367
Randall Spanglerfb267152016-10-11 15:28:16 -0700368 /* Get the byte offset from CHNV */
369 if (ReadFileInt(ACPI_CHNV_PATH, &chnv) < 0)
370 return -1;
Randall Spanglereb591952011-04-07 10:02:00 -0700371
Randall Spanglerfb267152016-10-11 15:28:16 -0700372 if (0 != VbCmosRead(chnv, 1, &nvbyte))
373 return -1;
Randall Spanglereb591952011-04-07 10:02:00 -0700374
Randall Spanglerfb267152016-10-11 15:28:16 -0700375 /* Set/clear the mask */
376 if (value)
377 nvbyte |= mask;
378 else
379 nvbyte &= ~mask;
Randall Spanglereb591952011-04-07 10:02:00 -0700380
Randall Spanglerfb267152016-10-11 15:28:16 -0700381 /* Write the byte back */
382 if (0 != VbCmosWrite(chnv, 1, &nvbyte))
383 return -1;
Randall Spanglereb591952011-04-07 10:02:00 -0700384
Randall Spanglerfb267152016-10-11 15:28:16 -0700385 /* Success */
386 return 0;
Randall Spanglereb591952011-04-07 10:02:00 -0700387}
388
389
390/* Read the active main firmware type into the destination buffer.
391 * Passed the destination and its size. Returns the destination, or
392 * NULL if error. */
Randall Spanglerfb267152016-10-11 15:28:16 -0700393static const char* VbReadMainFwType(char* dest, int size)
394{
395 unsigned value;
Randall Spanglereb591952011-04-07 10:02:00 -0700396
Randall Spanglerfb267152016-10-11 15:28:16 -0700397 /* Try reading type from BINF.3 */
398 if (ReadFileInt(ACPI_BINF_PATH ".3", &value) == 0) {
399 switch(value) {
400 case BINF3_NETBOOT:
401 return StrCopy(dest, "netboot", size);
402 case BINF3_RECOVERY:
403 return StrCopy(dest, "recovery", size);
404 case BINF3_NORMAL:
405 return StrCopy(dest, "normal", size);
406 case BINF3_DEVELOPER:
407 return StrCopy(dest, "developer", size);
408 default:
409 break; /* Fall through to legacy handling */
410 }
411 }
Randall Spanglereb591952011-04-07 10:02:00 -0700412
Randall Spanglerfb267152016-10-11 15:28:16 -0700413 /* Fall back to BINF.0 for legacy systems like Mario. */
414 if (ReadFileInt(ACPI_BINF_PATH ".0", &value) < 0)
415 /* Both BINF.0 and BINF.3 are missing, so this isn't Chrome OS
416 * firmware. */
417 return StrCopy(dest, "nonchrome", size);
Duncan Lauried241fff2014-10-13 08:11:09 -0700418
Randall Spanglerfb267152016-10-11 15:28:16 -0700419 switch(value) {
420 case BINF0_NORMAL:
421 return StrCopy(dest, "normal", size);
422 case BINF0_DEVELOPER:
423 return StrCopy(dest, "developer", size);
424 case BINF0_RECOVERY_BUTTON:
425 case BINF0_RECOVERY_DEV_SCREEN_KEY:
426 case BINF0_RECOVERY_RW_FW_BAD:
427 case BINF0_RECOVERY_NO_OS:
428 case BINF0_RECOVERY_BAD_OS:
429 case BINF0_RECOVERY_OS_INITIATED:
430 case BINF0_RECOVERY_TPM_ERROR:
431 /* Assorted flavors of recovery boot reason. */
432 return StrCopy(dest, "recovery", size);
433 default:
434 /* Other values don't map cleanly to firmware type. */
435 return NULL;
436 }
Randall Spanglereb591952011-04-07 10:02:00 -0700437}
438
439
440/* Read the recovery reason. Returns the reason code or -1 if error. */
Randall Spanglerfb267152016-10-11 15:28:16 -0700441static int VbGetRecoveryReason(void)
442{
443 unsigned value;
Randall Spangler7adcc602011-06-24 16:11:45 -0700444
Randall Spanglerfb267152016-10-11 15:28:16 -0700445 /* Try reading type from BINF.4 */
446 if (ReadFileInt(ACPI_BINF_PATH ".4", &value) == 0)
447 return value;
Randall Spanglereb591952011-04-07 10:02:00 -0700448
Randall Spanglerfb267152016-10-11 15:28:16 -0700449 /* Fall back to BINF.0 for legacy systems like Mario. */
450 if (ReadFileInt(ACPI_BINF_PATH ".0", &value) < 0)
451 return -1;
452 switch(value) {
453 case BINF0_NORMAL:
454 case BINF0_DEVELOPER:
455 return VBNV_RECOVERY_NOT_REQUESTED;
456 case BINF0_RECOVERY_BUTTON:
457 return VBNV_RECOVERY_RO_MANUAL;
458 case BINF0_RECOVERY_DEV_SCREEN_KEY:
459 return VBNV_RECOVERY_RW_DEV_SCREEN;
460 case BINF0_RECOVERY_RW_FW_BAD:
461 return VBNV_RECOVERY_RO_INVALID_RW;
462 case BINF0_RECOVERY_NO_OS:
463 return VBNV_RECOVERY_RW_NO_OS;
464 case BINF0_RECOVERY_BAD_OS:
465 return VBNV_RECOVERY_RW_INVALID_OS;
466 case BINF0_RECOVERY_OS_INITIATED:
467 return VBNV_RECOVERY_LEGACY;
468 default:
469 /* Other values don't map cleanly to firmware type. */
470 return -1;
471 }
Randall Spanglereb591952011-04-07 10:02:00 -0700472}
473
Bill Richardson1a4d03d2011-08-31 12:01:13 -0700474/* Physical GPIO number <N> may be accessed through /sys/class/gpio/gpio<M>/,
475 * but <N> and <M> may differ by some offset <O>. To determine that constant,
476 * we look for a directory named /sys/class/gpio/gpiochip<O>/. If there's not
477 * exactly one match for that, we're SOL.
478 */
Duncan Laurie8bb36892014-10-17 14:35:33 -0700479static int FindGpioChipOffset(unsigned *gpio_num, unsigned *offset,
Randall Spanglerfb267152016-10-11 15:28:16 -0700480 const char *name)
481{
482 DIR *dir;
483 struct dirent *ent;
484 int match = 0;
Bill Richardson1a4d03d2011-08-31 12:01:13 -0700485
Randall Spanglerfb267152016-10-11 15:28:16 -0700486 dir = opendir(GPIO_BASE_PATH);
487 if (!dir) {
488 return 0;
489 }
Bill Richardson1a4d03d2011-08-31 12:01:13 -0700490
Randall Spanglerfb267152016-10-11 15:28:16 -0700491 while(0 != (ent = readdir(dir))) {
492 if (1 == sscanf(ent->d_name, "gpiochip%u", offset)) {
493 match++;
494 }
495 }
Bill Richardson1a4d03d2011-08-31 12:01:13 -0700496
Randall Spanglerfb267152016-10-11 15:28:16 -0700497 closedir(dir);
498 return (1 == match);
Bill Richardson1a4d03d2011-08-31 12:01:13 -0700499}
500
Duncan Laurie8bb36892014-10-17 14:35:33 -0700501/* Physical GPIO number <N> may be accessed through /sys/class/gpio/gpio<M>/,
502 * but <N> and <M> may differ by some offset <O>. To determine that constant,
503 * we look for a directory named /sys/class/gpio/gpiochip<O>/ and check for
504 * a 'label' file inside of it to find the expected the controller name.
505 */
506static int FindGpioChipOffsetByLabel(unsigned *gpio_num, unsigned *offset,
Randall Spanglerfb267152016-10-11 15:28:16 -0700507 const char *name)
508{
509 DIR *dir;
510 struct dirent *ent;
511 char filename[128];
512 char chiplabel[128];
513 int match = 0;
514 unsigned controller_offset = 0;
Duncan Laurie8bb36892014-10-17 14:35:33 -0700515
Randall Spanglerfb267152016-10-11 15:28:16 -0700516 dir = opendir(GPIO_BASE_PATH);
517 if (!dir) {
518 return 0;
519 }
Duncan Laurie8bb36892014-10-17 14:35:33 -0700520
Randall Spanglerfb267152016-10-11 15:28:16 -0700521 while(0 != (ent = readdir(dir))) {
522 if (1 == sscanf(ent->d_name, "gpiochip%u",
523 &controller_offset)) {
524 /*
525 * Read the file at gpiochip<O>/label to get the
526 * identifier for this bank of GPIOs.
527 */
528 snprintf(filename, sizeof(filename),
529 "%s/gpiochip%u/label",
530 GPIO_BASE_PATH, controller_offset);
531 if (ReadFileString(chiplabel, sizeof(chiplabel),
532 filename)) {
533 if (!strncasecmp(chiplabel, name,
534 strlen(name))) {
535 /*
536 * Store offset when chip label is
537 * matched.
538 */
539 *offset = controller_offset;
540 match++;
541 }
542 }
543 }
544 }
Duncan Laurie8bb36892014-10-17 14:35:33 -0700545
Randall Spanglerfb267152016-10-11 15:28:16 -0700546 closedir(dir);
547 return (1 == match);
Duncan Laurie8bb36892014-10-17 14:35:33 -0700548}
549
John Zhao5f16cce2015-04-02 10:24:51 -0700550static int FindGpioChipOffsetByNumber(unsigned *gpio_num, unsigned *offset,
Randall Spanglerfb267152016-10-11 15:28:16 -0700551 Basemapping *data)
552{
553 DIR *dir;
554 struct dirent *ent;
555 int match = 0;
Aaron Durbin1aa59b02013-12-10 16:05:30 -0800556
Randall Spanglerfb267152016-10-11 15:28:16 -0700557 /* Obtain relative GPIO number.
558 * The assumption here is the Basemapping
559 * table is arranged in decreasing order of
560 * base address and ends with 0.
561 * A UID with value 0 indicates an invalid range
562 * and causes an early return to avoid the directory
563 * opening code below.
564 */
565 do {
566 if (*gpio_num >= data->base) {
567 *gpio_num -= data->base;
568 break;
569 }
570 data++;
571 } while(1);
John Zhao5f16cce2015-04-02 10:24:51 -0700572
Randall Spanglerfb267152016-10-11 15:28:16 -0700573 if (data->uid == 0) {
574 return 0;
575 }
Aaron Durbin1aa59b02013-12-10 16:05:30 -0800576
Randall Spanglerfb267152016-10-11 15:28:16 -0700577 dir = opendir(GPIO_BASE_PATH);
578 if (!dir) {
579 return 0;
580 }
Aaron Durbin1aa59b02013-12-10 16:05:30 -0800581
Randall Spanglerfb267152016-10-11 15:28:16 -0700582 while(0 != (ent = readdir(dir))) {
583 /* For every gpiochip entry determine uid. */
584 if (1 == sscanf(ent->d_name, "gpiochip%u", offset)) {
585 char uid_file[128];
586 unsigned uid_value;
587 snprintf(uid_file, sizeof(uid_file),
588 "%s/gpiochip%u/device/firmware_node/uid",
589 GPIO_BASE_PATH, *offset);
590 if (ReadFileInt(uid_file, &uid_value) < 0)
591 continue;
592 if (data->uid == uid_value) {
593 match++;
594 break;
595 }
596 }
597 }
Aaron Durbin1aa59b02013-12-10 16:05:30 -0800598
Randall Spanglerfb267152016-10-11 15:28:16 -0700599 closedir(dir);
600 return (1 == match);
Aaron Durbin1aa59b02013-12-10 16:05:30 -0800601}
602
Bill Richardson1a4d03d2011-08-31 12:01:13 -0700603
Randall Spanglerfb267152016-10-11 15:28:16 -0700604/* Braswell has 4 sets of GPIO banks. It is expected the firmware exposes each
605 * bank of gpios using a UID in ACPI. Furthermore the gpio number exposed is
606 * relative to the bank. e.g. gpio MF_ISH_GPIO_4 in the bank specified by UID 3
John Zhao5f16cce2015-04-02 10:24:51 -0700607 * would be encoded as 0x10016.
Randall Spanglerfb267152016-10-11 15:28:16 -0700608 *
John Zhao5f16cce2015-04-02 10:24:51 -0700609 * UID | Bank Offset
610 * ----+------------
611 * 1 | 0x0000
612 * 2 | 0x8000
613 * 3 | 0x10000
614 * 4 | 0x18000
615 */
616static int BraswellFindGpioChipOffset(unsigned *gpio_num, unsigned *offset,
Randall Spanglerfb267152016-10-11 15:28:16 -0700617 const char *name)
618{
619 static Basemapping data[]={
620 {0x20000, 0},
621 {0x18000, 4},
622 {0x10000, 3},
623 {0x08000, 2},
624 {0x00000, 1}};
John Zhao5f16cce2015-04-02 10:24:51 -0700625
Randall Spanglerfb267152016-10-11 15:28:16 -0700626 return FindGpioChipOffsetByNumber(gpio_num, offset, data);
John Zhao5f16cce2015-04-02 10:24:51 -0700627}
628
629/* BayTrail has 3 sets of GPIO banks. It is expected the firmware exposes
630 * each bank of gpios using a UID in ACPI. Furthermore the gpio number exposed
631 * is relative to the bank. e.g. gpio 6 in the bank specified by UID 3 would
632 * be encoded as 0x2006.
633 * UID | Bank Offset
634 * ----+------------
635 * 1 | 0x0000
636 * 2 | 0x1000
637 * 3 | 0x2000
638 */
639static int BayTrailFindGpioChipOffset(unsigned *gpio_num, unsigned *offset,
Randall Spanglerfb267152016-10-11 15:28:16 -0700640 const char *name)
641{
642 static Basemapping data[]={
643 {0x3000, 0},
644 {0x2000, 3},
645 {0x1000, 2},
646 {0x0000, 1}};
John Zhao5f16cce2015-04-02 10:24:51 -0700647
Randall Spanglerfb267152016-10-11 15:28:16 -0700648 return FindGpioChipOffsetByNumber(gpio_num, offset, data);
John Zhao5f16cce2015-04-02 10:24:51 -0700649}
650
Aaron Durbin31912b62013-12-10 14:58:03 -0800651struct GpioChipset {
Randall Spanglerfb267152016-10-11 15:28:16 -0700652 const char *name;
653 int (*ChipOffsetAndGpioNumber)(unsigned *gpio_num,
654 unsigned *chip_offset,
655 const char *name);
Aaron Durbin31912b62013-12-10 14:58:03 -0800656};
657
658static const struct GpioChipset chipsets_supported[] = {
Randall Spanglerfb267152016-10-11 15:28:16 -0700659 { "NM10", FindGpioChipOffset },
660 { "CougarPoint", FindGpioChipOffset },
661 { "PantherPoint", FindGpioChipOffset },
662 { "LynxPoint", FindGpioChipOffset },
663 { "PCH-LP", FindGpioChipOffset },
664 { "INT3437:00", FindGpioChipOffsetByLabel },
665 { "INT344B:00", FindGpioChipOffsetByLabel },
666 /* INT3452 are for Apollolake */
667 { "INT3452:00", FindGpioChipOffsetByLabel },
668 { "INT3452:01", FindGpioChipOffsetByLabel },
669 { "INT3452:02", FindGpioChipOffsetByLabel },
670 { "INT3452:03", FindGpioChipOffsetByLabel },
671 { "BayTrail", BayTrailFindGpioChipOffset },
672 { "Braswell", BraswellFindGpioChipOffset },
673 { NULL },
Aaron Durbin31912b62013-12-10 14:58:03 -0800674};
675
Randall Spanglerfb267152016-10-11 15:28:16 -0700676static const struct GpioChipset *FindChipset(const char *name)
677{
678 const struct GpioChipset *chipset = &chipsets_supported[0];
Aaron Durbin31912b62013-12-10 14:58:03 -0800679
Randall Spanglerfb267152016-10-11 15:28:16 -0700680 while (chipset->name != NULL) {
681 if (!strcmp(name, chipset->name))
682 return chipset;
683 chipset++;
684 }
685 return NULL;
Aaron Durbin31912b62013-12-10 14:58:03 -0800686}
687
Randall Spanglereb591952011-04-07 10:02:00 -0700688/* Read a GPIO of the specified signal type (see ACPI GPIO SignalType).
689 *
690 * Returns 1 if the signal is asserted, 0 if not asserted, or -1 if error. */
Randall Spanglerfb267152016-10-11 15:28:16 -0700691static int ReadGpio(unsigned signal_type)
692{
693 char name[128];
694 int index = 0;
695 unsigned gpio_type;
696 unsigned active_high;
697 unsigned controller_num;
698 unsigned controller_offset = 0;
699 char controller_name[128];
700 unsigned value;
701 const struct GpioChipset *chipset;
Randall Spanglereb591952011-04-07 10:02:00 -0700702
Randall Spanglerfb267152016-10-11 15:28:16 -0700703 /* Scan GPIO.* to find a matching signal type */
704 for (index = 0; ; index++) {
705 snprintf(name, sizeof(name), "%s.%d/GPIO.0", ACPI_GPIO_PATH,
706 index);
707 if (ReadFileInt(name, &gpio_type) < 0)
708 return -1; /* Ran out of GPIOs before finding a match */
709 if (gpio_type == signal_type)
710 break;
711 }
Randall Spanglereb591952011-04-07 10:02:00 -0700712
Randall Spanglerfb267152016-10-11 15:28:16 -0700713 /* Read attributes and controller info for the GPIO */
714 snprintf(name, sizeof(name), "%s.%d/GPIO.1", ACPI_GPIO_PATH, index);
715 if (ReadFileInt(name, &active_high) < 0)
716 return -1;
717 snprintf(name, sizeof(name), "%s.%d/GPIO.2", ACPI_GPIO_PATH, index);
718 if (ReadFileInt(name, &controller_num) < 0)
719 return -1;
720 /* Do not attempt to read GPIO that is set to -1 in ACPI */
721 if (controller_num == 0xFFFFFFFF)
722 return -1;
Randall Spanglereb591952011-04-07 10:02:00 -0700723
Randall Spanglerfb267152016-10-11 15:28:16 -0700724 /* Check for chipsets we recognize. */
725 snprintf(name, sizeof(name), "%s.%d/GPIO.3", ACPI_GPIO_PATH, index);
726 if (!ReadFileString(controller_name, sizeof(controller_name), name))
727 return -1;
728 chipset = FindChipset(controller_name);
729 if (chipset == NULL)
730 return -1;
Randall Spanglereb591952011-04-07 10:02:00 -0700731
Randall Spanglerfb267152016-10-11 15:28:16 -0700732 /* Modify GPIO number by driver's offset */
733 if (!chipset->ChipOffsetAndGpioNumber(&controller_num,
734 &controller_offset,
735 chipset->name))
736 return -1;
737 controller_offset += controller_num;
Randall Spanglereb591952011-04-07 10:02:00 -0700738
Randall Spanglerfb267152016-10-11 15:28:16 -0700739 /* Try reading the GPIO value */
740 snprintf(name, sizeof(name), "%s/gpio%d/value",
741 GPIO_BASE_PATH, controller_offset);
742 if (ReadFileInt(name, &value) < 0) {
743 /* Try exporting the GPIO */
744 FILE* f = fopen(GPIO_EXPORT_PATH, "wt");
745 if (!f)
746 return -1;
747 fprintf(f, "%u", controller_offset);
748 fclose(f);
Randall Spanglereb591952011-04-07 10:02:00 -0700749
Randall Spanglerfb267152016-10-11 15:28:16 -0700750 /* Try re-reading the GPIO value */
751 if (ReadFileInt(name, &value) < 0)
752 return -1;
753 }
Randall Spanglereb591952011-04-07 10:02:00 -0700754
Randall Spanglerfb267152016-10-11 15:28:16 -0700755 /* Normalize the value read from the kernel in case it is not always
756 * 1. */
757 value = value ? 1 : 0;
Randall Spanglereb591952011-04-07 10:02:00 -0700758
Randall Spanglerfb267152016-10-11 15:28:16 -0700759 /* Compare the GPIO value with the active value and return 1 if
760 * match. */
761 return (value == active_high ? 1 : 0);
Randall Spanglereb591952011-04-07 10:02:00 -0700762}
763
764
Randall Spanglerfb267152016-10-11 15:28:16 -0700765int VbGetArchPropertyInt(const char* name)
766{
767 int value = -1;
Randall Spanglereb591952011-04-07 10:02:00 -0700768
Randall Spanglerfb267152016-10-11 15:28:16 -0700769 /* Values from ACPI */
770 if (!strcasecmp(name,"fmap_base")) {
771 unsigned fmap_base;
772 if (ReadFileInt(ACPI_FMAP_PATH, &fmap_base) < 0)
773 return -1;
774 else
775 value = (int)fmap_base;
776 }
Randall Spanglerda8d32d2012-08-03 12:48:24 -0700777
Randall Spanglerfb267152016-10-11 15:28:16 -0700778 /* Switch positions */
779 if (!strcasecmp(name,"devsw_cur")) {
780 /* Systems with virtual developer switches return at-boot
781 * value */
782 int flags = VbGetSystemPropertyInt("vdat_flags");
783 if ((flags != -1) && (flags & VBSD_HONOR_VIRT_DEV_SWITCH))
784 value = VbGetSystemPropertyInt("devsw_boot");
785 else
786 value = ReadGpio(GPIO_SIGNAL_TYPE_DEV);
787 } else if (!strcasecmp(name,"recoverysw_cur")) {
788 value = ReadGpio(GPIO_SIGNAL_TYPE_RECOVERY);
789 } else if (!strcasecmp(name,"wpsw_cur")) {
790 value = ReadGpio(GPIO_SIGNAL_TYPE_WP);
791 if (-1 != value && FwidStartsWith("Mario."))
792 value = 1 - value; /* Mario reports this backwards */
793 } else if (!strcasecmp(name,"recoverysw_ec_boot")) {
794 value = ReadFileBit(ACPI_CHSW_PATH, CHSW_RECOVERY_EC_BOOT);
795 }
Randall Spanglerda8d32d2012-08-03 12:48:24 -0700796
Randall Spanglerfb267152016-10-11 15:28:16 -0700797 /* Fields for old systems which don't have VbSharedData */
798 if (VbSharedDataVersion() < 2) {
799 if (!strcasecmp(name,"recovery_reason")) {
800 value = VbGetRecoveryReason();
801 } else if (!strcasecmp(name,"devsw_boot")) {
802 value = ReadFileBit(ACPI_CHSW_PATH, CHSW_DEV_BOOT);
803 } else if (!strcasecmp(name,"recoverysw_boot")) {
804 value = ReadFileBit(ACPI_CHSW_PATH, CHSW_RECOVERY_BOOT);
805 } else if (!strcasecmp(name,"wpsw_boot")) {
806 value = ReadFileBit(ACPI_CHSW_PATH, CHSW_WP_BOOT);
807 if (-1 != value && FwidStartsWith("Mario."))
808 value = 1 - value; /* Mario reports this
809 * backwards */
810 }
811 }
Randall Spanglereb591952011-04-07 10:02:00 -0700812
Randall Spanglerfb267152016-10-11 15:28:16 -0700813 /* NV storage values. If unable to get from NV storage, fall back to
814 * the CMOS reboot field used by older BIOS (e.g. Mario). */
815 if (!strcasecmp(name,"recovery_request")) {
816 value = VbGetNvStorage(VBNV_RECOVERY_REQUEST);
817 if (-1 == value)
818 value = VbGetCmosRebootField(CMOSRF_RECOVERY);
819 } else if (!strcasecmp(name,"dbg_reset")) {
820 value = VbGetNvStorage(VBNV_DEBUG_RESET_MODE);
821 if (-1 == value)
822 value = VbGetCmosRebootField(CMOSRF_DEBUG_RESET);
823 } else if (!strcasecmp(name,"fwb_tries")) {
824 value = VbGetNvStorage(VBNV_TRY_B_COUNT);
825 if (-1 == value)
826 value = VbGetCmosRebootField(CMOSRF_TRY_B);
827 }
Randall Spanglerda8d32d2012-08-03 12:48:24 -0700828
Randall Spanglerfb267152016-10-11 15:28:16 -0700829 /* Firmware update tries is now stored in the kernel field. On
830 * older systems where it's not, it was stored in a file in the
831 * stateful partition. */
832 if (!strcasecmp(name,"fwupdate_tries")) {
833 unsigned fwupdate_value;
834 if (-1 != VbGetNvStorage(VBNV_KERNEL_FIELD))
835 return -1; /* NvStorage supported; fail through
836 * arch-specific implementation to normal
837 * implementation. */
838 /* Read value from file; missing file means value=0. */
839 if (ReadFileInt(NEED_FWUPDATE_PATH, &fwupdate_value) < 0)
840 value = 0;
841 else
842 value = (int)fwupdate_value;
843 }
Randall Spanglereb591952011-04-07 10:02:00 -0700844
Randall Spanglerfb267152016-10-11 15:28:16 -0700845 return value;
Randall Spanglereb591952011-04-07 10:02:00 -0700846}
847
848
J. Richard Barnettea3d70a32013-10-30 11:36:45 -0700849const char* VbGetArchPropertyString(const char* name, char* dest,
Randall Spanglerfb267152016-10-11 15:28:16 -0700850 size_t size)
851{
852 unsigned value;
Randall Spanglereb591952011-04-07 10:02:00 -0700853
Randall Spanglerfb267152016-10-11 15:28:16 -0700854 if (!strcasecmp(name,"arch")) {
855 return StrCopy(dest, "x86", size);
856 } else if (!strcasecmp(name,"hwid")) {
857 return ReadFileString(dest, size, ACPI_BASE_PATH "/HWID");
858 } else if (!strcasecmp(name,"fwid")) {
859 return ReadFileString(dest, size, ACPI_BASE_PATH "/FWID");
860 } else if (!strcasecmp(name,"ro_fwid")) {
861 return ReadFileString(dest, size, ACPI_BASE_PATH "/FRID");
862 } else if (!strcasecmp(name,"mainfw_act")) {
863 if (ReadFileInt(ACPI_BINF_PATH ".1", &value) < 0)
864 return NULL;
865 switch(value) {
866 case 0:
867 return StrCopy(dest, "recovery", size);
868 case 1:
869 return StrCopy(dest, "A", size);
870 case 2:
871 return StrCopy(dest, "B", size);
872 default:
873 return NULL;
874 }
875 } else if (!strcasecmp(name,"mainfw_type")) {
876 return VbReadMainFwType(dest, size);
877 } else if (!strcasecmp(name,"ecfw_act")) {
878 if (ReadFileInt(ACPI_BINF_PATH ".2", &value) < 0)
879 return NULL;
880 switch(value) {
881 case 0:
882 return StrCopy(dest, "RO", size);
883 case 1:
884 return StrCopy(dest, "RW", size);
885 default:
886 return NULL;
887 }
888 }
Randall Spanglereb591952011-04-07 10:02:00 -0700889
Randall Spanglerfb267152016-10-11 15:28:16 -0700890 return NULL;
Randall Spanglereb591952011-04-07 10:02:00 -0700891}
892
893
Randall Spanglerfb267152016-10-11 15:28:16 -0700894int VbSetArchPropertyInt(const char* name, int value)
895{
896 /* NV storage values. If unable to get from NV storage, fall back to
897 * the CMOS reboot field used by older BIOS. */
898 if (!strcasecmp(name,"recovery_request")) {
899 if (0 == VbSetNvStorage(VBNV_RECOVERY_REQUEST, value))
900 return 0;
901 return VbSetCmosRebootField(CMOSRF_RECOVERY, value);
902 } else if (!strcasecmp(name,"dbg_reset")) {
903 if (0 == VbSetNvStorage(VBNV_DEBUG_RESET_MODE, value))
904 return 0;
905 return VbSetCmosRebootField(CMOSRF_DEBUG_RESET, value);
906 } else if (!strcasecmp(name,"fwb_tries")) {
907 if (0 == VbSetNvStorage(VBNV_TRY_B_COUNT, value))
908 return 0;
909 return VbSetCmosRebootField(CMOSRF_TRY_B, value);
910 }
911 /* Firmware update tries is now stored in the kernel field. On
912 * older systems where it's not, it was stored in a file in the
913 * stateful partition. */
914 else if (!strcasecmp(name,"fwupdate_tries")) {
915 if (-1 != VbGetNvStorage(VBNV_KERNEL_FIELD))
916 return -1; /* NvStorage supported; fail through
917 * arch-specific implementation to normal
918 * implementation */
Randall Spangler07f34842011-04-11 13:35:06 -0700919
Randall Spanglerfb267152016-10-11 15:28:16 -0700920 if (value) {
921 char buf[32];
922 snprintf(buf, sizeof(buf), "%d", value);
923 return WriteFile(NEED_FWUPDATE_PATH, buf, strlen(buf));
924 } else {
925 /* No update tries, so remove file if it exists. */
926 unlink(NEED_FWUPDATE_PATH);
927 return 0;
928 }
929 }
Randall Spanglereb591952011-04-07 10:02:00 -0700930
Randall Spanglerfb267152016-10-11 15:28:16 -0700931 return -1;
Randall Spanglereb591952011-04-07 10:02:00 -0700932}
933
Randall Spanglerfb267152016-10-11 15:28:16 -0700934int VbSetArchPropertyString(const char* name, const char* value)
935{
936 /* If there were settable architecture-dependent string properties,
937 * they'd be here. */
938 return -1;
Randall Spanglereb591952011-04-07 10:02:00 -0700939}