LCOV - code coverage report
Current view: top level - shared - acpi-fpdt.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 0 54 0.0 %
Date: 2015-07-29 18:47:03 Functions: 0 1 0.0 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       2             : 
       3             : /***
       4             :   This file is part of systemd.
       5             : 
       6             :   Copyright 2013 Kay Sievers
       7             : 
       8             :   systemd is free software; you can redistribute it and/or modify it
       9             :   under the terms of the GNU Lesser General Public License as published by
      10             :   the Free Software Foundation; either version 2.1 of the License, or
      11             :   (at your option) any later version.
      12             : 
      13             :   systemd is distributed in the hope that it will be useful, but
      14             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      16             :   Lesser General Public License for more details.
      17             : 
      18             :   You should have received a copy of the GNU Lesser General Public License
      19             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      20             : ***/
      21             : 
      22             : #include <stdio.h>
      23             : #include <stdint.h>
      24             : #include <string.h>
      25             : #include <unistd.h>
      26             : #include <fcntl.h>
      27             : 
      28             : #include <util.h>
      29             : #include <fileio.h>
      30             : #include <time-util.h>
      31             : #include <acpi-fpdt.h>
      32             : 
      33             : struct acpi_table_header {
      34             :         char signature[4];
      35             :         uint32_t length;
      36             :         uint8_t revision;
      37             :         uint8_t checksum;
      38             :         char oem_id[6];
      39             :         char oem_table_id[8];
      40             :         uint32_t oem_revision;
      41             :         char asl_compiler_id[4];
      42             :         uint32_t asl_compiler_revision;
      43             : };
      44             : 
      45             : enum {
      46             :         ACPI_FPDT_TYPE_BOOT =   0,
      47             :         ACPI_FPDT_TYPE_S3PERF = 1,
      48             : };
      49             : 
      50             : struct acpi_fpdt_header {
      51             :         uint16_t type;
      52             :         uint8_t length;
      53             :         uint8_t revision;
      54             :         uint8_t reserved[4];
      55             :         uint64_t ptr;
      56             : };
      57             : 
      58             : struct acpi_fpdt_boot_header {
      59             :         char signature[4];
      60             :         uint32_t length;
      61             : };
      62             : 
      63             : enum {
      64             :         ACPI_FPDT_S3PERF_RESUME_REC =   0,
      65             :         ACPI_FPDT_S3PERF_SUSPEND_REC =  1,
      66             :         ACPI_FPDT_BOOT_REC =            2,
      67             : };
      68             : 
      69             : struct acpi_fpdt_boot {
      70             :         uint16_t type;
      71             :         uint8_t length;
      72             :         uint8_t revision;
      73             :         uint8_t reserved[4];
      74             :         uint64_t reset_end;
      75             :         uint64_t load_start;
      76             :         uint64_t startup_start;
      77             :         uint64_t exit_services_entry;
      78             :         uint64_t exit_services_exit;
      79             : };
      80             : 
      81           0 : int acpi_get_boot_usec(usec_t *loader_start, usec_t *loader_exit) {
      82           0 :         _cleanup_free_ char *buf = NULL;
      83             :         struct acpi_table_header *tbl;
      84           0 :         size_t l = 0;
      85             :         struct acpi_fpdt_header *rec;
      86             :         int r;
      87           0 :         uint64_t ptr = 0;
      88           0 :         _cleanup_close_ int fd = -1;
      89             :         struct acpi_fpdt_boot_header hbrec;
      90             :         struct acpi_fpdt_boot brec;
      91             : 
      92           0 :         r = read_full_file("/sys/firmware/acpi/tables/FPDT", &buf, &l);
      93           0 :         if (r < 0)
      94           0 :                 return r;
      95             : 
      96           0 :         if (l < sizeof(struct acpi_table_header) + sizeof(struct acpi_fpdt_header))
      97           0 :                 return -EINVAL;
      98             : 
      99           0 :         tbl = (struct acpi_table_header *)buf;
     100           0 :         if (l != tbl->length)
     101           0 :                 return -EINVAL;
     102             : 
     103           0 :         if (memcmp(tbl->signature, "FPDT", 4) != 0)
     104           0 :                 return -EINVAL;
     105             : 
     106             :         /* find Firmware Basic Boot Performance Pointer Record */
     107           0 :         for (rec = (struct acpi_fpdt_header *)(buf + sizeof(struct acpi_table_header));
     108           0 :              (char *)rec < buf + l;
     109           0 :              rec = (struct acpi_fpdt_header *)((char *)rec + rec->length)) {
     110           0 :                 if (rec->length <= 0)
     111           0 :                         break;
     112           0 :                 if (rec->type != ACPI_FPDT_TYPE_BOOT)
     113           0 :                         continue;
     114           0 :                 if (rec->length != sizeof(struct acpi_fpdt_header))
     115           0 :                         continue;
     116             : 
     117           0 :                 ptr = rec->ptr;
     118           0 :                 break;
     119             :         }
     120             : 
     121           0 :         if (ptr == 0)
     122           0 :                 return -EINVAL;
     123             : 
     124             :         /* read Firmware Basic Boot Performance Data Record */
     125           0 :         fd = open("/dev/mem", O_CLOEXEC|O_RDONLY);
     126           0 :         if (fd < 0)
     127           0 :                 return -errno;
     128             : 
     129           0 :         l = pread(fd, &hbrec, sizeof(struct acpi_fpdt_boot_header), ptr);
     130           0 :         if (l != sizeof(struct acpi_fpdt_boot_header))
     131           0 :                 return -EINVAL;
     132             : 
     133           0 :         if (memcmp(hbrec.signature, "FBPT", 4) != 0)
     134           0 :                 return -EINVAL;
     135             : 
     136           0 :         if (hbrec.length < sizeof(struct acpi_fpdt_boot_header) + sizeof(struct acpi_fpdt_boot))
     137           0 :                 return -EINVAL;
     138             : 
     139           0 :         l = pread(fd, &brec, sizeof(struct acpi_fpdt_boot), ptr + sizeof(struct acpi_fpdt_boot_header));
     140           0 :         if (l != sizeof(struct acpi_fpdt_boot))
     141           0 :                 return -EINVAL;
     142             : 
     143           0 :         if (brec.length != sizeof(struct acpi_fpdt_boot))
     144           0 :                 return -EINVAL;
     145             : 
     146           0 :         if (brec.type != ACPI_FPDT_BOOT_REC)
     147           0 :                 return -EINVAL;
     148             : 
     149           0 :         if (brec.startup_start == 0 || brec.exit_services_exit < brec.startup_start)
     150           0 :                 return -EINVAL;
     151           0 :         if (brec.exit_services_exit > NSEC_PER_HOUR)
     152           0 :                 return -EINVAL;
     153             : 
     154           0 :         if (loader_start)
     155           0 :                 *loader_start = brec.startup_start / 1000;
     156           0 :         if (loader_exit)
     157           0 :                 *loader_exit = brec.exit_services_exit / 1000;
     158             : 
     159           0 :         return 0;
     160             : }

Generated by: LCOV version 1.11