OLD | NEW |
1 /* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. | 1 /* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. |
2 * Use of this source code is governed by a BSD-style license that can be | 2 * Use of this source code is governed by a BSD-style license that can be |
3 * found in the LICENSE file. | 3 * found in the LICENSE file. |
4 */ | 4 */ |
5 | 5 |
6 #include <stdio.h> | 6 #include <stdio.h> |
7 #include <string.h> | 7 #include <string.h> |
8 #include <sys/types.h> | 8 #include <sys/types.h> |
9 #include <sys/stat.h> | 9 #include <sys/stat.h> |
10 #include <unistd.h> | 10 #include <unistd.h> |
11 #include <ctype.h> | 11 #include <ctype.h> |
12 | 12 |
13 #include "host_common.h" | 13 #include "host_common.h" |
14 | 14 |
15 #include "crossystem.h" | 15 #include "crossystem.h" |
| 16 #include "crossystem_arch.h" |
16 #include "utility.h" | 17 #include "utility.h" |
17 #include "vboot_common.h" | 18 #include "vboot_common.h" |
18 #include "vboot_nvstorage.h" | 19 #include "vboot_nvstorage.h" |
19 #include "vboot_struct.h" | 20 #include "vboot_struct.h" |
20 | 21 |
21 /* ACPI constants from Chrome OS Main Processor Firmware Spec */ | |
22 /* GPIO signal types */ | |
23 #define GPIO_SIGNAL_TYPE_RECOVERY 1 | |
24 #define GPIO_SIGNAL_TYPE_DEV 2 | |
25 #define GPIO_SIGNAL_TYPE_WP 3 | |
26 /* CHSW bitflags */ | |
27 #define CHSW_RECOVERY_BOOT 0x00000002 | |
28 #define CHSW_RECOVERY_EC_BOOT 0x00000004 | |
29 #define CHSW_DEV_BOOT 0x00000020 | |
30 #define CHSW_WP_BOOT 0x00000200 | |
31 /* CMOS reboot field bitflags */ | |
32 #define CMOSRF_RECOVERY 0x80 | |
33 #define CMOSRF_DEBUG_RESET 0x40 | |
34 #define CMOSRF_TRY_B 0x20 | |
35 /* Boot reasons from BINF.0, from early H2C firmware */ | |
36 /* Unknown */ | |
37 #define BINF0_UNKNOWN 0 | |
38 /* Normal boot to Chrome OS */ | |
39 #define BINF0_NORMAL 1 | |
40 /* Developer mode boot (developer mode warning displayed) */ | |
41 #define BINF0_DEVELOPER 2 | |
42 /* Recovery initiated by user, using recovery button */ | |
43 #define BINF0_RECOVERY_BUTTON 3 | |
44 /* Recovery initiated by user pressing a key at developer mode warning | |
45 * screen */ | |
46 #define BINF0_RECOVERY_DEV_SCREEN_KEY 4 | |
47 /* Recovery caused by BIOS failed signature check (neither rewritable | |
48 * firmware was valid) */ | |
49 #define BINF0_RECOVERY_RW_FW_BAD 5 | |
50 /* Recovery caused by no OS kernel detected */ | |
51 #define BINF0_RECOVERY_NO_OS 6 | |
52 /* Recovery caused by OS kernel failed signature check */ | |
53 #define BINF0_RECOVERY_BAD_OS 7 | |
54 /* Recovery initiated by OS */ | |
55 #define BINF0_RECOVERY_OS_INITIATED 8 | |
56 /* OS-initiated S3 diagnostic path (debug mode boot) */ | |
57 #define BINF0_S3_DIAGNOSTIC_PATH 9 | |
58 /* S3 resume failed */ | |
59 #define BINF0_S3_RESUME_FAILED 10 | |
60 /* Recovery caused by TPM error */ | |
61 #define BINF0_RECOVERY_TPM_ERROR 11 | |
62 /* Firmware types from BINF.3 */ | |
63 #define BINF3_RECOVERY 0 | |
64 #define BINF3_NORMAL 1 | |
65 #define BINF3_DEVELOPER 2 | |
66 | |
67 /* Base name for ACPI files */ | |
68 #define ACPI_BASE_PATH "/sys/devices/platform/chromeos_acpi" | |
69 /* Paths for frequently used ACPI files */ | |
70 #define ACPI_BINF_PATH ACPI_BASE_PATH "/BINF" | |
71 #define ACPI_CHNV_PATH ACPI_BASE_PATH "/CHNV" | |
72 #define ACPI_CHSW_PATH ACPI_BASE_PATH "/CHSW" | |
73 #define ACPI_FMAP_PATH ACPI_BASE_PATH "/FMAP" | |
74 #define ACPI_GPIO_PATH ACPI_BASE_PATH "/GPIO" | |
75 #define ACPI_VBNV_PATH ACPI_BASE_PATH "/VBNV" | |
76 #define ACPI_VDAT_PATH ACPI_BASE_PATH "/VDAT" | |
77 | |
78 /* Base name for GPIO files */ | |
79 #define GPIO_BASE_PATH "/sys/class/gpio" | |
80 #define GPIO_EXPORT_PATH GPIO_BASE_PATH "/export" | |
81 | |
82 /* Filename for NVRAM file */ | |
83 #define NVRAM_PATH "/dev/nvram" | |
84 | |
85 /* Filename for kernel command line */ | 22 /* Filename for kernel command line */ |
86 #define KERNEL_CMDLINE_PATH "/proc/cmdline" | 23 #define KERNEL_CMDLINE_PATH "/proc/cmdline" |
87 | 24 |
88 /* A structure to contain buffer data retrieved from the ACPI. */ | |
89 typedef struct { | |
90 int buffer_size; | |
91 uint8_t* buffer; | |
92 } AcpiBuffer; | |
93 | |
94 | |
95 /* Fields that GetVdatString() can get */ | 25 /* Fields that GetVdatString() can get */ |
96 typedef enum VdatStringField { | 26 typedef enum VdatStringField { |
97 VDAT_STRING_TIMERS = 0, /* Timer values */ | 27 VDAT_STRING_TIMERS = 0, /* Timer values */ |
98 VDAT_STRING_LOAD_FIRMWARE_DEBUG, /* LoadFirmware() debug information */ | 28 VDAT_STRING_LOAD_FIRMWARE_DEBUG, /* LoadFirmware() debug information */ |
99 VDAT_STRING_LOAD_KERNEL_DEBUG /* LoadKernel() debug information */ | 29 VDAT_STRING_LOAD_KERNEL_DEBUG /* LoadKernel() debug information */ |
100 } VdatStringField; | 30 } VdatStringField; |
101 | 31 |
102 | 32 |
103 /* Fields that GetVdatInt() can get */ | 33 /* Fields that GetVdatInt() can get */ |
104 typedef enum VdatIntField { | 34 typedef enum VdatIntField { |
105 VDAT_INT_FLAGS = 0, /* Flags */ | 35 VDAT_INT_FLAGS = 0, /* Flags */ |
106 VDAT_INT_FW_VERSION_TPM, /* Current firmware version in TPM */ | 36 VDAT_INT_FW_VERSION_TPM, /* Current firmware version in TPM */ |
107 VDAT_INT_KERNEL_VERSION_TPM, /* Current kernel version in TPM */ | 37 VDAT_INT_KERNEL_VERSION_TPM, /* Current kernel version in TPM */ |
108 VDAT_INT_TRIED_FIRMWARE_B, /* Tried firmware B due to fwb_tries */ | 38 VDAT_INT_TRIED_FIRMWARE_B, /* Tried firmware B due to fwb_tries */ |
109 VDAT_INT_KERNEL_KEY_VERIFIED /* Kernel key verified using | 39 VDAT_INT_KERNEL_KEY_VERIFIED /* Kernel key verified using |
110 * signature, not just hash */ | 40 * signature, not just hash */ |
111 } VdatIntField; | 41 } VdatIntField; |
112 | 42 |
113 | 43 |
114 /* Copy up to dest_size-1 characters from src to dest, ensuring null | |
115 termination (which strncpy() doesn't do). Returns the destination | |
116 string. */ | |
117 char* StrCopy(char* dest, const char* src, int dest_size) { | |
118 strncpy(dest, src, dest_size); | |
119 dest[dest_size - 1] = '\0'; | |
120 return dest; | |
121 } | |
122 | |
123 | |
124 /* Read a string from a file. Passed the destination, dest size, and | |
125 * filename to read. | |
126 * | |
127 * Returns the destination, or NULL if error. */ | |
128 char* ReadFileString(char* dest, int size, const char* filename) { | |
129 char* got; | |
130 FILE* f; | |
131 | |
132 f = fopen(filename, "rt"); | |
133 if (!f) | |
134 return NULL; | |
135 | |
136 got = fgets(dest, size, f); | |
137 fclose(f); | |
138 return got; | |
139 } | |
140 | |
141 | |
142 /* Read an integer from a file. | |
143 * | |
144 * Returns the parsed integer, or -1 if error. */ | |
145 int ReadFileInt(const char* filename) { | |
146 char buf[64]; | |
147 int value; | |
148 char* e = NULL; | |
149 | |
150 if (!ReadFileString(buf, sizeof(buf), filename)) | |
151 return -1; | |
152 | |
153 /* Convert to integer. Allow characters after the int ("123 blah"). */ | |
154 value = strtol(buf, &e, 0); | |
155 if (e == buf) | |
156 return -1; /* No characters consumed, so conversion failed */ | |
157 | |
158 return value; | |
159 } | |
160 | |
161 | |
162 /* Check if a bit is set in a file which contains an integer. | |
163 * | |
164 * Returns 1 if the bit is set, 0 if clear, or -1 if error. */ | |
165 int ReadFileBit(const char* filename, int bitmask) { | |
166 int value = ReadFileInt(filename); | |
167 if (value == -1) | |
168 return -1; | |
169 else return (value & bitmask ? 1 : 0); | |
170 } | |
171 | |
172 | |
173 /* Return true if the FWID starts with the specified string. */ | 44 /* Return true if the FWID starts with the specified string. */ |
174 static int FwidStartsWith(const char *start) { | 45 int FwidStartsWith(const char *start) { |
175 char fwid[128]; | 46 char fwid[128]; |
176 if (!VbGetSystemPropertyString("fwid", fwid, sizeof(fwid))) | 47 if (!VbGetSystemPropertyString("fwid", fwid, sizeof(fwid))) |
177 return 0; | 48 return 0; |
178 | 49 |
179 return 0 == strncmp(fwid, start, strlen(start)); | 50 return 0 == strncmp(fwid, start, strlen(start)); |
180 } | 51 } |
181 | 52 |
182 | 53 |
183 /* Read a GPIO of the specified signal type (see ACPI GPIO SignalType). | |
184 * | |
185 * Returns 1 if the signal is asserted, 0 if not asserted, or -1 if error. */ | |
186 int ReadGpio(int signal_type) { | |
187 char name[128]; | |
188 int index = 0; | |
189 int gpio_type; | |
190 int active_high; | |
191 int controller_offset; | |
192 char controller_name[128]; | |
193 int value; | |
194 | |
195 /* Scan GPIO.* to find a matching signal type */ | |
196 for (index = 0; ; index++) { | |
197 snprintf(name, sizeof(name), "%s.%d/GPIO.0", ACPI_GPIO_PATH, index); | |
198 gpio_type = ReadFileInt(name); | |
199 if (gpio_type == signal_type) | |
200 break; | |
201 else if (gpio_type == -1) | |
202 return -1; /* Ran out of GPIOs before finding a match */ | |
203 } | |
204 | |
205 /* Read attributes and controller info for the GPIO */ | |
206 snprintf(name, sizeof(name), "%s.%d/GPIO.1", ACPI_GPIO_PATH, index); | |
207 active_high = ReadFileBit(name, 0x00000001); | |
208 snprintf(name, sizeof(name), "%s.%d/GPIO.2", ACPI_GPIO_PATH, index); | |
209 controller_offset = ReadFileInt(name); | |
210 if (active_high == -1 || controller_offset == -1) | |
211 return -1; /* Missing needed info */ | |
212 | |
213 /* We only support the NM10 for now */ | |
214 snprintf(name, sizeof(name), "%s.%d/GPIO.3", ACPI_GPIO_PATH, index); | |
215 if (!ReadFileString(controller_name, sizeof(controller_name), name)) | |
216 return -1; | |
217 if (0 != strcmp(controller_name, "NM10")) | |
218 return -1; | |
219 | |
220 /* Assume the NM10 has offset 192 */ | |
221 /* TODO: should really check gpiochipNNN/label to see if it's the | |
222 * address we expect for the NM10, and then read the offset from | |
223 * gpiochipNNN/base. */ | |
224 controller_offset += 192; | |
225 | |
226 /* Try reading the GPIO value */ | |
227 snprintf(name, sizeof(name), "%s/gpio%d/value", | |
228 GPIO_BASE_PATH, controller_offset); | |
229 value = ReadFileInt(name); | |
230 | |
231 if (value == -1) { | |
232 /* Try exporting the GPIO */ | |
233 FILE* f = fopen(GPIO_EXPORT_PATH, "wt"); | |
234 if (!f) | |
235 return -1; | |
236 fprintf(f, "%d", controller_offset); | |
237 fclose(f); | |
238 | |
239 /* Try re-reading the GPIO value */ | |
240 value = ReadFileInt(name); | |
241 } | |
242 | |
243 if (value == -1) | |
244 return -1; | |
245 | |
246 /* Compare the GPIO value with the active value and return 1 if match. */ | |
247 return (value == active_high ? 1 : 0); | |
248 } | |
249 | |
250 | |
251 /* Read the CMOS reboot field in NVRAM. | |
252 * | |
253 * Returns 0 if the mask is clear in the field, 1 if set, or -1 if error. */ | |
254 int VbGetCmosRebootField(uint8_t mask) { | |
255 FILE* f; | |
256 int chnv, nvbyte; | |
257 | |
258 /* Get the byte offset from CHNV */ | |
259 chnv = ReadFileInt(ACPI_CHNV_PATH); | |
260 if (chnv == -1) | |
261 return -1; | |
262 | |
263 f = fopen(NVRAM_PATH, "rb"); | |
264 if (!f) | |
265 return -1; | |
266 | |
267 if (0 != fseek(f, chnv, SEEK_SET) || EOF == (nvbyte = fgetc(f))) { | |
268 fclose(f); | |
269 return -1; | |
270 } | |
271 | |
272 fclose(f); | |
273 return (nvbyte & mask ? 1 : 0); | |
274 } | |
275 | |
276 | |
277 /* Write the CMOS reboot field in NVRAM. | |
278 * | |
279 * Sets (value=0) or clears (value!=0) the mask in the byte. | |
280 * | |
281 * Returns 0 if success, or -1 if error. */ | |
282 int VbSetCmosRebootField(uint8_t mask, int value) { | |
283 FILE* f; | |
284 int chnv, nvbyte; | |
285 | |
286 /* Get the byte offset from CHNV */ | |
287 chnv = ReadFileInt(ACPI_CHNV_PATH); | |
288 if (chnv == -1) | |
289 return -1; | |
290 | |
291 f = fopen(NVRAM_PATH, "w+b"); | |
292 if (!f) | |
293 return -1; | |
294 | |
295 /* Read the current value */ | |
296 if (0 != fseek(f, chnv, SEEK_SET) || EOF == (nvbyte = fgetc(f))) { | |
297 fclose(f); | |
298 return -1; | |
299 } | |
300 | |
301 /* Set/clear the mask */ | |
302 if (value) | |
303 nvbyte |= mask; | |
304 else | |
305 nvbyte &= ~mask; | |
306 | |
307 /* Write the byte back */ | |
308 if (0 != fseek(f, chnv, SEEK_SET) || EOF == (fputc(nvbyte, f))) { | |
309 fclose(f); | |
310 return -1; | |
311 } | |
312 | |
313 /* Success */ | |
314 fclose(f); | |
315 return 0; | |
316 } | |
317 | |
318 /* | |
319 * Get buffer data from ACPI. | |
320 * | |
321 * Buffer data is expected to be represented by a file which is a text dump of | |
322 * the buffer, representing each byte by two hex numbers, space and newline | |
323 * separated. | |
324 * | |
325 * Input - ACPI file name to get data from. | |
326 * | |
327 * Output: a pointer to AcpiBuffer structure containing the binary | |
328 * representation of the data. The caller is responsible for | |
329 * deallocating the pointer, this will take care of both the structure | |
330 * and the buffer. Null in case of error. | |
331 */ | |
332 | |
333 AcpiBuffer* VbGetBuffer(const char* filename) | |
334 { | |
335 FILE* f = NULL; | |
336 char* file_buffer = NULL; | |
337 AcpiBuffer* acpi_buffer = NULL; | |
338 AcpiBuffer* return_value = NULL; | |
339 | |
340 do { | |
341 struct stat fs; | |
342 uint8_t* output_ptr; | |
343 int rv, i, real_size; | |
344 | |
345 rv = stat(filename, &fs); | |
346 if (rv || !S_ISREG(fs.st_mode)) | |
347 break; | |
348 | |
349 f = fopen(filename, "r"); | |
350 if (!f) | |
351 break; | |
352 | |
353 file_buffer = Malloc(fs.st_size + 1); | |
354 if (!file_buffer) | |
355 break; | |
356 | |
357 real_size = fread(file_buffer, 1, fs.st_size, f); | |
358 if (!real_size) | |
359 break; | |
360 file_buffer[real_size] = '\0'; | |
361 | |
362 /* Each byte in the output will replace two characters and a space | |
363 * in the input, so the output size does not exceed input side/3 | |
364 * (a little less if account for newline characters). */ | |
365 acpi_buffer = Malloc(sizeof(AcpiBuffer) + real_size/3); | |
366 if (!acpi_buffer) | |
367 break; | |
368 acpi_buffer->buffer = (uint8_t*)(acpi_buffer + 1); | |
369 acpi_buffer->buffer_size = 0; | |
370 output_ptr = acpi_buffer->buffer; | |
371 | |
372 /* process the file contents */ | |
373 for (i = 0; i < real_size; i++) { | |
374 char* base, *end; | |
375 | |
376 base = file_buffer + i; | |
377 | |
378 if (!isxdigit(*base)) | |
379 continue; | |
380 | |
381 output_ptr[acpi_buffer->buffer_size++] = strtol(base, &end, 16) & 0xff; | |
382 | |
383 if ((end - base) != 2) | |
384 /* Input file format error */ | |
385 break; | |
386 | |
387 i += 2; /* skip the second character and the following space */ | |
388 } | |
389 | |
390 if (i == real_size) { | |
391 /* all is well */ | |
392 return_value = acpi_buffer; | |
393 acpi_buffer = NULL; /* prevent it from deallocating */ | |
394 } | |
395 } while(0); | |
396 | |
397 /* wrap up */ | |
398 if (f) | |
399 fclose(f); | |
400 | |
401 if (file_buffer) | |
402 Free(file_buffer); | |
403 | |
404 if (acpi_buffer) | |
405 Free(acpi_buffer); | |
406 | |
407 return return_value; | |
408 } | |
409 | |
410 /* Read an integer property from VbNvStorage. | |
411 * | |
412 * Returns the parameter value, or -1 if error. */ | |
413 int VbGetNvStorage(VbNvParam param) { | 54 int VbGetNvStorage(VbNvParam param) { |
414 FILE* f; | |
415 VbNvContext vnc; | 55 VbNvContext vnc; |
416 int offs; | |
417 uint32_t value; | 56 uint32_t value; |
418 int retval; | 57 int retval; |
419 | 58 |
420 /* Get the byte offset from VBNV */ | 59 /* TODO: locking around NV access */ |
421 offs = ReadFileInt(ACPI_VBNV_PATH ".0"); | 60 |
422 if (offs == -1) | 61 if (0 != VbReadNvStorage(&vnc)) |
423 return -1; | 62 return -1; |
424 if (VBNV_BLOCK_SIZE > ReadFileInt(ACPI_VBNV_PATH ".1")) | |
425 return -1; /* NV storage block is too small */ | |
426 | |
427 /* TODO: locking around NV access */ | |
428 f = fopen(NVRAM_PATH, "rb"); | |
429 if (!f) | |
430 return -1; | |
431 | |
432 if (0 != fseek(f, offs, SEEK_SET) || | |
433 1 != fread(vnc.raw, VBNV_BLOCK_SIZE, 1, f)) { | |
434 fclose(f); | |
435 return -1; | |
436 } | |
437 | |
438 fclose(f); | |
439 | |
440 if (0 != VbNvSetup(&vnc)) | 63 if (0 != VbNvSetup(&vnc)) |
441 return -1; | 64 return -1; |
442 retval = VbNvGet(&vnc, param, &value); | 65 retval = VbNvGet(&vnc, param, &value); |
443 if (0 != VbNvTeardown(&vnc)) | 66 if (0 != VbNvTeardown(&vnc)) |
444 return -1; | 67 return -1; |
445 if (0 != retval) | 68 if (0 != retval) |
446 return -1; | 69 return -1; |
447 | 70 |
448 /* TODO: If vnc.raw_changed, attempt to reopen NVRAM for write and | 71 /* TODO: If vnc.raw_changed, attempt to reopen NVRAM for write and |
449 * save the new defaults. If we're able to, log. */ | 72 * save the new defaults. If we're able to, log. */ |
450 /* TODO: release lock */ | 73 /* TODO: release lock */ |
451 | 74 |
452 return (int)value; | 75 return (int)value; |
453 } | 76 } |
454 | 77 |
455 | 78 |
456 /* Write an integer property to VbNvStorage. | |
457 * | |
458 * Returns 0 if success, -1 if error. */ | |
459 int VbSetNvStorage(VbNvParam param, int value) { | 79 int VbSetNvStorage(VbNvParam param, int value) { |
460 FILE* f; | |
461 VbNvContext vnc; | 80 VbNvContext vnc; |
462 int offs; | |
463 int retval = -1; | 81 int retval = -1; |
464 int i; | 82 int i; |
465 | 83 |
466 /* Get the byte offset from VBNV */ | 84 if (0 != VbReadNvStorage(&vnc)) |
467 offs = ReadFileInt(ACPI_VBNV_PATH ".0"); | |
468 if (offs == -1) | |
469 return -1; | 85 return -1; |
470 if (VBNV_BLOCK_SIZE > ReadFileInt(ACPI_VBNV_PATH ".1")) | |
471 return -1; /* NV storage block is too small */ | |
472 | |
473 /* TODO: locking around NV access */ | |
474 f = fopen(NVRAM_PATH, "w+b"); | |
475 if (!f) | |
476 return -1; | |
477 | |
478 if (0 != fseek(f, offs, SEEK_SET) || | |
479 1 != fread(vnc.raw, VBNV_BLOCK_SIZE, 1, f)) { | |
480 goto VbSetNvCleanup; | |
481 } | |
482 | 86 |
483 if (0 != VbNvSetup(&vnc)) | 87 if (0 != VbNvSetup(&vnc)) |
484 goto VbSetNvCleanup; | 88 goto VbSetNvCleanup; |
485 i = VbNvSet(&vnc, param, (uint32_t)value); | 89 i = VbNvSet(&vnc, param, (uint32_t)value); |
486 if (0 != VbNvTeardown(&vnc)) | 90 if (0 != VbNvTeardown(&vnc)) |
487 goto VbSetNvCleanup; | 91 goto VbSetNvCleanup; |
488 if (0 != i) | 92 if (0 != i) |
489 goto VbSetNvCleanup; | 93 goto VbSetNvCleanup; |
490 | 94 |
491 if (vnc.raw_changed) { | 95 if (vnc.raw_changed) { |
492 if (0 != fseek(f, offs, SEEK_SET) || | 96 if (0 != VbReadNvStorage(&vnc)) |
493 1 != fwrite(vnc.raw, VBNV_BLOCK_SIZE, 1, f)) | |
494 goto VbSetNvCleanup; | 97 goto VbSetNvCleanup; |
495 } | 98 } |
496 | 99 |
497 /* Success */ | 100 /* Success */ |
498 retval = 0; | 101 retval = 0; |
499 | 102 |
500 VbSetNvCleanup: | 103 VbSetNvCleanup: |
501 fclose(f); | |
502 /* TODO: release lock */ | 104 /* TODO: release lock */ |
503 return retval; | 105 return retval; |
504 } | 106 } |
505 | 107 |
506 | 108 |
507 /* Read the recovery reason. Returns the reason code or -1 if error. */ | |
508 int VbGetRecoveryReason(void) { | |
509 int value; | |
510 | |
511 /* Try reading type from BINF.4 */ | |
512 value = ReadFileInt(ACPI_BINF_PATH ".4"); | |
513 if (-1 != value) | |
514 return value; | |
515 | |
516 /* Fall back to BINF.0 for legacy systems like Mario. */ | |
517 switch(ReadFileInt(ACPI_BINF_PATH ".0")) { | |
518 case BINF0_NORMAL: | |
519 case BINF0_DEVELOPER: | |
520 return VBNV_RECOVERY_NOT_REQUESTED; | |
521 case BINF0_RECOVERY_BUTTON: | |
522 return VBNV_RECOVERY_RO_MANUAL; | |
523 case BINF0_RECOVERY_DEV_SCREEN_KEY: | |
524 return VBNV_RECOVERY_RW_DEV_SCREEN; | |
525 case BINF0_RECOVERY_RW_FW_BAD: | |
526 case BINF0_RECOVERY_NO_OS: | |
527 return VBNV_RECOVERY_RW_NO_OS; | |
528 case BINF0_RECOVERY_BAD_OS: | |
529 return VBNV_RECOVERY_RW_INVALID_OS; | |
530 case BINF0_RECOVERY_OS_INITIATED: | |
531 return VBNV_RECOVERY_LEGACY; | |
532 default: | |
533 /* Other values don't map cleanly to firmware type. */ | |
534 return -1; | |
535 } | |
536 } | |
537 | |
538 | |
539 /* Read the active main firmware type into the destination buffer. | |
540 * Passed the destination and its size. Returns the destination, or | |
541 * NULL if error. */ | |
542 const char* VbReadMainFwType(char* dest, int size) { | |
543 | |
544 /* Try reading type from BINF.3 */ | |
545 switch(ReadFileInt(ACPI_BINF_PATH ".3")) { | |
546 case BINF3_RECOVERY: | |
547 return StrCopy(dest, "recovery", size); | |
548 case BINF3_NORMAL: | |
549 return StrCopy(dest, "normal", size); | |
550 case BINF3_DEVELOPER: | |
551 return StrCopy(dest, "developer", size); | |
552 default: | |
553 break; /* Fall through to legacy handling */ | |
554 } | |
555 | |
556 /* Fall back to BINF.0 for legacy systems like Mario. */ | |
557 switch(ReadFileInt(ACPI_BINF_PATH ".0")) { | |
558 case -1: | |
559 /* Both BINF.0 and BINF.3 are missing, so this isn't Chrome OS | |
560 * firmware. */ | |
561 return StrCopy(dest, "nonchrome", size); | |
562 case BINF0_NORMAL: | |
563 return StrCopy(dest, "normal", size); | |
564 case BINF0_DEVELOPER: | |
565 return StrCopy(dest, "developer", size); | |
566 case BINF0_RECOVERY_BUTTON: | |
567 case BINF0_RECOVERY_DEV_SCREEN_KEY: | |
568 case BINF0_RECOVERY_RW_FW_BAD: | |
569 case BINF0_RECOVERY_NO_OS: | |
570 case BINF0_RECOVERY_BAD_OS: | |
571 case BINF0_RECOVERY_OS_INITIATED: | |
572 case BINF0_RECOVERY_TPM_ERROR: | |
573 /* Assorted flavors of recovery boot reason. */ | |
574 return StrCopy(dest, "recovery", size); | |
575 default: | |
576 /* Other values don't map cleanly to firmware type. */ | |
577 return NULL; | |
578 } | |
579 } | |
580 | |
581 | |
582 /* Determine whether OS-level debugging should be allowed. Passed the | 109 /* Determine whether OS-level debugging should be allowed. Passed the |
583 * destination and its size. Returns 1 if yes, 0 if no, -1 if error. */ | 110 * destination and its size. Returns 1 if yes, 0 if no, -1 if error. */ |
584 int VbGetCrosDebug(void) { | 111 int VbGetCrosDebug(void) { |
585 FILE* f = NULL; | 112 FILE* f = NULL; |
586 char buf[4096] = ""; | 113 char buf[4096] = ""; |
587 int binf3; | |
588 char *t, *saveptr; | 114 char *t, *saveptr; |
589 | 115 |
590 /* Try reading firmware type from BINF.3. */ | 116 /* Try reading firmware type. */ |
591 binf3 = ReadFileInt(ACPI_BINF_PATH ".3"); | 117 if (VbGetArchPropertyString("mainfw_type", buf, sizeof(buf))) { |
592 if (BINF3_RECOVERY == binf3) | 118 if (0 == strcmp(buf, "recovery")) |
593 return 0; /* Recovery mode never allows debug. */ | 119 return 0; /* Recovery mode never allows debug. */ |
594 else if (BINF3_DEVELOPER == binf3) | 120 else if (0 == strcmp(buf, "developer")) |
595 return 1; /* Developer firmware always allows debug. */ | 121 return 1; /* Developer firmware always allows debug. */ |
| 122 } |
596 | 123 |
597 /* Normal new firmware, older ChromeOS firmware, or non-Chrome firmware. | 124 /* Normal new firmware, older ChromeOS firmware, or non-Chrome firmware. |
598 * For all these cases, check /proc/cmdline for cros_[no]debug. */ | 125 * For all these cases, check /proc/cmdline for cros_[no]debug. */ |
599 f = fopen(KERNEL_CMDLINE_PATH, "rt"); | 126 f = fopen(KERNEL_CMDLINE_PATH, "rt"); |
600 if (f) { | 127 if (f) { |
601 if (NULL == fgets(buf, sizeof(buf), f)) | 128 if (NULL == fgets(buf, sizeof(buf), f)) |
602 *buf = 0; | 129 *buf = 0; |
603 fclose(f); | 130 fclose(f); |
604 } | 131 } |
605 for (t = strtok_r(buf, " ", &saveptr); t; t=strtok_r(NULL, " ", &saveptr)) { | 132 for (t = strtok_r(buf, " ", &saveptr); t; t=strtok_r(NULL, " ", &saveptr)) { |
606 if (0 == strcmp(t, "cros_debug")) | 133 if (0 == strcmp(t, "cros_debug")) |
607 return 1; | 134 return 1; |
608 else if (0 == strcmp(t, "cros_nodebug")) | 135 else if (0 == strcmp(t, "cros_nodebug")) |
609 return 0; | 136 return 0; |
610 } | 137 } |
611 | 138 |
612 /* Normal new firmware or older Chrome OS firmware allows debug if the | 139 /* Normal new firmware or older Chrome OS firmware allows debug if the |
613 * dev switch is on. */ | 140 * dev switch is on. */ |
614 if (1 == ReadFileBit(ACPI_CHSW_PATH, CHSW_DEV_BOOT)) | 141 if (1 == VbGetSystemPropertyInt("devsw_boot")) |
615 return 1; | 142 return 1; |
616 | 143 |
617 /* All other cases disallow debug. */ | 144 /* All other cases disallow debug. */ |
618 return 0; | 145 return 0; |
619 } | 146 } |
620 | 147 |
621 | 148 |
622 char* GetVdatLoadFirmwareDebug(char* dest, int size, | 149 char* GetVdatLoadFirmwareDebug(char* dest, int size, |
623 const VbSharedDataHeader* sh) { | 150 const VbSharedDataHeader* sh) { |
624 snprintf(dest, size, | 151 snprintf(dest, size, |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
726 /* Warn if data was truncated; we left space for this above. */ | 253 /* Warn if data was truncated; we left space for this above. */ |
727 if (used > size) | 254 if (used > size) |
728 strcat(dest, TRUNCATED); | 255 strcat(dest, TRUNCATED); |
729 | 256 |
730 return dest; | 257 return dest; |
731 } | 258 } |
732 | 259 |
733 | 260 |
734 char* GetVdatString(char* dest, int size, VdatStringField field) | 261 char* GetVdatString(char* dest, int size, VdatStringField field) |
735 { | 262 { |
736 VbSharedDataHeader* sh; | 263 VbSharedDataHeader* sh = VbSharedDataRead(); |
737 AcpiBuffer* ab = VbGetBuffer(ACPI_VDAT_PATH); | |
738 char* value = dest; | 264 char* value = dest; |
739 if (!ab) | 265 |
| 266 if (!sh) |
740 return NULL; | 267 return NULL; |
741 | 268 |
742 sh = (VbSharedDataHeader*)ab->buffer; | |
743 | |
744 switch (field) { | 269 switch (field) { |
745 case VDAT_STRING_TIMERS: | 270 case VDAT_STRING_TIMERS: |
746 snprintf(dest, size, | 271 snprintf(dest, size, |
747 "LFS=%" PRIu64 ",%" PRIu64 | 272 "LFS=%" PRIu64 ",%" PRIu64 |
748 " LF=%" PRIu64 ",%" PRIu64 | 273 " LF=%" PRIu64 ",%" PRIu64 |
749 " LK=%" PRIu64 ",%" PRIu64, | 274 " LK=%" PRIu64 ",%" PRIu64, |
750 sh->timer_load_firmware_start_enter, | 275 sh->timer_load_firmware_start_enter, |
751 sh->timer_load_firmware_start_exit, | 276 sh->timer_load_firmware_start_exit, |
752 sh->timer_load_firmware_enter, | 277 sh->timer_load_firmware_enter, |
753 sh->timer_load_firmware_exit, | 278 sh->timer_load_firmware_exit, |
754 sh->timer_load_kernel_enter, | 279 sh->timer_load_kernel_enter, |
755 sh->timer_load_kernel_exit); | 280 sh->timer_load_kernel_exit); |
756 break; | 281 break; |
757 | 282 |
758 case VDAT_STRING_LOAD_FIRMWARE_DEBUG: | 283 case VDAT_STRING_LOAD_FIRMWARE_DEBUG: |
759 value = GetVdatLoadFirmwareDebug(dest, size, sh); | 284 value = GetVdatLoadFirmwareDebug(dest, size, sh); |
760 break; | 285 break; |
761 | 286 |
762 case VDAT_STRING_LOAD_KERNEL_DEBUG: | 287 case VDAT_STRING_LOAD_KERNEL_DEBUG: |
763 value = GetVdatLoadKernelDebug(dest, size, sh); | 288 value = GetVdatLoadKernelDebug(dest, size, sh); |
764 break; | 289 break; |
765 | 290 |
766 default: | 291 default: |
767 Free(ab); | 292 value = NULL; |
768 return NULL; | 293 break; |
769 } | 294 } |
770 | 295 |
771 Free(ab); | 296 Free(sh); |
772 return value; | 297 return value; |
773 } | 298 } |
774 | 299 |
775 | 300 |
776 int GetVdatInt(VdatIntField field) { | 301 int GetVdatInt(VdatIntField field) { |
777 VbSharedDataHeader* sh; | 302 VbSharedDataHeader* sh = VbSharedDataRead(); |
778 AcpiBuffer* ab = VbGetBuffer(ACPI_VDAT_PATH); | |
779 int value = -1; | 303 int value = -1; |
780 | 304 |
781 if (!ab) | 305 if (!sh) |
782 return -1; | 306 return -1; |
783 | 307 |
784 sh = (VbSharedDataHeader*)ab->buffer; | |
785 | |
786 switch (field) { | 308 switch (field) { |
787 case VDAT_INT_FLAGS: | 309 case VDAT_INT_FLAGS: |
788 value = (int)sh->flags; | 310 value = (int)sh->flags; |
789 break; | 311 break; |
790 case VDAT_INT_FW_VERSION_TPM: | 312 case VDAT_INT_FW_VERSION_TPM: |
791 value = (int)sh->fw_version_tpm; | 313 value = (int)sh->fw_version_tpm; |
792 break; | 314 break; |
793 case VDAT_INT_KERNEL_VERSION_TPM: | 315 case VDAT_INT_KERNEL_VERSION_TPM: |
794 value = (int)sh->kernel_version_tpm; | 316 value = (int)sh->kernel_version_tpm; |
795 break; | 317 break; |
796 case VDAT_INT_TRIED_FIRMWARE_B: | 318 case VDAT_INT_TRIED_FIRMWARE_B: |
797 value = (sh->flags & VBSD_FWB_TRIED ? 1 : 0); | 319 value = (sh->flags & VBSD_FWB_TRIED ? 1 : 0); |
798 break; | 320 break; |
799 case VDAT_INT_KERNEL_KEY_VERIFIED: | 321 case VDAT_INT_KERNEL_KEY_VERIFIED: |
800 value = (sh->flags & VBSD_KERNEL_KEY_VERIFIED ? 1 : 0); | 322 value = (sh->flags & VBSD_KERNEL_KEY_VERIFIED ? 1 : 0); |
801 break; | 323 break; |
802 } | 324 } |
803 | 325 |
804 Free(ab); | 326 Free(sh); |
805 return value; | 327 return value; |
806 } | 328 } |
807 | 329 |
808 | 330 |
809 /* Read a system property integer. | |
810 * | |
811 * Returns the property value, or -1 if error. */ | |
812 int VbGetSystemPropertyInt(const char* name) { | 331 int VbGetSystemPropertyInt(const char* name) { |
813 int value = -1; | 332 int value = -1; |
814 | 333 |
815 /* Switch positions */ | 334 /* Check architecture-dependent properties first */ |
816 if (!strcasecmp(name,"devsw_cur")) { | 335 value = VbGetArchPropertyInt(name); |
817 value = ReadGpio(GPIO_SIGNAL_TYPE_DEV); | 336 if (-1 != value) |
818 } else if (!strcasecmp(name,"devsw_boot")) { | 337 return value; |
819 value = ReadFileBit(ACPI_CHSW_PATH, CHSW_DEV_BOOT); | 338 |
820 } else if (!strcasecmp(name,"recoverysw_cur")) { | 339 /* NV storage values */ |
821 value = ReadGpio(GPIO_SIGNAL_TYPE_RECOVERY); | |
822 } else if (!strcasecmp(name,"recoverysw_boot")) { | |
823 value = ReadFileBit(ACPI_CHSW_PATH, CHSW_RECOVERY_BOOT); | |
824 } else if (!strcasecmp(name,"recoverysw_ec_boot")) { | |
825 value = ReadFileBit(ACPI_CHSW_PATH, CHSW_RECOVERY_EC_BOOT); | |
826 } else if (!strcasecmp(name,"wpsw_cur")) { | |
827 value = ReadGpio(GPIO_SIGNAL_TYPE_WP); | |
828 if (-1 != value && FwidStartsWith("Mario.")) | |
829 value = 1 - value; /* Mario reports this backwards */ | |
830 } else if (!strcasecmp(name,"wpsw_boot")) { | |
831 value = ReadFileBit(ACPI_CHSW_PATH, CHSW_WP_BOOT); | |
832 if (-1 != value && FwidStartsWith("Mario.")) | |
833 value = 1 - value; /* Mario reports this backwards */ | |
834 } | |
835 /* Saved memory is at a fixed location for all H2C BIOS. If the CHSW | |
836 * path exists in sysfs, it's a H2C BIOS. */ | |
837 else if (!strcasecmp(name,"savedmem_base")) { | |
838 return (-1 == ReadFileInt(ACPI_CHSW_PATH) ? -1 : 0x00F00000); | |
839 } else if (!strcasecmp(name,"savedmem_size")) { | |
840 return (-1 == ReadFileInt(ACPI_CHSW_PATH) ? -1 : 0x00100000); | |
841 } | |
842 /* NV storage values with no defaults for older BIOS. */ | |
843 else if (!strcasecmp(name,"kern_nv")) { | 340 else if (!strcasecmp(name,"kern_nv")) { |
844 value = VbGetNvStorage(VBNV_KERNEL_FIELD); | 341 value = VbGetNvStorage(VBNV_KERNEL_FIELD); |
845 } else if (!strcasecmp(name,"nvram_cleared")) { | 342 } else if (!strcasecmp(name,"nvram_cleared")) { |
846 value = VbGetNvStorage(VBNV_KERNEL_SETTINGS_RESET); | 343 value = VbGetNvStorage(VBNV_KERNEL_SETTINGS_RESET); |
847 } else if (!strcasecmp(name,"vbtest_errfunc")) { | 344 } else if (!strcasecmp(name,"vbtest_errfunc")) { |
848 value = VbGetNvStorage(VBNV_TEST_ERROR_FUNC); | 345 value = VbGetNvStorage(VBNV_TEST_ERROR_FUNC); |
849 } else if (!strcasecmp(name,"vbtest_errno")) { | 346 } else if (!strcasecmp(name,"vbtest_errno")) { |
850 value = VbGetNvStorage(VBNV_TEST_ERROR_NUM); | 347 value = VbGetNvStorage(VBNV_TEST_ERROR_NUM); |
851 } | 348 } else if (!strcasecmp(name,"recovery_request")) { |
852 /* NV storage values. If unable to get from NV storage, fall back to the | |
853 * CMOS reboot field used by older BIOS. */ | |
854 else if (!strcasecmp(name,"recovery_request")) { | |
855 value = VbGetNvStorage(VBNV_RECOVERY_REQUEST); | 349 value = VbGetNvStorage(VBNV_RECOVERY_REQUEST); |
856 if (-1 == value) | |
857 value = VbGetCmosRebootField(CMOSRF_RECOVERY); | |
858 } else if (!strcasecmp(name,"dbg_reset")) { | 350 } else if (!strcasecmp(name,"dbg_reset")) { |
859 value = VbGetNvStorage(VBNV_DEBUG_RESET_MODE); | 351 value = VbGetNvStorage(VBNV_DEBUG_RESET_MODE); |
860 if (-1 == value) | |
861 value = VbGetCmosRebootField(CMOSRF_DEBUG_RESET); | |
862 } else if (!strcasecmp(name,"fwb_tries")) { | 352 } else if (!strcasecmp(name,"fwb_tries")) { |
863 value = VbGetNvStorage(VBNV_TRY_B_COUNT); | 353 value = VbGetNvStorage(VBNV_TRY_B_COUNT); |
864 if (-1 == value) | |
865 value = VbGetCmosRebootField(CMOSRF_TRY_B); | |
866 } | 354 } |
867 /* Other parameters */ | 355 /* Other parameters */ |
868 else if (!strcasecmp(name,"recovery_reason")) { | 356 else if (!strcasecmp(name,"cros_debug")) { |
869 return VbGetRecoveryReason(); | |
870 } else if (!strcasecmp(name,"fmap_base")) { | |
871 value = ReadFileInt(ACPI_FMAP_PATH); | |
872 } else if (!strcasecmp(name,"cros_debug")) { | |
873 value = VbGetCrosDebug(); | 357 value = VbGetCrosDebug(); |
874 } else if (!strcasecmp(name,"vdat_flags")) { | 358 } else if (!strcasecmp(name,"vdat_flags")) { |
875 value = GetVdatInt(VDAT_INT_FLAGS); | 359 value = GetVdatInt(VDAT_INT_FLAGS); |
876 } else if (!strcasecmp(name,"tpm_fwver")) { | 360 } else if (!strcasecmp(name,"tpm_fwver")) { |
877 value = GetVdatInt(VDAT_INT_FW_VERSION_TPM); | 361 value = GetVdatInt(VDAT_INT_FW_VERSION_TPM); |
878 } else if (!strcasecmp(name,"tpm_kernver")) { | 362 } else if (!strcasecmp(name,"tpm_kernver")) { |
879 value = GetVdatInt(VDAT_INT_KERNEL_VERSION_TPM); | 363 value = GetVdatInt(VDAT_INT_KERNEL_VERSION_TPM); |
880 } else if (!strcasecmp(name,"tried_fwb")) { | 364 } else if (!strcasecmp(name,"tried_fwb")) { |
881 value = GetVdatInt(VDAT_INT_TRIED_FIRMWARE_B); | 365 value = GetVdatInt(VDAT_INT_TRIED_FIRMWARE_B); |
882 } | 366 } |
883 | 367 |
884 return value; | 368 return value; |
885 } | 369 } |
886 | 370 |
887 /* Read a system property string into a destination buffer of the specified | 371 |
888 * size. | |
889 * | |
890 * Returns the passed buffer, or NULL if error. */ | |
891 const char* VbGetSystemPropertyString(const char* name, char* dest, int size) { | 372 const char* VbGetSystemPropertyString(const char* name, char* dest, int size) { |
| 373 /* Check architecture-dependent properties first */ |
| 374 if (VbGetArchPropertyString(name, dest, size)) |
| 375 return dest; |
892 | 376 |
893 if (!strcasecmp(name,"hwid")) { | 377 if (!strcasecmp(name,"kernkey_vfy")) { |
894 return ReadFileString(dest, size, ACPI_BASE_PATH "/HWID"); | |
895 } else if (!strcasecmp(name,"fwid")) { | |
896 return ReadFileString(dest, size, ACPI_BASE_PATH "/FWID"); | |
897 } else if (!strcasecmp(name,"ro_fwid")) { | |
898 return ReadFileString(dest, size, ACPI_BASE_PATH "/FRID"); | |
899 } else if (!strcasecmp(name,"mainfw_act")) { | |
900 switch(ReadFileInt(ACPI_BINF_PATH ".1")) { | |
901 case 0: | |
902 return StrCopy(dest, "recovery", size); | |
903 case 1: | |
904 return StrCopy(dest, "A", size); | |
905 case 2: | |
906 return StrCopy(dest, "B", size); | |
907 default: | |
908 return NULL; | |
909 } | |
910 } else if (!strcasecmp(name,"mainfw_type")) { | |
911 return VbReadMainFwType(dest, size); | |
912 } else if (!strcasecmp(name,"ecfw_act")) { | |
913 switch(ReadFileInt(ACPI_BINF_PATH ".2")) { | |
914 case 0: | |
915 return StrCopy(dest, "RO", size); | |
916 case 1: | |
917 return StrCopy(dest, "RW", size); | |
918 default: | |
919 return NULL; | |
920 } | |
921 } else if (!strcasecmp(name,"kernkey_vfy")) { | |
922 switch(GetVdatInt(VDAT_INT_KERNEL_KEY_VERIFIED)) { | 378 switch(GetVdatInt(VDAT_INT_KERNEL_KEY_VERIFIED)) { |
923 case 0: | 379 case 0: |
924 return "hash"; | 380 return "hash"; |
925 case 1: | 381 case 1: |
926 return "sig"; | 382 return "sig"; |
927 default: | 383 default: |
928 return NULL; | 384 return NULL; |
929 } | 385 } |
930 } else if (!strcasecmp(name, "vdat_timers")) { | 386 } else if (!strcasecmp(name, "vdat_timers")) { |
931 return GetVdatString(dest, size, VDAT_STRING_TIMERS); | 387 return GetVdatString(dest, size, VDAT_STRING_TIMERS); |
932 } else if (!strcasecmp(name, "vdat_lfdebug")) { | 388 } else if (!strcasecmp(name, "vdat_lfdebug")) { |
933 return GetVdatString(dest, size, VDAT_STRING_LOAD_FIRMWARE_DEBUG); | 389 return GetVdatString(dest, size, VDAT_STRING_LOAD_FIRMWARE_DEBUG); |
934 } else if (!strcasecmp(name, "vdat_lkdebug")) { | 390 } else if (!strcasecmp(name, "vdat_lkdebug")) { |
935 return GetVdatString(dest, size, VDAT_STRING_LOAD_KERNEL_DEBUG); | 391 return GetVdatString(dest, size, VDAT_STRING_LOAD_KERNEL_DEBUG); |
936 } else | 392 } |
937 return NULL; | 393 |
| 394 return NULL; |
938 } | 395 } |
939 | 396 |
940 | 397 |
941 /* Set a system property integer. | |
942 * | |
943 * Returns 0 if success, -1 if error. */ | |
944 int VbSetSystemPropertyInt(const char* name, int value) { | 398 int VbSetSystemPropertyInt(const char* name, int value) { |
| 399 /* Check architecture-dependent properties first */ |
| 400 if (0 == VbSetArchPropertyInt(name, value)) |
| 401 return 0; |
945 | 402 |
946 /* NV storage values with no defaults for older BIOS. */ | 403 /* NV storage values */ |
947 if (!strcasecmp(name,"nvram_cleared")) { | 404 if (!strcasecmp(name,"nvram_cleared")) { |
948 /* Can only clear this flag; it's set inside the NV storage library. */ | 405 /* Can only clear this flag; it's set inside the NV storage library. */ |
949 return VbSetNvStorage(VBNV_KERNEL_SETTINGS_RESET, 0); | 406 return VbSetNvStorage(VBNV_KERNEL_SETTINGS_RESET, 0); |
950 } else if (!strcasecmp(name,"kern_nv")) { | 407 } else if (!strcasecmp(name,"kern_nv")) { |
951 return VbSetNvStorage(VBNV_KERNEL_FIELD, value); | 408 return VbSetNvStorage(VBNV_KERNEL_FIELD, value); |
952 } else if (!strcasecmp(name,"vbtest_errfunc")) { | 409 } else if (!strcasecmp(name,"vbtest_errfunc")) { |
953 return VbSetNvStorage(VBNV_TEST_ERROR_FUNC, value); | 410 return VbSetNvStorage(VBNV_TEST_ERROR_FUNC, value); |
954 } else if (!strcasecmp(name,"vbtest_errno")) { | 411 } else if (!strcasecmp(name,"vbtest_errno")) { |
955 return VbSetNvStorage(VBNV_TEST_ERROR_NUM, value); | 412 return VbSetNvStorage(VBNV_TEST_ERROR_NUM, value); |
956 } | 413 } else if (!strcasecmp(name,"recovery_request")) { |
957 /* NV storage values. If unable to get from NV storage, fall back to the | 414 return VbSetNvStorage(VBNV_RECOVERY_REQUEST, value); |
958 * CMOS reboot field used by older BIOS. */ | |
959 else if (!strcasecmp(name,"recovery_request")) { | |
960 if (0 == VbSetNvStorage(VBNV_RECOVERY_REQUEST, value)) | |
961 return 0; | |
962 return VbSetCmosRebootField(CMOSRF_RECOVERY, value); | |
963 } else if (!strcasecmp(name,"dbg_reset")) { | 415 } else if (!strcasecmp(name,"dbg_reset")) { |
964 if (0 == VbSetNvStorage(VBNV_DEBUG_RESET_MODE, value)) | 416 return VbSetNvStorage(VBNV_DEBUG_RESET_MODE, value); |
965 return 0; | |
966 return VbSetCmosRebootField(CMOSRF_DEBUG_RESET, value); | |
967 } else if (!strcasecmp(name,"fwb_tries")) { | 417 } else if (!strcasecmp(name,"fwb_tries")) { |
968 if (0 == VbSetNvStorage(VBNV_TRY_B_COUNT, value)) | 418 return VbSetNvStorage(VBNV_TRY_B_COUNT, value); |
969 return 0; | |
970 return VbSetCmosRebootField(CMOSRF_TRY_B, value); | |
971 } | 419 } |
972 | 420 |
973 return -1; | 421 return -1; |
974 } | 422 } |
975 | 423 |
976 | 424 |
977 /* Set a system property string. | |
978 * | |
979 * Returns 0 if success, -1 if error. */ | |
980 int VbSetSystemPropertyString(const char* name, const char* value) { | 425 int VbSetSystemPropertyString(const char* name, const char* value) { |
981 | 426 /* Chain to architecture-dependent properties */ |
982 /* TODO: support setting */ | 427 return VbSetArchPropertyString(name, value); |
983 return -1; | |
984 } | 428 } |
OLD | NEW |