clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name crossystem_arch.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/home/coreboot/node-root/workspace/coreboot_scanbuild/3rdparty/vboot -resource-dir /opt/xgcc/lib/clang/17 -D CHROMEOS_ENVIRONMENT -D EC_EFS=0 -D EXTERNAL_TPM_CLEAR_REQUEST=0 -D _GNU_SOURCE -D _FILE_OFFSET_BITS=64 -D HAVE_EXECINFO_H -D HAVE_NSS -I /usr/include/nss -I /usr/include/nspr -I firmware/include -I firmware/lib/include -I firmware/lib/cgptlib/include -I firmware/lib/tpm_lite/include -I firmware/2lib/include -I host/include -I host/lib/include -I host/lib21/include -internal-isystem /opt/xgcc/lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -source-date-epoch 1714465709 -Os -Wno-deprecated-declarations -Wno-trigraphs -Wwrite-strings -Wno-format-security -Wno-address-of-packed-member -Wno-unknown-warning -Wno-error=deprecated-declarations -std=gnu11 -fconst-strings -fdebug-compilation-dir=/home/coreboot/node-root/workspace/coreboot_scanbuild/3rdparty/vboot -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-opt-analyze-headers -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /cb-build/coreboot_scanbuild.0/sharedutils-scanbuildtmp/2024-05-02-073004-2299942-1 -x c host/arch/x86/lib/crossystem_arch.c
1 | |
2 | |
3 | |
4 | |
5 | |
6 | #include <ctype.h> |
7 | #include <dirent.h> |
8 | #include <errno.h> |
9 | #include <fcntl.h> |
10 | #if !defined(__FreeBSD__) && !defined(__OpenBSD__) |
11 | #include <linux/nvram.h> |
12 | #include <linux/version.h> |
13 | #endif |
14 | #include <stddef.h> |
15 | #include <stdint.h> |
16 | #include <stdio.h> |
17 | #include <string.h> |
18 | #include <sys/ioctl.h> |
19 | #include <sys/stat.h> |
20 | #include <sys/types.h> |
21 | #include <sys/utsname.h> |
22 | #include <unistd.h> |
23 | |
24 | #include "crossystem_arch.h" |
25 | #include "crossystem.h" |
26 | #include "crossystem_vbnv.h" |
27 | #include "host_common.h" |
28 | #include "vboot_struct.h" |
29 | |
30 | |
31 | |
32 | |
33 | #define BINF0_UNKNOWN 0 |
34 | |
35 | #define BINF0_NORMAL 1 |
36 | |
37 | #define BINF0_DEVELOPER 2 |
38 | |
39 | #define BINF0_RECOVERY_BUTTON 3 |
40 | |
41 | |
42 | #define BINF0_RECOVERY_DEV_SCREEN_KEY 4 |
43 | |
44 | |
45 | #define BINF0_RECOVERY_RW_FW_BAD 5 |
46 | |
47 | #define BINF0_RECOVERY_NO_OS 6 |
48 | |
49 | #define BINF0_RECOVERY_BAD_OS 7 |
50 | |
51 | #define BINF0_RECOVERY_OS_INITIATED 8 |
52 | |
53 | #define BINF0_S3_DIAGNOSTIC_PATH 9 |
54 | |
55 | #define BINF0_S3_RESUME_FAILED 10 |
56 | |
57 | #define BINF0_RECOVERY_TPM_ERROR 11 |
58 | |
59 | #define CHSW_RECOVERY_BOOT 0x00000002 |
60 | #define CHSW_RECOVERY_EC_BOOT 0x00000004 |
61 | #define CHSW_DEV_BOOT 0x00000020 |
62 | |
63 | #define CMOSRF_RECOVERY 0x80 |
64 | #define CMOSRF_DEBUG_RESET 0x40 |
65 | #define CMOSRF_TRY_B 0x20 |
66 | |
67 | #define GPIO_SIGNAL_TYPE_RECOVERY 1 |
68 | #define GPIO_SIGNAL_TYPE_DEPRECATED_DEV 2 /* Deprecated; see chromium:942901 */ |
69 | #define GPIO_SIGNAL_TYPE_WP 3 |
70 | #define GPIO_SIGNAL_TYPE_PHASE_ENFORCEMENT 4 |
71 | |
72 | |
73 | #define GPIO_BASE_PATH "/sys/class/gpio" |
74 | #define GPIO_EXPORT_PATH GPIO_BASE_PATH "/export" |
75 | |
76 | |
77 | #define SMBIOS_BASE_PATH "/sys/class/dmi/id" |
78 | #define SMBIOS_PRODUCT_VERSION_PATH SMBIOS_BASE_PATH "/product_version" |
79 | |
80 | |
81 | #define NVRAM_PATH "/dev/nvram" |
82 | |
83 | |
84 | #define NEED_FWUPDATE_PATH "/mnt/stateful_partition/.need_firmware_update" |
85 | |
86 | |
87 | #define PCI_VENDOR_ID_PATH "/sys/bus/pci/devices/0000:00:00.0/vendor" |
88 | #define PCI_DEVICE_ID_PATH "/sys/bus/pci/devices/0000:00:00.0/device" |
89 | |
90 | typedef struct { |
91 | unsigned int base; |
92 | unsigned int uid; |
93 | } Basemapping; |
94 | |
95 | static void VbFixCmosChecksum(FILE* file) |
96 | { |
97 | #if !defined(__FreeBSD__) && !defined(__OpenBSD__) |
98 | int fd = fileno(file); |
99 | ioctl(fd, NVRAM_SETCKS); |
100 | #endif |
101 | } |
102 | |
103 | |
104 | |
105 | |
106 | |
107 | |
108 | |
109 | |
110 | static char* GetAcpiSysfsPath(const char* name) |
111 | { |
112 | |
113 | |
114 | |
115 | |
116 | static const char* legacy_driver_path = "/sys/devices/platform/chromeos_acpi"; |
117 | static const char* legacy_fw_path = "/sys/devices/platform/GGL0001:00"; |
118 | static const char* current_path = "/sys/devices/platform/GOOG0016:00"; |
119 | char* path; |
120 | struct stat fs; |
121 | int ret; |
122 | |
123 | if (stat(legacy_driver_path, &fs) == 0 && S_ISDIR(fs.st_mode)) |
124 | ret = asprintf(&path, "%s/%s", legacy_driver_path, name); |
125 | else if (stat(legacy_fw_path, &fs) == 0 && S_ISDIR(fs.st_mode)) |
126 | ret = asprintf(&path, "%s/%s", legacy_fw_path, name); |
127 | else |
128 | ret = asprintf(&path, "%s/%s", current_path, name); |
129 | |
130 | return ret == -1 ? NULL : path; |
131 | } |
132 | |
133 | |
134 | static char* ReadAcpiSysfsString(char* dest, int size, const char* name) |
135 | { |
136 | char* path; |
137 | char* ret; |
138 | |
139 | path = GetAcpiSysfsPath(name); |
140 | if (!path) |
141 | return NULL; |
142 | |
143 | ret = ReadFileFirstLine(dest, size, path); |
144 | free(path); |
145 | return ret; |
146 | } |
147 | |
148 | |
149 | static int ReadAcpiSysfsInt(const char* name, unsigned* value) |
150 | { |
151 | char* path; |
152 | int ret; |
153 | |
154 | path = GetAcpiSysfsPath(name); |
155 | if (!path) |
156 | return -1; |
157 | |
158 | ret = ReadFileInt(path, value); |
159 | free(path); |
160 | return ret; |
161 | } |
162 | |
163 | |
164 | static int ReadAcpiSysfsBit(const char* name, int bitmask) |
165 | { |
166 | char* path; |
167 | int ret; |
168 | |
169 | path = GetAcpiSysfsPath(name); |
170 | if (!path) |
171 | return -1; |
172 | |
173 | ret = ReadFileBit(path, bitmask); |
174 | free(path); |
175 | return ret; |
176 | } |
177 | |
178 | |
179 | static int VbCmosRead(unsigned offs, size_t size, void *ptr) |
180 | { |
181 | size_t res; |
182 | FILE* f; |
183 | |
184 | f = fopen(NVRAM_PATH, "rb"); |
185 | if (!f) |
186 | return -1; |
187 | |
188 | if (0 != fseek(f, offs, SEEK_SET)) { |
189 | fclose(f); |
190 | return -1; |
191 | } |
192 | |
193 | res = fread(ptr, size, 1, f); |
194 | if (1 != res && errno == EIO && ferror(f)) { |
195 | VbFixCmosChecksum(f); |
196 | res = fread(ptr, size, 1, f); |
197 | } |
198 | |
199 | fclose(f); |
200 | return (1 == res) ? 0 : -1; |
201 | } |
202 | |
203 | |
204 | static int VbCmosWrite(unsigned offs, size_t size, const void *ptr) |
205 | { |
206 | size_t res; |
207 | FILE* f; |
208 | |
209 | f = fopen(NVRAM_PATH, "w+b"); |
210 | if (!f) |
211 | return -1; |
212 | |
213 | if (0 != fseek(f, offs, SEEK_SET)) { |
214 | fclose(f); |
215 | return -1; |
216 | } |
217 | |
218 | res = fwrite(ptr, size, 1, f); |
219 | if (1 != res && errno == EIO && ferror(f)) { |
220 | VbFixCmosChecksum(f); |
221 | res = fwrite(ptr, size, 1, f); |
222 | } |
223 | |
224 | fclose(f); |
225 | return (1 == res) ? 0 : -1; |
226 | } |
227 | |
228 | |
229 | int vb2_read_nv_storage(struct vb2_context *ctx) |
230 | { |
231 | unsigned offs, blksz; |
232 | unsigned expectsz = vb2_nv_get_size(ctx); |
233 | |
234 | |
235 | if (ReadAcpiSysfsInt("VBNV.0", &offs) < 0) |
236 | return -1; |
237 | if (ReadAcpiSysfsInt("VBNV.1", &blksz) < 0) |
238 | return -1; |
239 | if (expectsz > blksz) |
240 | return -1; |
241 | |
242 | if (0 != VbCmosRead(offs, expectsz, ctx->nvdata)) |
243 | return -1; |
244 | |
245 | return 0; |
246 | } |
247 | |
248 | |
249 | int vb2_write_nv_storage(struct vb2_context *ctx) |
250 | { |
251 | unsigned offs, blksz; |
252 | unsigned expectsz = vb2_nv_get_size(ctx); |
253 | |
254 | if (!(ctx->flags & VB2_CONTEXT_NVDATA_CHANGED)) |
| 1 | Assuming the condition is false | |
|
| |
255 | return 0; |
256 | |
257 | |
258 | if (ReadAcpiSysfsInt("VBNV.0", &offs) < 0) |
| 3 | | Assuming the condition is false | |
|
| |
259 | return -1; |
260 | if (ReadAcpiSysfsInt("VBNV.1", &blksz) < 0) |
| 5 | | Assuming the condition is false | |
|
| |
261 | return -1; |
262 | if (expectsz > blksz) |
| 7 | | Assuming 'expectsz' is <= 'blksz' | |
|
| |
263 | return -1; |
264 | |
265 | if (0 != VbCmosWrite(offs, expectsz, ctx->nvdata)) |
| |
266 | return -1; |
267 | |
268 | |
269 | VbSharedDataHeader *sh = VbSharedDataRead(); |
| 10 | | Calling 'VbSharedDataRead' | |
|
270 | if (sh) { |
271 | if (sh->flags & VBSD_BOOT_FIRMWARE_VBOOT2) |
272 | vb2_write_nv_storage_flashrom(ctx); |
273 | free(sh); |
274 | } |
275 | |
276 | return 0; |
277 | } |
278 | |
279 | |
280 | |
281 | |
282 | |
283 | |
284 | |
285 | |
286 | |
287 | |
288 | |
289 | |
290 | |
291 | |
292 | |
293 | |
294 | |
295 | |
296 | |
297 | static uint8_t* VbGetBuffer(const char* filename, int* buffer_size) |
298 | { |
299 | FILE* f = NULL; |
300 | char* file_buffer = NULL; |
301 | uint8_t* output_buffer = NULL; |
302 | uint8_t* return_value = NULL; |
303 | |
304 | |
305 | if (buffer_size) |
| |
306 | *buffer_size = 0; |
307 | |
308 | do { |
| 40 | | Loop condition is false. Exiting loop | |
|
309 | struct stat fs; |
310 | uint8_t* output_ptr; |
311 | int rv, i, real_size; |
312 | int parsed_size = 0; |
313 | |
314 | int fd = open(filename, O_RDONLY); |
315 | if (fd == -1) |
| 15 | | Assuming the condition is false | |
|
| |
316 | break; |
317 | |
318 | rv = fstat(fd, &fs); |
319 | if (rv || !S_ISREG(fs.st_mode)) { |
| |
| 18 | | Assuming the condition is true | |
|
| |
320 | close(fd); |
321 | break; |
322 | } |
323 | |
324 | f = fdopen(fd, "r"); |
325 | if (!f) { |
| 20 | | Assuming 'f' is non-null, which participates in a condition later | |
|
| |
326 | close(fd); |
327 | break; |
328 | } |
329 | |
330 | file_buffer = malloc(fs.st_size + 1); |
331 | if (!file_buffer) |
| 22 | | Assuming 'file_buffer' is non-null, which participates in a condition later | |
|
| |
332 | break; |
333 | |
334 | real_size = fread(file_buffer, 1, fs.st_size, f); |
335 | if (!real_size) |
| 24 | | Assuming 'real_size' is not equal to 0, which participates in a condition later | |
|
| |
336 | break; |
337 | file_buffer[real_size] = '\0'; |
338 | |
339 | |
340 | |
341 | |
342 | output_buffer = malloc(real_size/3); |
| 26 | | Uninitialized value stored to field 'struct_version' | |
|
343 | if (!output_buffer) |
| 27 | | Assuming 'output_buffer' is non-null, which participates in a condition later | |
|
| |
344 | break; |
345 | output_ptr = output_buffer; |
346 | |
347 | |
348 | for (i = 0; i < real_size; i++) { |
| 29 | | Loop condition is true. Entering loop body | |
|
| 35 | | Assuming 'i' is >= 'real_size' | |
|
| 36 | | Loop condition is false. Execution continues on line 367 | |
|
349 | char* base, *end; |
350 | |
351 | base = file_buffer + i; |
352 | |
353 | if (!isxdigit(*base)) |
| 30 | | Assuming the condition is false | |
|
| |
354 | continue; |
355 | |
356 | output_ptr[parsed_size++] = |
| 32 | | Assigning value, which participates in a condition later | |
|
357 | strtol(base, &end, 16) & 0xff; |
358 | |
359 | if ((end - base) != 2) |
| 33 | | Assuming the condition is false | |
|
| |
360 | |
361 | break; |
362 | |
363 | |
364 | i += 2; |
365 | } |
366 | |
367 | if (i == real_size) { |
| 37 | | Assuming 'i' is equal to 'real_size' | |
|
| |
368 | |
369 | return_value = output_buffer; |
370 | output_buffer = NULL; |
371 | if (buffer_size) |
| |
372 | *buffer_size = parsed_size; |
373 | } |
374 | } while(0); |
375 | |
376 | |
377 | if (f) |
| |
378 | fclose(f); |
379 | |
380 | if (file_buffer) |
| |
381 | free(file_buffer); |
382 | |
383 | if (output_buffer) |
| |
384 | free(output_buffer); |
385 | |
386 | return return_value; |
| 44 | | Returning pointer (loaded from 'return_value'), which participates in a condition later | |
|
387 | } |
388 | |
389 | |
390 | VbSharedDataHeader* VbSharedDataRead(void) |
391 | { |
392 | VbSharedDataHeader* sh; |
393 | int got_size = 0; |
394 | int expect_size; |
395 | char* path; |
396 | |
397 | path = GetAcpiSysfsPath("VDAT"); |
398 | if (!path) |
| 11 | | Assuming 'path' is non-null | |
|
| |
399 | return NULL; |
400 | |
401 | sh = (VbSharedDataHeader*)VbGetBuffer(path, &got_size); |
| |
| 45 | | Returning from 'VbGetBuffer' | |
|
402 | free(path); |
403 | if (!sh) |
| |
404 | return NULL; |
405 | |
406 | |
407 | |
408 | if (1 == sh->struct_version) |
| 47 | | The right operand of '==' is a garbage value |
|
409 | expect_size = VB_SHARED_DATA_HEADER_SIZE_V1; |
410 | else { |
411 | |
412 | expect_size = sizeof(VbSharedDataHeader); |
413 | } |
414 | |
415 | if (got_size < expect_size) { |
416 | free(sh); |
417 | return NULL; |
418 | } |
419 | if (sh->data_size > got_size) |
420 | sh->data_size = got_size; |
421 | |
422 | return sh; |
423 | } |
424 | |
425 | |
426 | |
427 | |
428 | |
429 | static int VbGetCmosRebootField(uint8_t mask) |
430 | { |
431 | unsigned chnv; |
432 | uint8_t nvbyte; |
433 | |
434 | |
435 | if (ReadAcpiSysfsInt("CHNV", &chnv) < 0) |
436 | return -1; |
437 | |
438 | if (0 != VbCmosRead(chnv, 1, &nvbyte)) |
439 | return -1; |
440 | |
441 | return (nvbyte & mask ? 1 : 0); |
442 | } |
443 | |
444 | |
445 | |
446 | |
447 | |
448 | |
449 | |
450 | static int VbSetCmosRebootField(uint8_t mask, int value) |
451 | { |
452 | unsigned chnv; |
453 | uint8_t nvbyte; |
454 | |
455 | |
456 | if (ReadAcpiSysfsInt("CHNV", &chnv) < 0) |
457 | return -1; |
458 | |
459 | if (0 != VbCmosRead(chnv, 1, &nvbyte)) |
460 | return -1; |
461 | |
462 | |
463 | if (value) |
464 | nvbyte |= mask; |
465 | else |
466 | nvbyte &= ~mask; |
467 | |
468 | |
469 | if (0 != VbCmosWrite(chnv, 1, &nvbyte)) |
470 | return -1; |
471 | |
472 | |
473 | return 0; |
474 | } |
475 | |
476 | |
477 | |
478 | |
479 | |
480 | static const char* VbReadMainFwType(char* dest, int size) |
481 | { |
482 | unsigned value; |
483 | |
484 | |
485 | if (ReadAcpiSysfsInt("BINF.3", &value) == 0) { |
486 | switch(value) { |
487 | case BINF3_LEGACY: |
488 | return StrCopy(dest, "legacy", size); |
489 | case BINF3_NETBOOT: |
490 | return StrCopy(dest, "netboot", size); |
491 | case BINF3_RECOVERY: |
492 | return StrCopy(dest, "recovery", size); |
493 | case BINF3_NORMAL: |
494 | return StrCopy(dest, "normal", size); |
495 | case BINF3_DEVELOPER: |
496 | return StrCopy(dest, "developer", size); |
497 | default: |
498 | break; |
499 | } |
500 | } |
501 | |
502 | |
503 | if (ReadAcpiSysfsInt("BINF.0", &value) < 0) |
504 | |
505 | |
506 | return StrCopy(dest, "nonchrome", size); |
507 | |
508 | switch(value) { |
509 | case BINF0_NORMAL: |
510 | return StrCopy(dest, "normal", size); |
511 | case BINF0_DEVELOPER: |
512 | return StrCopy(dest, "developer", size); |
513 | case BINF0_RECOVERY_BUTTON: |
514 | case BINF0_RECOVERY_DEV_SCREEN_KEY: |
515 | case BINF0_RECOVERY_RW_FW_BAD: |
516 | case BINF0_RECOVERY_NO_OS: |
517 | case BINF0_RECOVERY_BAD_OS: |
518 | case BINF0_RECOVERY_OS_INITIATED: |
519 | case BINF0_RECOVERY_TPM_ERROR: |
520 | |
521 | return StrCopy(dest, "recovery", size); |
522 | default: |
523 | |
524 | return NULL; |
525 | } |
526 | } |
527 | |
528 | |
529 | |
530 | static vb2_error_t VbGetRecoveryReason(void) |
531 | { |
532 | unsigned value; |
533 | |
534 | |
535 | if (ReadAcpiSysfsInt("BINF.4", &value) == 0) |
536 | return value; |
537 | |
538 | |
539 | if (ReadAcpiSysfsInt("BINF.0", &value) < 0) |
540 | return -1; |
541 | switch(value) { |
542 | case BINF0_NORMAL: |
543 | case BINF0_DEVELOPER: |
544 | return VB2_RECOVERY_NOT_REQUESTED; |
545 | case BINF0_RECOVERY_BUTTON: |
546 | return VB2_RECOVERY_RO_MANUAL; |
547 | case BINF0_RECOVERY_RW_FW_BAD: |
548 | return VB2_RECOVERY_RO_INVALID_RW; |
549 | case BINF0_RECOVERY_NO_OS: |
550 | return VB2_RECOVERY_RW_NO_KERNEL; |
551 | case BINF0_RECOVERY_BAD_OS: |
552 | return VB2_RECOVERY_RW_INVALID_OS; |
553 | case BINF0_RECOVERY_OS_INITIATED: |
554 | return VB2_RECOVERY_LEGACY; |
555 | default: |
556 | |
557 | return -1; |
558 | } |
559 | } |
560 | |
561 | |
562 | |
563 | |
564 | |
565 | |
566 | static int FindGpioChipOffset(unsigned *gpio_num, unsigned *offset, |
567 | const char *name) |
568 | { |
569 | DIR *dir; |
570 | struct dirent *ent; |
571 | int match = 0; |
572 | |
573 | dir = opendir(GPIO_BASE_PATH); |
574 | if (!dir) { |
575 | return 0; |
576 | } |
577 | |
578 | while(0 != (ent = readdir(dir))) { |
579 | if (1 == sscanf(ent->d_name, "gpiochip%u", offset)) { |
580 | match++; |
581 | } |
582 | } |
583 | |
584 | closedir(dir); |
585 | return (1 == match); |
586 | } |
587 | |
588 | |
589 | |
590 | |
591 | |
592 | |
593 | static int FindGpioChipOffsetByLabel(unsigned *gpio_num, unsigned *offset, |
594 | const char *name) |
595 | { |
596 | DIR *dir; |
597 | struct dirent *ent; |
598 | char filename[128]; |
599 | char chiplabel[128]; |
600 | int match = 0; |
601 | unsigned controller_offset = 0; |
602 | |
603 | dir = opendir(GPIO_BASE_PATH); |
604 | if (!dir) { |
605 | return 0; |
606 | } |
607 | |
608 | while(0 != (ent = readdir(dir))) { |
609 | if (1 == sscanf(ent->d_name, "gpiochip%u", |
610 | &controller_offset)) { |
611 | |
612 | |
613 | |
614 | |
615 | snprintf(filename, sizeof(filename), |
616 | "%s/gpiochip%u/label", |
617 | GPIO_BASE_PATH, controller_offset); |
618 | if (ReadFileFirstLine(chiplabel, sizeof(chiplabel), |
619 | filename)) { |
620 | if (!strncasecmp(chiplabel, name, |
621 | strlen(name))) { |
622 | |
623 | |
624 | |
625 | |
626 | *offset = controller_offset; |
627 | match++; |
628 | } |
629 | } |
630 | } |
631 | } |
632 | |
633 | closedir(dir); |
634 | return (1 == match); |
635 | } |
636 | |
637 | static int FindGpioChipOffsetByNumber(unsigned *gpio_num, unsigned *offset, |
638 | Basemapping *data) |
639 | { |
640 | DIR *dir; |
641 | struct dirent *ent; |
642 | int match = 0; |
643 | |
644 | |
645 | |
646 | |
647 | |
648 | |
649 | |
650 | |
651 | |
652 | do { |
653 | if (*gpio_num >= data->base) { |
654 | *gpio_num -= data->base; |
655 | break; |
656 | } |
657 | data++; |
658 | } while(1); |
659 | |
660 | if (data->uid == 0) { |
661 | return 0; |
662 | } |
663 | |
664 | dir = opendir(GPIO_BASE_PATH); |
665 | if (!dir) { |
666 | return 0; |
667 | } |
668 | |
669 | while(0 != (ent = readdir(dir))) { |
670 | |
671 | if (1 == sscanf(ent->d_name, "gpiochip%u", offset)) { |
672 | char uid_file[128]; |
673 | unsigned uid_value; |
674 | snprintf(uid_file, sizeof(uid_file), |
675 | "%s/gpiochip%u/device/firmware_node/uid", |
676 | GPIO_BASE_PATH, *offset); |
677 | if (ReadFileInt(uid_file, &uid_value) < 0) |
678 | continue; |
679 | if (data->uid == uid_value) { |
680 | match++; |
681 | break; |
682 | } |
683 | } |
684 | } |
685 | |
686 | closedir(dir); |
687 | return (1 == match); |
688 | } |
689 | |
690 | |
691 | |
692 | |
693 | |
694 | |
695 | |
696 | |
697 | |
698 | |
699 | |
700 | |
701 | |
702 | |
703 | static int BraswellFindGpioChipOffset(unsigned *gpio_num, unsigned *offset, |
704 | const char *name) |
705 | { |
706 | int ret; |
707 | struct utsname host; |
708 | unsigned int maj, min; |
709 | int gpe = 0; |
710 | static Basemapping data[]={ |
711 | {0x20000, 0}, |
712 | {0x18000, 4}, |
713 | {0x10000, 3}, |
714 | {0x08000, 2}, |
715 | {0x00000, 1}}; |
716 | |
717 | |
718 | |
719 | |
720 | |
721 | |
722 | |
723 | |
724 | |
725 | |
726 | |
727 | |
728 | |
729 | |
730 | |
731 | |
732 | |
733 | |
734 | |
735 | if (*gpio_num >= 0x10000 && *gpio_num < 0x18000) |
736 | gpe = 1; |
737 | |
738 | ret = FindGpioChipOffsetByNumber(gpio_num, offset, data); |
739 | if (!ret || !gpe) |
740 | return ret; |
741 | |
742 | if (uname(&host) == 0) { |
743 | if (sscanf(host.release, "%u.%u.", &maj, &min) == 2) { |
744 | #if !defined(__FreeBSD__) && !defined(__OpenBSD__) |
745 | if (KERNEL_VERSION(maj, min, 0) >= KERNEL_VERSION(4, 16, 0) && |
746 | *offset > 11) |
747 | *offset += 3; |
748 | #endif |
749 | } else { |
750 | printf("Couldn't retrieve kernel version!\n"); |
751 | ret = 0; |
752 | } |
753 | } else { |
754 | perror("uname"); |
755 | ret = 0; |
756 | } |
757 | |
758 | return ret; |
759 | } |
760 | |
761 | |
762 | |
763 | |
764 | |
765 | |
766 | |
767 | |
768 | |
769 | |
770 | |
771 | static int BayTrailFindGpioChipOffset(unsigned *gpio_num, unsigned *offset, |
772 | const char *name) |
773 | { |
774 | static Basemapping data[]={ |
775 | {0x3000, 0}, |
776 | {0x2000, 3}, |
777 | {0x1000, 2}, |
778 | {0x0000, 1}}; |
779 | |
780 | return FindGpioChipOffsetByNumber(gpio_num, offset, data); |
781 | } |
782 | |
783 | struct GpioChipset { |
784 | const char *name; |
785 | int (*ChipOffsetAndGpioNumber)(unsigned *gpio_num, |
786 | unsigned *chip_offset, |
787 | const char *name); |
788 | }; |
789 | |
790 | static const struct GpioChipset chipsets_supported[] = { |
791 | { "AMD0030", FindGpioChipOffset }, |
792 | { "NM10", FindGpioChipOffset }, |
793 | { "CougarPoint", FindGpioChipOffset }, |
794 | { "PantherPoint", FindGpioChipOffset }, |
795 | { "LynxPoint", FindGpioChipOffset }, |
796 | { "PCH-LP", FindGpioChipOffset }, |
797 | { "INT3437:00", FindGpioChipOffsetByLabel }, |
798 | { "INT344B:00", FindGpioChipOffsetByLabel }, |
799 | |
800 | { "INT3452:00", FindGpioChipOffsetByLabel }, |
801 | { "INT3452:01", FindGpioChipOffsetByLabel }, |
802 | { "INT3452:02", FindGpioChipOffsetByLabel }, |
803 | { "INT3452:03", FindGpioChipOffsetByLabel }, |
804 | { "INT3455:00", FindGpioChipOffsetByLabel }, |
805 | { "INT34BB:00", FindGpioChipOffsetByLabel }, |
806 | { "INT34C8:00", FindGpioChipOffsetByLabel }, |
807 | { "INT34C5:00", FindGpioChipOffsetByLabel }, |
808 | |
809 | { "INTC1055:00", FindGpioChipOffsetByLabel }, |
810 | { "INTC1056:00", FindGpioChipOffsetByLabel }, |
811 | { "INTC1057:00", FindGpioChipOffsetByLabel }, |
812 | |
813 | { "INTC1083:00", FindGpioChipOffsetByLabel }, |
814 | |
815 | { "INT3453:00", FindGpioChipOffsetByLabel }, |
816 | { "INT3453:01", FindGpioChipOffsetByLabel }, |
817 | { "INT3453:02", FindGpioChipOffsetByLabel }, |
818 | { "INT3453:03", FindGpioChipOffsetByLabel }, |
819 | { "BayTrail", BayTrailFindGpioChipOffset }, |
820 | { "Braswell", BraswellFindGpioChipOffset }, |
821 | { NULL }, |
822 | }; |
823 | |
824 | static const struct GpioChipset *FindChipset(const char *name) |
825 | { |
826 | const struct GpioChipset *chipset = &chipsets_supported[0]; |
827 | |
828 | while (chipset->name != NULL) { |
829 | if (!strcmp(name, chipset->name)) |
830 | return chipset; |
831 | chipset++; |
832 | } |
833 | return NULL; |
834 | } |
835 | |
836 | |
837 | |
838 | |
839 | static int ReadGpio(unsigned signal_type) |
840 | { |
841 | char name[256]; |
842 | int index = 0; |
843 | unsigned gpio_type; |
844 | unsigned active_high; |
845 | unsigned controller_num; |
846 | unsigned controller_offset = 0; |
847 | char controller_name[128]; |
848 | unsigned value; |
849 | const struct GpioChipset *chipset; |
850 | char base_path[128]; |
851 | char* path; |
852 | |
853 | path = GetAcpiSysfsPath("GPIO"); |
854 | if (!path) |
855 | return -1; |
856 | strncpy(base_path, path, sizeof(base_path) - 1); |
857 | base_path[sizeof(base_path) - 1] = 0; |
858 | free(path); |
859 | |
860 | |
861 | for (index = 0; ; index++) { |
862 | snprintf(name, sizeof(name), "%s.%d/GPIO.0", base_path, index); |
863 | if (ReadFileInt(name, &gpio_type) < 0) |
864 | return -1; |
865 | if (gpio_type == signal_type) |
866 | break; |
867 | } |
868 | |
869 | |
870 | snprintf(name, sizeof(name), "%s.%d/GPIO.1", base_path, index); |
871 | if (ReadFileInt(name, &active_high) < 0) |
872 | return -1; |
873 | snprintf(name, sizeof(name), "%s.%d/GPIO.2", base_path, index); |
874 | if (ReadFileInt(name, &controller_num) < 0) |
875 | return -1; |
876 | |
877 | if (controller_num == 0xFFFFFFFF) |
878 | return -1; |
879 | |
880 | |
881 | snprintf(name, sizeof(name), "%s.%d/GPIO.3", base_path, index); |
882 | if (!ReadFileFirstLine(controller_name, sizeof(controller_name), name)) |
883 | return -1; |
884 | chipset = FindChipset(controller_name); |
885 | if (chipset == NULL) |
886 | return -1; |
887 | |
888 | |
889 | if (!chipset->ChipOffsetAndGpioNumber(&controller_num, |
890 | &controller_offset, |
891 | chipset->name)) |
892 | return -1; |
893 | controller_offset += controller_num; |
894 | |
895 | |
896 | snprintf(name, sizeof(name), "%s/gpio%d/value", |
897 | GPIO_BASE_PATH, controller_offset); |
898 | if (ReadFileInt(name, &value) < 0) { |
899 | |
900 | FILE* f = fopen(GPIO_EXPORT_PATH, "wt"); |
901 | if (!f) |
902 | return -1; |
903 | fprintf(f, "%u", controller_offset); |
904 | fclose(f); |
905 | |
906 | |
907 | if (ReadFileInt(name, &value) < 0) |
908 | return -1; |
909 | } |
910 | |
911 | |
912 | |
913 | value = value ? 1 : 0; |
914 | |
915 | |
916 | |
917 | return (value == active_high ? 1 : 0); |
918 | } |
919 | |
920 | static int GetBoardId(void) |
921 | { |
922 | |
923 | |
924 | |
925 | |
926 | |
927 | int board_id = -1; |
928 | FILE *f = fopen(SMBIOS_PRODUCT_VERSION_PATH, "r"); |
929 | |
930 | if (!f) |
931 | return -1; |
932 | |
933 | if (fscanf(f, "rev%d\n", &board_id) != 1) |
934 | board_id = -1; |
935 | |
936 | fclose(f); |
937 | return board_id; |
938 | } |
939 | |
940 | int VbGetArchPropertyInt(const char* name) |
941 | { |
942 | int value = -1; |
943 | |
944 | |
945 | if (!strcasecmp(name,"devsw_cur")) { |
946 | |
947 | |
948 | value = VbGetSystemPropertyInt("devsw_boot"); |
949 | } else if (!strcasecmp(name,"recoverysw_cur")) { |
950 | value = ReadGpio(GPIO_SIGNAL_TYPE_RECOVERY); |
951 | } else if (!strcasecmp(name,"wpsw_cur")) { |
952 | value = ReadGpio(GPIO_SIGNAL_TYPE_WP); |
953 | } else if (!strcasecmp(name,"recoverysw_ec_boot")) { |
954 | value = ReadAcpiSysfsBit("CHSW", CHSW_RECOVERY_EC_BOOT); |
955 | } else if (!strcasecmp(name,"phase_enforcement")) { |
956 | value = ReadGpio(GPIO_SIGNAL_TYPE_PHASE_ENFORCEMENT); |
957 | } |
958 | |
959 | |
960 | if (VbSharedDataVersion() < 2) { |
961 | if (!strcasecmp(name,"recovery_reason")) { |
962 | value = VbGetRecoveryReason(); |
963 | } else if (!strcasecmp(name,"devsw_boot")) { |
964 | value = ReadAcpiSysfsBit("CHSW", CHSW_DEV_BOOT); |
965 | } else if (!strcasecmp(name,"recoverysw_boot")) { |
966 | value = ReadAcpiSysfsBit("CHSW", CHSW_RECOVERY_BOOT); |
967 | } |
968 | } |
969 | |
970 | |
971 | |
972 | if (!strcasecmp(name,"recovery_request")) { |
973 | value = vb2_get_nv_storage(VB2_NV_RECOVERY_REQUEST); |
974 | if (-1 == value) |
975 | value = VbGetCmosRebootField(CMOSRF_RECOVERY); |
976 | } else if (!strcasecmp(name,"dbg_reset")) { |
977 | value = vb2_get_nv_storage(VB2_NV_DEBUG_RESET_MODE); |
978 | if (-1 == value) |
979 | value = VbGetCmosRebootField(CMOSRF_DEBUG_RESET); |
980 | } else if (!strcasecmp(name,"fwb_tries")) { |
981 | value = vb2_get_nv_storage(VB2_NV_TRY_COUNT); |
982 | if (-1 == value) |
983 | value = VbGetCmosRebootField(CMOSRF_TRY_B); |
984 | } |
985 | |
986 | |
987 | |
988 | |
989 | if (!strcasecmp(name,"fwupdate_tries")) { |
990 | unsigned fwupdate_value; |
991 | if (-1 != vb2_get_nv_storage(VB2_NV_KERNEL_FIELD)) |
992 | return -1; |
993 | |
994 | |
995 | |
996 | if (ReadFileInt(NEED_FWUPDATE_PATH, &fwupdate_value) < 0) |
997 | value = 0; |
998 | else |
999 | value = (int)fwupdate_value; |
1000 | } |
1001 | |
1002 | if (!strcasecmp(name, "board_id")) |
1003 | return GetBoardId(); |
1004 | |
1005 | return value; |
1006 | } |
1007 | |
1008 | |
1009 | const char* VbGetArchPropertyString(const char* name, char* dest, |
1010 | size_t size) |
1011 | { |
1012 | unsigned value; |
1013 | |
1014 | if (!strcasecmp(name,"arch")) { |
1015 | return StrCopy(dest, "x86", size); |
1016 | } else if (!strcasecmp(name,"hwid")) { |
1017 | return ReadAcpiSysfsString(dest, size, "HWID"); |
1018 | } else if (!strcasecmp(name,"fwid")) { |
1019 | return ReadAcpiSysfsString(dest, size, "FWID"); |
1020 | } else if (!strcasecmp(name,"ro_fwid")) { |
1021 | return ReadAcpiSysfsString(dest, size, "FRID"); |
1022 | } else if (!strcasecmp(name,"mainfw_act")) { |
1023 | if (ReadAcpiSysfsInt("BINF.1", &value) < 0) |
1024 | return NULL; |
1025 | switch(value) { |
1026 | case 0: |
1027 | return StrCopy(dest, "recovery", size); |
1028 | case 1: |
1029 | return StrCopy(dest, "A", size); |
1030 | case 2: |
1031 | return StrCopy(dest, "B", size); |
1032 | default: |
1033 | return NULL; |
1034 | } |
1035 | } else if (!strcasecmp(name,"mainfw_type")) { |
1036 | return VbReadMainFwType(dest, size); |
1037 | } else if (!strcasecmp(name,"ecfw_act")) { |
1038 | if (ReadAcpiSysfsInt("BINF.2", &value) < 0) |
1039 | return NULL; |
1040 | switch(value) { |
1041 | case 0: |
1042 | return StrCopy(dest, "RO", size); |
1043 | case 1: |
1044 | return StrCopy(dest, "RW", size); |
1045 | default: |
1046 | return NULL; |
1047 | } |
1048 | } |
1049 | |
1050 | return NULL; |
1051 | } |
1052 | |
1053 | |
1054 | int VbSetArchPropertyInt(const char* name, int value) |
1055 | { |
1056 | |
1057 | |
1058 | if (!strcasecmp(name,"recovery_request")) { |
1059 | if (0 == vb2_set_nv_storage(VB2_NV_RECOVERY_REQUEST, value)) |
1060 | return 0; |
1061 | return VbSetCmosRebootField(CMOSRF_RECOVERY, value); |
1062 | } else if (!strcasecmp(name,"dbg_reset")) { |
1063 | if (0 == vb2_set_nv_storage(VB2_NV_DEBUG_RESET_MODE, value)) |
1064 | return 0; |
1065 | return VbSetCmosRebootField(CMOSRF_DEBUG_RESET, value); |
1066 | } else if (!strcasecmp(name,"fwb_tries")) { |
1067 | if (0 == vb2_set_nv_storage(VB2_NV_TRY_COUNT, value)) |
1068 | return 0; |
1069 | return VbSetCmosRebootField(CMOSRF_TRY_B, value); |
1070 | } |
1071 | |
1072 | |
1073 | |
1074 | else if (!strcasecmp(name,"fwupdate_tries")) { |
1075 | if (-1 != vb2_get_nv_storage(VB2_NV_KERNEL_FIELD)) |
1076 | return -1; |
1077 | |
1078 | |
1079 | |
1080 | if (value) { |
1081 | char buf[32]; |
1082 | snprintf(buf, sizeof(buf), "%d", value); |
1083 | return WriteFile(NEED_FWUPDATE_PATH, buf, strlen(buf)); |
1084 | } else { |
1085 | |
1086 | unlink(NEED_FWUPDATE_PATH); |
1087 | return 0; |
1088 | } |
1089 | } |
1090 | |
1091 | return -1; |
1092 | } |
1093 | |
1094 | int VbSetArchPropertyString(const char* name, const char* value) |
1095 | { |
1096 | |
1097 | |
1098 | return -1; |
1099 | } |