2 This file is part of systemd.
4 Copyright 2013 Kay Sievers
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
27 #include "acpi-fpdt.h"
28 #include "alloc-util.h"
31 #include "time-util.h"
33 struct acpi_table_header
{
40 uint32_t oem_revision
;
41 char asl_compiler_id
[4];
42 uint32_t asl_compiler_revision
;
46 ACPI_FPDT_TYPE_BOOT
= 0,
47 ACPI_FPDT_TYPE_S3PERF
= 1,
50 struct acpi_fpdt_header
{
58 struct acpi_fpdt_boot_header
{
64 ACPI_FPDT_S3PERF_RESUME_REC
= 0,
65 ACPI_FPDT_S3PERF_SUSPEND_REC
= 1,
66 ACPI_FPDT_BOOT_REC
= 2,
69 struct acpi_fpdt_boot
{
76 uint64_t startup_start
;
77 uint64_t exit_services_entry
;
78 uint64_t exit_services_exit
;
81 int acpi_get_boot_usec(usec_t
*loader_start
, usec_t
*loader_exit
) {
82 _cleanup_free_
char *buf
= NULL
;
83 struct acpi_table_header
*tbl
;
85 struct acpi_fpdt_header
*rec
;
88 _cleanup_close_
int fd
= -1;
89 struct acpi_fpdt_boot_header hbrec
;
90 struct acpi_fpdt_boot brec
;
92 r
= read_full_file("/sys/firmware/acpi/tables/FPDT", &buf
, &l
);
96 if (l
< sizeof(struct acpi_table_header
) + sizeof(struct acpi_fpdt_header
))
99 tbl
= (struct acpi_table_header
*)buf
;
100 if (l
!= tbl
->length
)
103 if (memcmp(tbl
->signature
, "FPDT", 4) != 0)
106 /* find Firmware Basic Boot Performance Pointer Record */
107 for (rec
= (struct acpi_fpdt_header
*)(buf
+ sizeof(struct acpi_table_header
));
108 (char *)rec
< buf
+ l
;
109 rec
= (struct acpi_fpdt_header
*)((char *)rec
+ rec
->length
)) {
110 if (rec
->length
<= 0)
112 if (rec
->type
!= ACPI_FPDT_TYPE_BOOT
)
114 if (rec
->length
!= sizeof(struct acpi_fpdt_header
))
124 /* read Firmware Basic Boot Performance Data Record */
125 fd
= open("/dev/mem", O_CLOEXEC
|O_RDONLY
);
129 l
= pread(fd
, &hbrec
, sizeof(struct acpi_fpdt_boot_header
), ptr
);
130 if (l
!= sizeof(struct acpi_fpdt_boot_header
))
133 if (memcmp(hbrec
.signature
, "FBPT", 4) != 0)
136 if (hbrec
.length
< sizeof(struct acpi_fpdt_boot_header
) + sizeof(struct acpi_fpdt_boot
))
139 l
= pread(fd
, &brec
, sizeof(struct acpi_fpdt_boot
), ptr
+ sizeof(struct acpi_fpdt_boot_header
));
140 if (l
!= sizeof(struct acpi_fpdt_boot
))
143 if (brec
.length
!= sizeof(struct acpi_fpdt_boot
))
146 if (brec
.type
!= ACPI_FPDT_BOOT_REC
)
149 if (brec
.exit_services_exit
== 0)
150 /* Non-UEFI compatible boot. */
153 if (brec
.startup_start
== 0 || brec
.exit_services_exit
< brec
.startup_start
)
155 if (brec
.exit_services_exit
> NSEC_PER_HOUR
)
159 *loader_start
= brec
.startup_start
/ 1000;
161 *loader_exit
= brec
.exit_services_exit
/ 1000;