Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
+6
View File
@@ -0,0 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
/acpidbg
/acpidump
/ec
/pfrut
/include/
+26
View File
@@ -0,0 +1,26 @@
# SPDX-License-Identifier: GPL-2.0-only
# tools/power/acpi/Makefile - ACPI tool Makefile
#
# Copyright (c) 2013, Intel Corporation
# Author: Lv Zheng <lv.zheng@intel.com>
#
include ../../scripts/Makefile.include
.NOTPARALLEL:
all: acpidbg acpidump ec pfrut
clean: acpidbg_clean acpidump_clean ec_clean pfrut_clean
install: acpidbg_install acpidump_install ec_install pfrut_install
uninstall: acpidbg_uninstall acpidump_uninstall ec_uninstall pfrut_uninstall
acpidbg acpidump ec pfrut: FORCE
$(call descend,tools/$@,all)
acpidbg_clean acpidump_clean ec_clean pfrut_clean:
$(call descend,tools/$(@:_clean=),clean)
acpidbg_install acpidump_install ec_install pfrut_install:
$(call descend,tools/$(@:_install=),install)
acpidbg_uninstall acpidump_uninstall ec_uninstall pfrut_uninstall:
$(call descend,tools/$(@:_uninstall=),uninstall)
.PHONY: FORCE
@@ -0,0 +1,89 @@
# SPDX-License-Identifier: GPL-2.0-only
# tools/power/acpi/Makefile.config - ACPI tool Makefile
#
# Copyright (c) 2015, Intel Corporation
# Author: Lv Zheng <lv.zheng@intel.com>
#
ifeq ($(srctree),)
srctree := $(patsubst %/,%,$(dir $(shell pwd)))
srctree := $(patsubst %/,%,$(dir $(srctree)))
#$(info Determined 'srctree' to be $(srctree))
endif
include $(srctree)/../../scripts/Makefile.include
OUTPUT=$(srctree)/
ifeq ("$(origin O)", "command line")
OUTPUT := $(O)/tools/power/acpi/
endif
#$(info Determined 'OUTPUT' to be $(OUTPUT))
# --- CONFIGURATION BEGIN ---
# Set the following to `true' to make a unstripped, unoptimized
# binary. Leave this set to `false' for production use.
DEBUG ?= true
# make the build silent. Set this to something else to make it noisy again.
V ?= false
# Prefix to the directories we're installing to
DESTDIR ?=
# --- CONFIGURATION END ---
# Directory definitions. These are default and most probably
# do not need to be changed. Please note that DESTDIR is
# added in front of any of them
bindir ?= /usr/bin
sbindir ?= /usr/sbin
mandir ?= /usr/man
# Toolchain: what tools do we use, and what options do they need:
INSTALL = /usr/bin/install -c
INSTALL_PROGRAM = ${INSTALL}
INSTALL_DATA = ${INSTALL} -m 644
INSTALL_SCRIPT = ${INSTALL_PROGRAM}
# If you are running a cross compiler, you may want to set this
# to something more interesting, like "arm-linux-". If you want
# to compile vs uClibc, that can be done here as well.
CROSS = #/usr/i386-linux-uclibc/usr/bin/i386-uclibc-
CROSS_COMPILE ?= $(CROSS)
LD = $(CC)
# check if compiler option is supported
cc-supports = ${shell if $(CC) ${1} -S -o /dev/null -x c /dev/null > /dev/null 2>&1; then echo "$(1)"; fi;}
# use '-Os' optimization if available, else use -O2
OPTIMIZATION := $(call cc-supports,-Os,-O2)
WARNINGS := -Wall
WARNINGS += $(call cc-supports,-Wstrict-prototypes)
WARNINGS += $(call cc-supports,-Wdeclaration-after-statement)
KERNEL_INCLUDE := $(OUTPUT)include
ACPICA_INCLUDE := $(srctree)/../../../drivers/acpi/acpica
CFLAGS += -D_LINUX -I$(KERNEL_INCLUDE) -I$(ACPICA_INCLUDE)
CFLAGS += $(WARNINGS)
MKDIR = mkdir
ifeq ($(strip $(V)),false)
QUIET=@
ECHO=@echo
else
QUIET=
ECHO=@\#
endif
# if DEBUG is enabled, then we do not strip or optimize
ifeq ($(strip $(DEBUG)),true)
CFLAGS += -O1 -g -DDEBUG
STRIPCMD = /bin/true -Since_we_are_debugging
else
CFLAGS += $(OPTIMIZATION) -fomit-frame-pointer
STRIPCMD = $(STRIP) -s --remove-section=.note --remove-section=.comment
endif
@@ -0,0 +1,49 @@
# SPDX-License-Identifier: GPL-2.0-only
# tools/power/acpi/Makefile.rules - ACPI tool Makefile
#
# Copyright (c) 2015, Intel Corporation
# Author: Lv Zheng <lv.zheng@intel.com>
#
objdir := $(OUTPUT)tools/$(TOOL)/
toolobjs := $(addprefix $(objdir),$(TOOL_OBJS))
$(OUTPUT)$(TOOL): $(toolobjs) FORCE
$(ECHO) " LD " $(subst $(OUTPUT),,$@)
$(QUIET) $(LD) $(CFLAGS) $(toolobjs) $(LDFLAGS) -L$(OUTPUT) -o $@
$(ECHO) " STRIP " $(subst $(OUTPUT),,$@)
$(QUIET) $(STRIPCMD) $@
$(KERNEL_INCLUDE):
$(ECHO) " MKDIR " $(subst $(OUTPUT),,$@)
$(QUIET) mkdir -p $(KERNEL_INCLUDE)
$(ECHO) " CP " $(subst $(OUTPUT),,$@)
$(QUIET) cp -rf $(srctree)/../../../include/acpi $(KERNEL_INCLUDE)/
$(objdir)%.o: %.c $(KERNEL_INCLUDE)
$(ECHO) " CC " $(subst $(OUTPUT),,$@)
$(QUIET) $(MKDIR) -p $(objdir) 2>/dev/null
$(QUIET) $(CC) -c $(CFLAGS) -o $@ $<
all: $(OUTPUT)$(TOOL)
clean:
$(ECHO) " RMOBJ " $(subst $(OUTPUT),,$(objdir))
$(QUIET) find $(objdir) \( -not -type d \)\
-and \( -name '*~' -o -name '*.[oas]' \)\
-type f -print | xargs rm -f
$(ECHO) " RM " $(TOOL)
$(QUIET) rm -f $(OUTPUT)$(TOOL)
$(ECHO) " RMINC " $(subst $(OUTPUT),,$(KERNEL_INCLUDE))
$(QUIET) rm -rf $(KERNEL_INCLUDE)
install-tools:
$(ECHO) " INST " $(TOOL)
$(QUIET) $(INSTALL) -d $(DESTDIR)$(sbindir)
$(QUIET) $(INSTALL_PROGRAM) $(OUTPUT)$(TOOL) $(DESTDIR)$(sbindir)
uninstall-tools:
$(ECHO) " UNINST " $(TOOL)
$(QUIET) rm -f $(DESTDIR)$(sbindir)/$(TOOL)
install: all install-tools $(EXTRA_INSTALL)
uninstall: uninstall-tools $(EXTRA_UNINSTALL)
.PHONY: FORCE
@@ -0,0 +1,68 @@
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
/******************************************************************************
*
* Module Name: cmfsize - Common get file size function
*
* Copyright (C) 2000 - 2026, Intel Corp.
*
*****************************************************************************/
#include <acpi/acpi.h>
#include "accommon.h"
#include "acapps.h"
#define _COMPONENT ACPI_TOOLS
ACPI_MODULE_NAME("cmfsize")
/*******************************************************************************
*
* FUNCTION: cm_get_file_size
*
* PARAMETERS: file - Open file descriptor
*
* RETURN: File Size. On error, -1 (ACPI_UINT32_MAX)
*
* DESCRIPTION: Get the size of a file. Uses seek-to-EOF. File must be open.
* Does not disturb the current file pointer.
*
******************************************************************************/
u32 cm_get_file_size(ACPI_FILE file)
{
long file_size;
long current_offset;
acpi_status status;
/* Save the current file pointer, seek to EOF to obtain file size */
current_offset = ftell(file);
if (current_offset < 0) {
goto offset_error;
}
status = fseek(file, 0, SEEK_END);
if (ACPI_FAILURE(status)) {
goto seek_error;
}
file_size = ftell(file);
if (file_size < 0) {
goto offset_error;
}
/* Restore original file pointer */
status = fseek(file, current_offset, SEEK_SET);
if (ACPI_FAILURE(status)) {
goto seek_error;
}
return ((u32)file_size);
offset_error:
fprintf(stderr, "Could not get file offset\n");
return (ACPI_UINT32_MAX);
seek_error:
fprintf(stderr, "Could not set file offset\n");
return (ACPI_UINT32_MAX);
}
@@ -0,0 +1,205 @@
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
/******************************************************************************
*
* Module Name: getopt
*
* Copyright (C) 2000 - 2026, Intel Corp.
*
*****************************************************************************/
/*
* ACPICA getopt() implementation
*
* Option strings:
* "f" - Option has no arguments
* "f:" - Option requires an argument
* "f+" - Option has an optional argument
* "f^" - Option has optional single-char sub-options
* "f|" - Option has required single-char sub-options
*/
#include <acpi/acpi.h>
#include "accommon.h"
#include "acapps.h"
#define ACPI_OPTION_ERROR(msg, badchar) \
if (acpi_gbl_opterr) {fprintf (stderr, "%s%c\n", msg, badchar);}
int acpi_gbl_opterr = 1;
int acpi_gbl_optind = 1;
int acpi_gbl_sub_opt_char = 0;
char *acpi_gbl_optarg;
static int current_char_ptr = 1;
/*******************************************************************************
*
* FUNCTION: acpi_getopt_argument
*
* PARAMETERS: argc, argv - from main
*
* RETURN: 0 if an argument was found, -1 otherwise. Sets acpi_gbl_Optarg
* to point to the next argument.
*
* DESCRIPTION: Get the next argument. Used to obtain arguments for the
* two-character options after the original call to acpi_getopt.
* Note: Either the argument starts at the next character after
* the option, or it is pointed to by the next argv entry.
* (After call to acpi_getopt, we need to backup to the previous
* argv entry).
*
******************************************************************************/
int acpi_getopt_argument(int argc, char **argv)
{
acpi_gbl_optind--;
current_char_ptr++;
if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') {
acpi_gbl_optarg =
&argv[acpi_gbl_optind++][(int)(current_char_ptr + 1)];
} else if (++acpi_gbl_optind >= argc) {
ACPI_OPTION_ERROR("\nOption requires an argument", 0);
current_char_ptr = 1;
return (-1);
} else {
acpi_gbl_optarg = argv[acpi_gbl_optind++];
}
current_char_ptr = 1;
return (0);
}
/*******************************************************************************
*
* FUNCTION: acpi_getopt
*
* PARAMETERS: argc, argv - from main
* opts - options info list
*
* RETURN: Option character or ACPI_OPT_END
*
* DESCRIPTION: Get the next option
*
******************************************************************************/
int acpi_getopt(int argc, char **argv, char *opts)
{
int current_char;
char *opts_ptr;
if (current_char_ptr == 1) {
if (acpi_gbl_optind >= argc ||
argv[acpi_gbl_optind][0] != '-' ||
argv[acpi_gbl_optind][1] == '\0') {
return (ACPI_OPT_END);
} else if (strcmp(argv[acpi_gbl_optind], "--") == 0) {
acpi_gbl_optind++;
return (ACPI_OPT_END);
}
}
/* Get the option */
current_char = argv[acpi_gbl_optind][current_char_ptr];
/* Make sure that the option is legal */
if (current_char == ':' ||
(opts_ptr = strchr(opts, current_char)) == NULL) {
ACPI_OPTION_ERROR("Illegal option: -", current_char);
if (argv[acpi_gbl_optind][++current_char_ptr] == '\0') {
acpi_gbl_optind++;
current_char_ptr = 1;
}
return ('?');
}
/* Option requires an argument? */
if (*++opts_ptr == ':') {
if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') {
acpi_gbl_optarg =
&argv[acpi_gbl_optind++][(int)
(current_char_ptr + 1)];
} else if (++acpi_gbl_optind >= argc) {
ACPI_OPTION_ERROR("Option requires an argument: -",
current_char);
current_char_ptr = 1;
return ('?');
} else {
acpi_gbl_optarg = argv[acpi_gbl_optind++];
}
current_char_ptr = 1;
}
/* Option has an optional argument? */
else if (*opts_ptr == '+') {
if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') {
acpi_gbl_optarg =
&argv[acpi_gbl_optind++][(int)
(current_char_ptr + 1)];
} else if (++acpi_gbl_optind >= argc) {
acpi_gbl_optarg = NULL;
} else {
acpi_gbl_optarg = argv[acpi_gbl_optind++];
}
current_char_ptr = 1;
}
/* Option has optional single-char arguments? */
else if (*opts_ptr == '^') {
if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') {
acpi_gbl_optarg =
&argv[acpi_gbl_optind][(int)(current_char_ptr + 1)];
} else {
acpi_gbl_optarg = "^";
}
acpi_gbl_sub_opt_char = acpi_gbl_optarg[0];
acpi_gbl_optind++;
current_char_ptr = 1;
}
/* Option has a required single-char argument? */
else if (*opts_ptr == '|') {
if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') {
acpi_gbl_optarg =
&argv[acpi_gbl_optind][(int)(current_char_ptr + 1)];
} else {
ACPI_OPTION_ERROR
("Option requires a single-character suboption: -",
current_char);
current_char_ptr = 1;
return ('?');
}
acpi_gbl_sub_opt_char = acpi_gbl_optarg[0];
acpi_gbl_optind++;
current_char_ptr = 1;
}
/* Option with no arguments */
else {
if (argv[acpi_gbl_optind][++current_char_ptr] == '\0') {
current_char_ptr = 1;
acpi_gbl_optind++;
}
acpi_gbl_optarg = NULL;
}
return (current_char);
}
+127
View File
@@ -0,0 +1,127 @@
.TH ACPIDUMP 8
.SH NAME
acpidump \- dump a system's ACPI tables to an ASCII file
.SH SYNOPSIS
.B acpidump
.RI [ options ]
.br
.SH DESCRIPTION
.B acpidump
dumps the systems ACPI tables to an ASCII file appropriate for
attaching to a bug report.
Subsequently, they can be processed by utilities in the ACPICA package.
.SH OPTIONS
acpidump options are as follow:
.TP
.B Options
.TP
.B \-b
Dump tables to binary files
.TP
.B \-h \-?
This help message
.TP
.B \-o <File>
Redirect output to file
.TP
.B \-r <Address>
Dump tables from specified RSDP
.TP
.B \-s
Print table summaries only
.TP
.B \-v
Display version information
.TP
.B \-z
Verbose mode
.TP
.B Table Options
.TP
.B \-a <Address>
Get table via a physical address
.TP
.B \-c <on|off>
Turning on/off customized table dumping
.TP
.B \-f <BinaryFile>
Get table via a binary file
.TP
.B \-n <Signature>
Get table via a name/signature
.TP
.B \-x
Do not use but dump XSDT
.TP
.B \-x \-x
Do not use or dump XSDT
.TP
.fi
Invocation without parameters dumps all available tables.
.TP
Multiple mixed instances of -a, -f, and -n are supported.
.SH EXAMPLES
.nf
# acpidump > acpidump.out
$ acpixtract -a acpidump.out
Acpi table [DSDT] - 15974 bytes written to DSDT.dat
Acpi table [FACS] - 64 bytes written to FACS.dat
Acpi table [FACP] - 116 bytes written to FACP.dat
Acpi table [APIC] - 120 bytes written to APIC.dat
Acpi table [MCFG] - 60 bytes written to MCFG.dat
Acpi table [SSDT] - 444 bytes written to SSDT1.dat
Acpi table [SSDT] - 439 bytes written to SSDT2.dat
Acpi table [SSDT] - 439 bytes written to SSDT3.dat
Acpi table [SSDT] - 439 bytes written to SSDT4.dat
Acpi table [SSDT] - 439 bytes written to SSDT5.dat
Acpi table [RSDT] - 76 bytes written to RSDT.dat
Acpi table [RSDP] - 20 bytes written to RSDP.dat
$ iasl -d *.dat
...
.fi
creates *.dsl, a human readable form which can be edited
and compiled using iasl.
.SH NOTES
.B "acpidump "
must be run as root.
.SH REFERENCES
ACPICA: https://acpica.org/
.SH FILES
.ta
.nf
/dev/mem
/sys/firmware/acpi/tables/*
/sys/firmware/acpi/tables/dynamic/*
/sys/firmware/efi/systab
.fi
.SH AUTHOR
.TP
Original by:
Len Brown <len.brown@intel.com>
.TP
Written by:
Chao Guan <chao.guan@intel.com>
.TP
Updated by:
Bob Moore <robert.moore@intel.com>
Lv Zheng <lv.zheng@intel.com>
.SH SEE ALSO
\&\fIacpixtract\fR\|(8), \fIiasl\fR\|(8).
.SH COPYRIGHT
COPYRIGHT (c) 2013, Intel Corporation.
+137
View File
@@ -0,0 +1,137 @@
.TH "PFRUT" "8" "October 2021" "pfrut 1.0" ""
.hy
.SH Name
.PP
pfrut \- Platform Firmware Runtime Update and Telemetry tool
.SH SYNOPSIS
.PP
\f[B]pfrut\f[R] [\f[I]Options\f[R]]
.SH DESCRIPTION
.PP
The PFRUT(Platform Firmware Runtime Update and Telemetry) kernel interface is designed
to
.PD 0
.P
.PD
interact with the platform firmware interface defined in the
.PD 0
.P
.PD
Management Mode Firmware Runtime
Update (https://uefi.org/sites/default/files/resources/Intel_MM_OS_Interface_Spec_Rev100.pdf)
.PD 0
.P
.PD
\f[B]pfrut\f[R] is the tool to interact with the kernel interface.
.PD 0
.P
.PD
.SH OPTIONS
.TP
.B \f[B]\-h\f[R], \f[B]\-\-help\f[R]
Display helper information.
.TP
.B \f[B]\-l\f[R], \f[B]\-\-load\f[R]
Load the capsule file into the system.
To be more specific, the capsule file will be copied to the
communication buffer.
.TP
.B \f[B]\-s\f[R], \f[B]\-\-stage\f[R]
Stage the capsule image from communication buffer into Management Mode
and perform authentication.
.TP
.B \f[B]\-a\f[R], \f[B]\-\-activate\f[R]
Activate a previous staged capsule image.
.TP
.B \f[B]\-u\f[R], \f[B]\-\-update\f[R]
Perform both stage and activation actions.
.TP
.B \f[B]\-q\f[R], \f[B]\-\-query\f[R]
Query the update capability.
.TP
.B \f[B]\-d\f[R], \f[B]\-\-setrev\f[R]
Set the revision ID of code injection/driver update.
.TP
.B \f[B]\-D\f[R], \f[B]\-\-setrevlog\f[R]
Set the revision ID of telemetry.
.TP
.B \f[B]\-G\f[R], \f[B]\-\-getloginfo\f[R]
Get telemetry log information and print it out.
.TP
.B \f[B]\-T\f[R], \f[B]\-\-type\f[R]
Set the telemetry log data type.
.TP
.B \f[B]\-L\f[R], \f[B]\-\-level\f[R]
Set the telemetry log level.
.TP
.B \f[B]\-R\f[R], \f[B]\-\-read\f[R]
Read all the telemetry data and print it out.
.SH EXAMPLES
.PP
\f[B]pfrut \-G\f[R]
.PP
log_level:4
.PD 0
.P
.PD
log_type:0
.PD 0
.P
.PD
log_revid:2
.PD 0
.P
.PD
max_data_size:65536
.PD 0
.P
.PD
chunk1_size:0
.PD 0
.P
.PD
chunk2_size:1401
.PD 0
.P
.PD
rollover_cnt:0
.PD 0
.P
.PD
reset_cnt:4
.PP
\f[B]pfru \-q\f[R]
.PP
code injection image type:794bf8b2\-6e7b\-454e\-885f\-3fb9bb185402
.PD 0
.P
.PD
fw_version:0
.PD 0
.P
.PD
code_rt_version:1
.PD 0
.P
.PD
driver update image type:0e5f0b14\-f849\-7945\-ad81\-bc7b6d2bb245
.PD 0
.P
.PD
drv_rt_version:0
.PD 0
.P
.PD
drv_svn:0
.PD 0
.P
.PD
platform id:39214663\-b1a8\-4eaa\-9024\-f2bb53ea4723
.PD 0
.P
.PD
oem id:a36db54f\-ea2a\-e14e\-b7c4\-b5780e51ba3d
.PP
\f[B]pfrut \-l yours.cap \-u \-T 1 \-L 4\f[R]
.SH AUTHORS
Chen Yu.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,170 @@
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
/******************************************************************************
*
* Module Name: osunixdir - Unix directory access interfaces
*
* Copyright (C) 2000 - 2026, Intel Corp.
*
*****************************************************************************/
#include <acpi/acpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <fnmatch.h>
#include <ctype.h>
#include <sys/stat.h>
/*
* Allocated structure returned from os_open_directory
*/
typedef struct external_find_info {
char *dir_pathname;
DIR *dir_ptr;
char temp_buffer[256];
char *wildcard_spec;
char requested_file_type;
} external_find_info;
/*******************************************************************************
*
* FUNCTION: acpi_os_open_directory
*
* PARAMETERS: dir_pathname - Full pathname to the directory
* wildcard_spec - string of the form "*.c", etc.
*
* RETURN: A directory "handle" to be used in subsequent search operations.
* NULL returned on failure.
*
* DESCRIPTION: Open a directory in preparation for a wildcard search
*
******************************************************************************/
void *acpi_os_open_directory(char *dir_pathname,
char *wildcard_spec, char requested_file_type)
{
struct external_find_info *external_info;
DIR *dir;
/* Allocate the info struct that will be returned to the caller */
external_info = calloc(1, sizeof(struct external_find_info));
if (!external_info) {
return (NULL);
}
/* Get the directory stream */
dir = opendir(dir_pathname);
if (!dir) {
fprintf(stderr, "Cannot open directory - %s\n", dir_pathname);
free(external_info);
return (NULL);
}
/* Save the info in the return structure */
external_info->wildcard_spec = wildcard_spec;
external_info->requested_file_type = requested_file_type;
external_info->dir_pathname = dir_pathname;
external_info->dir_ptr = dir;
return (external_info);
}
/*******************************************************************************
*
* FUNCTION: acpi_os_get_next_filename
*
* PARAMETERS: dir_handle - Created via acpi_os_open_directory
*
* RETURN: Next filename matched. NULL if no more matches.
*
* DESCRIPTION: Get the next file in the directory that matches the wildcard
* specification.
*
******************************************************************************/
char *acpi_os_get_next_filename(void *dir_handle)
{
struct external_find_info *external_info = dir_handle;
struct dirent *dir_entry;
char *temp_str;
int str_len;
struct stat temp_stat;
int err;
while ((dir_entry = readdir(external_info->dir_ptr))) {
if (!fnmatch
(external_info->wildcard_spec, dir_entry->d_name, 0)) {
if (dir_entry->d_name[0] == '.') {
continue;
}
str_len = strlen(dir_entry->d_name) +
strlen(external_info->dir_pathname) + 2;
temp_str = calloc(str_len, 1);
if (!temp_str) {
fprintf(stderr,
"Could not allocate buffer for temporary string\n");
return (NULL);
}
strcpy(temp_str, external_info->dir_pathname);
strcat(temp_str, "/");
strcat(temp_str, dir_entry->d_name);
err = stat(temp_str, &temp_stat);
if (err == -1) {
fprintf(stderr,
"Cannot stat file (should not happen) - %s\n",
temp_str);
free(temp_str);
return (NULL);
}
free(temp_str);
if ((S_ISDIR(temp_stat.st_mode)
&& (external_info->requested_file_type ==
REQUEST_DIR_ONLY))
|| ((!S_ISDIR(temp_stat.st_mode)
&& external_info->requested_file_type ==
REQUEST_FILE_ONLY))) {
/* copy to a temp buffer because dir_entry struct is on the stack */
strcpy(external_info->temp_buffer,
dir_entry->d_name);
return (external_info->temp_buffer);
}
}
}
return (NULL);
}
/*******************************************************************************
*
* FUNCTION: acpi_os_close_directory
*
* PARAMETERS: dir_handle - Created via acpi_os_open_directory
*
* RETURN: None.
*
* DESCRIPTION: Close the open directory and cleanup.
*
******************************************************************************/
void acpi_os_close_directory(void *dir_handle)
{
struct external_find_info *external_info = dir_handle;
/* Close the directory and free allocations */
closedir(external_info->dir_ptr);
free(dir_handle);
}
@@ -0,0 +1,117 @@
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
/******************************************************************************
*
* Module Name: osunixmap - Unix OSL for file mappings
*
* Copyright (C) 2000 - 2026, Intel Corp.
*
*****************************************************************************/
#include "acpidump.h"
#include <unistd.h>
#include <sys/mman.h>
#ifdef _free_BSD
#include <sys/param.h>
#endif
#define _COMPONENT ACPI_OS_SERVICES
ACPI_MODULE_NAME("osunixmap")
#ifndef O_BINARY
#define O_BINARY 0
#endif
#if defined(_dragon_fly) || defined(_free_BSD) || defined(_QNX)
#define MMAP_FLAGS MAP_SHARED
#else
#define MMAP_FLAGS MAP_PRIVATE
#endif
#define SYSTEM_MEMORY "/dev/mem"
/*******************************************************************************
*
* FUNCTION: acpi_os_get_page_size
*
* PARAMETERS: None
*
* RETURN: Page size of the platform.
*
* DESCRIPTION: Obtain page size of the platform.
*
******************************************************************************/
static acpi_size acpi_os_get_page_size(void)
{
#ifdef PAGE_SIZE
return PAGE_SIZE;
#else
return sysconf(_SC_PAGESIZE);
#endif
}
/******************************************************************************
*
* FUNCTION: acpi_os_map_memory
*
* PARAMETERS: where - Physical address of memory to be mapped
* length - How much memory to map
*
* RETURN: Pointer to mapped memory. Null on error.
*
* DESCRIPTION: Map physical memory into local address space.
*
*****************************************************************************/
void *acpi_os_map_memory(acpi_physical_address where, acpi_size length)
{
u8 *mapped_memory;
acpi_physical_address offset;
acpi_size page_size;
int fd;
fd = open(SYSTEM_MEMORY, O_RDONLY | O_BINARY);
if (fd < 0) {
fprintf(stderr, "Cannot open %s\n", SYSTEM_MEMORY);
return (NULL);
}
/* Align the offset to use mmap */
page_size = acpi_os_get_page_size();
offset = where % page_size;
/* Map the table header to get the length of the full table */
mapped_memory = mmap(NULL, (length + offset), PROT_READ, MMAP_FLAGS,
fd, (where - offset));
if (mapped_memory == MAP_FAILED) {
fprintf(stderr, "Cannot map %s\n", SYSTEM_MEMORY);
close(fd);
return (NULL);
}
close(fd);
return (ACPI_CAST8(mapped_memory + offset));
}
/******************************************************************************
*
* FUNCTION: acpi_os_unmap_memory
*
* PARAMETERS: where - Logical address of memory to be unmapped
* length - How much memory to unmap
*
* RETURN: None.
*
* DESCRIPTION: Delete a previously created mapping. Where and Length must
* correspond to a previous mapping exactly.
*
*****************************************************************************/
void acpi_os_unmap_memory(void *where, acpi_size length)
{
acpi_physical_address offset;
acpi_size page_size;
page_size = acpi_os_get_page_size();
offset = ACPI_TO_INTEGER(where) % page_size;
munmap((u8 *)where - offset, (length + offset));
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,22 @@
# SPDX-License-Identifier: GPL-2.0-only
# tools/power/acpi/tools/acpidbg/Makefile - ACPI tool Makefile
#
# Copyright (c) 2015, Intel Corporation
# Author: Lv Zheng <lv.zheng@intel.com>
#
include ../../Makefile.config
TOOL = acpidbg
vpath %.c \
../../../../../drivers/acpi/acpica\
../../common\
../../os_specific/service_layers\
.
CFLAGS += -DACPI_APPLICATION -DACPI_SINGLE_THREAD -DACPI_DEBUGGER\
-I.
LDFLAGS += -lpthread
TOOL_OBJS = \
acpidbg.o
include ../../Makefile.rules
@@ -0,0 +1,441 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* ACPI AML interfacing userspace utility
*
* Copyright (C) 2015, Intel Corporation
* Authors: Lv Zheng <lv.zheng@intel.com>
*/
#include <acpi/acpi.h>
/* Headers not included by include/acpi/platform/aclinux.h */
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <error.h>
#include <stdbool.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/select.h>
#include "../../../../../include/linux/circ_buf.h"
#define ACPI_AML_FILE "/sys/kernel/debug/acpi/acpidbg"
#define ACPI_AML_SEC_TICK 1
#define ACPI_AML_USEC_PEEK 200
#define ACPI_AML_BUF_SIZE 4096
#define ACPI_AML_BATCH_WRITE_CMD 0x00 /* Write command to kernel */
#define ACPI_AML_BATCH_READ_LOG 0x01 /* Read log from kernel */
#define ACPI_AML_BATCH_WRITE_LOG 0x02 /* Write log to console */
#define ACPI_AML_LOG_START 0x00
#define ACPI_AML_PROMPT_START 0x01
#define ACPI_AML_PROMPT_STOP 0x02
#define ACPI_AML_LOG_STOP 0x03
#define ACPI_AML_PROMPT_ROLL 0x04
#define ACPI_AML_INTERACTIVE 0x00
#define ACPI_AML_BATCH 0x01
#define circ_count(circ) \
(CIRC_CNT((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
#define circ_count_to_end(circ) \
(CIRC_CNT_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
#define circ_space(circ) \
(CIRC_SPACE((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
#define circ_space_to_end(circ) \
(CIRC_SPACE_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
#define acpi_aml_cmd_count() circ_count(&acpi_aml_cmd_crc)
#define acpi_aml_log_count() circ_count(&acpi_aml_log_crc)
#define acpi_aml_cmd_space() circ_space(&acpi_aml_cmd_crc)
#define acpi_aml_log_space() circ_space(&acpi_aml_log_crc)
#define ACPI_AML_DO(_fd, _op, _buf, _ret) \
do { \
_ret = acpi_aml_##_op(_fd, &acpi_aml_##_buf##_crc); \
if (_ret == 0) { \
fprintf(stderr, \
"%s %s pipe closed.\n", #_buf, #_op); \
return; \
} \
} while (0)
#define ACPI_AML_BATCH_DO(_fd, _op, _buf, _ret) \
do { \
_ret = acpi_aml_##_op##_batch_##_buf(_fd, \
&acpi_aml_##_buf##_crc); \
if (_ret == 0) \
return; \
} while (0)
static char acpi_aml_cmd_buf[ACPI_AML_BUF_SIZE];
static char acpi_aml_log_buf[ACPI_AML_BUF_SIZE];
static struct circ_buf acpi_aml_cmd_crc = {
.buf = acpi_aml_cmd_buf,
.head = 0,
.tail = 0,
};
static struct circ_buf acpi_aml_log_crc = {
.buf = acpi_aml_log_buf,
.head = 0,
.tail = 0,
};
static const char *acpi_aml_file_path = ACPI_AML_FILE;
static unsigned long acpi_aml_mode = ACPI_AML_INTERACTIVE;
static bool acpi_aml_exit;
static bool acpi_aml_batch_drain;
static unsigned long acpi_aml_batch_state;
static char acpi_aml_batch_prompt;
static char acpi_aml_batch_roll;
static unsigned long acpi_aml_log_state;
static char *acpi_aml_batch_cmd = NULL;
static char *acpi_aml_batch_pos = NULL;
static int acpi_aml_set_fl(int fd, int flags)
{
int ret;
ret = fcntl(fd, F_GETFL, 0);
if (ret < 0) {
perror("fcntl(F_GETFL)");
return ret;
}
flags |= ret;
ret = fcntl(fd, F_SETFL, flags);
if (ret < 0) {
perror("fcntl(F_SETFL)");
return ret;
}
return ret;
}
static int acpi_aml_set_fd(int fd, int maxfd, fd_set *set)
{
if (fd > maxfd)
maxfd = fd;
FD_SET(fd, set);
return maxfd;
}
static int acpi_aml_read(int fd, struct circ_buf *crc)
{
char *p;
int len;
p = &crc->buf[crc->head];
len = circ_space_to_end(crc);
len = read(fd, p, len);
if (len < 0)
perror("read");
else if (len > 0)
crc->head = (crc->head + len) & (ACPI_AML_BUF_SIZE - 1);
return len;
}
static int acpi_aml_read_batch_cmd(int unused, struct circ_buf *crc)
{
char *p;
int len;
int remained = strlen(acpi_aml_batch_pos);
p = &crc->buf[crc->head];
len = circ_space_to_end(crc);
if (len > remained) {
memcpy(p, acpi_aml_batch_pos, remained);
acpi_aml_batch_pos += remained;
len = remained;
} else {
memcpy(p, acpi_aml_batch_pos, len);
acpi_aml_batch_pos += len;
}
if (len > 0)
crc->head = (crc->head + len) & (ACPI_AML_BUF_SIZE - 1);
return len;
}
static int acpi_aml_read_batch_log(int fd, struct circ_buf *crc)
{
char *p;
int len;
int ret = 0;
p = &crc->buf[crc->head];
len = circ_space_to_end(crc);
while (ret < len && acpi_aml_log_state != ACPI_AML_LOG_STOP) {
if (acpi_aml_log_state == ACPI_AML_PROMPT_ROLL) {
*p = acpi_aml_batch_roll;
len = 1;
crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
ret += 1;
acpi_aml_log_state = ACPI_AML_LOG_START;
} else {
len = read(fd, p, 1);
if (len <= 0) {
if (len < 0)
perror("read");
ret = len;
break;
}
}
switch (acpi_aml_log_state) {
case ACPI_AML_LOG_START:
if (*p == '\n')
acpi_aml_log_state = ACPI_AML_PROMPT_START;
crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
ret += 1;
break;
case ACPI_AML_PROMPT_START:
if (*p == ACPI_DEBUGGER_COMMAND_PROMPT ||
*p == ACPI_DEBUGGER_EXECUTE_PROMPT) {
acpi_aml_batch_prompt = *p;
acpi_aml_log_state = ACPI_AML_PROMPT_STOP;
} else {
if (*p != '\n')
acpi_aml_log_state = ACPI_AML_LOG_START;
crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
ret += 1;
}
break;
case ACPI_AML_PROMPT_STOP:
if (*p == ' ') {
acpi_aml_log_state = ACPI_AML_LOG_STOP;
acpi_aml_exit = true;
} else {
/* Roll back */
acpi_aml_log_state = ACPI_AML_PROMPT_ROLL;
acpi_aml_batch_roll = *p;
*p = acpi_aml_batch_prompt;
crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
ret += 1;
}
break;
default:
assert(0);
break;
}
}
return ret;
}
static int acpi_aml_write(int fd, struct circ_buf *crc)
{
char *p;
int len;
p = &crc->buf[crc->tail];
len = circ_count_to_end(crc);
len = write(fd, p, len);
if (len < 0)
perror("write");
else if (len > 0)
crc->tail = (crc->tail + len) & (ACPI_AML_BUF_SIZE - 1);
return len;
}
static int acpi_aml_write_batch_log(int fd, struct circ_buf *crc)
{
char *p;
int len;
p = &crc->buf[crc->tail];
len = circ_count_to_end(crc);
if (!acpi_aml_batch_drain) {
len = write(fd, p, len);
if (len < 0)
perror("write");
}
if (len > 0)
crc->tail = (crc->tail + len) & (ACPI_AML_BUF_SIZE - 1);
return len;
}
static int acpi_aml_write_batch_cmd(int fd, struct circ_buf *crc)
{
int len;
len = acpi_aml_write(fd, crc);
if (circ_count_to_end(crc) == 0)
acpi_aml_batch_state = ACPI_AML_BATCH_READ_LOG;
return len;
}
static void acpi_aml_loop(int fd)
{
fd_set rfds;
fd_set wfds;
struct timeval tv;
int ret;
int maxfd = 0;
if (acpi_aml_mode == ACPI_AML_BATCH) {
acpi_aml_log_state = ACPI_AML_LOG_START;
acpi_aml_batch_pos = acpi_aml_batch_cmd;
if (acpi_aml_batch_drain)
acpi_aml_batch_state = ACPI_AML_BATCH_READ_LOG;
else
acpi_aml_batch_state = ACPI_AML_BATCH_WRITE_CMD;
}
acpi_aml_exit = false;
while (!acpi_aml_exit) {
tv.tv_sec = ACPI_AML_SEC_TICK;
tv.tv_usec = 0;
FD_ZERO(&rfds);
FD_ZERO(&wfds);
if (acpi_aml_cmd_space()) {
if (acpi_aml_mode == ACPI_AML_INTERACTIVE)
maxfd = acpi_aml_set_fd(STDIN_FILENO, maxfd, &rfds);
else if (strlen(acpi_aml_batch_pos) &&
acpi_aml_batch_state == ACPI_AML_BATCH_WRITE_CMD)
ACPI_AML_BATCH_DO(STDIN_FILENO, read, cmd, ret);
}
if (acpi_aml_cmd_count() &&
(acpi_aml_mode == ACPI_AML_INTERACTIVE ||
acpi_aml_batch_state == ACPI_AML_BATCH_WRITE_CMD))
maxfd = acpi_aml_set_fd(fd, maxfd, &wfds);
if (acpi_aml_log_space() &&
(acpi_aml_mode == ACPI_AML_INTERACTIVE ||
acpi_aml_batch_state == ACPI_AML_BATCH_READ_LOG))
maxfd = acpi_aml_set_fd(fd, maxfd, &rfds);
if (acpi_aml_log_count())
maxfd = acpi_aml_set_fd(STDOUT_FILENO, maxfd, &wfds);
ret = select(maxfd+1, &rfds, &wfds, NULL, &tv);
if (ret < 0) {
perror("select");
break;
}
if (ret > 0) {
if (FD_ISSET(STDIN_FILENO, &rfds))
ACPI_AML_DO(STDIN_FILENO, read, cmd, ret);
if (FD_ISSET(fd, &wfds)) {
if (acpi_aml_mode == ACPI_AML_BATCH)
ACPI_AML_BATCH_DO(fd, write, cmd, ret);
else
ACPI_AML_DO(fd, write, cmd, ret);
}
if (FD_ISSET(fd, &rfds)) {
if (acpi_aml_mode == ACPI_AML_BATCH)
ACPI_AML_BATCH_DO(fd, read, log, ret);
else
ACPI_AML_DO(fd, read, log, ret);
}
if (FD_ISSET(STDOUT_FILENO, &wfds)) {
if (acpi_aml_mode == ACPI_AML_BATCH)
ACPI_AML_BATCH_DO(STDOUT_FILENO, write, log, ret);
else
ACPI_AML_DO(STDOUT_FILENO, write, log, ret);
}
}
}
}
static bool acpi_aml_readable(int fd)
{
fd_set rfds;
struct timeval tv;
int ret;
int maxfd = 0;
tv.tv_sec = 0;
tv.tv_usec = ACPI_AML_USEC_PEEK;
FD_ZERO(&rfds);
maxfd = acpi_aml_set_fd(fd, maxfd, &rfds);
ret = select(maxfd+1, &rfds, NULL, NULL, &tv);
if (ret < 0)
perror("select");
if (ret > 0 && FD_ISSET(fd, &rfds))
return true;
return false;
}
/*
* This is a userspace IO flush implementation, replying on the prompt
* characters and can be turned into a flush() call after kernel implements
* .flush() filesystem operation.
*/
static void acpi_aml_flush(int fd)
{
while (acpi_aml_readable(fd)) {
acpi_aml_batch_drain = true;
acpi_aml_loop(fd);
acpi_aml_batch_drain = false;
}
}
void usage(FILE *file, char *progname)
{
fprintf(file, "usage: %s [-b cmd] [-f file] [-h]\n", progname);
fprintf(file, "\nOptions:\n");
fprintf(file, " -b Specify command to be executed in batch mode\n");
fprintf(file, " -f Specify interface file other than");
fprintf(file, " /sys/kernel/debug/acpi/acpidbg\n");
fprintf(file, " -h Print this help message\n");
}
int main(int argc, char **argv)
{
int fd = -1;
int ch;
int len;
int ret = EXIT_SUCCESS;
while ((ch = getopt(argc, argv, "b:f:h")) != -1) {
switch (ch) {
case 'b':
if (acpi_aml_batch_cmd) {
fprintf(stderr, "Already specify %s\n",
acpi_aml_batch_cmd);
ret = EXIT_FAILURE;
goto exit;
}
len = strlen(optarg);
acpi_aml_batch_cmd = calloc(len + 2, 1);
if (!acpi_aml_batch_cmd) {
perror("calloc");
ret = EXIT_FAILURE;
goto exit;
}
memcpy(acpi_aml_batch_cmd, optarg, len);
acpi_aml_batch_cmd[len] = '\n';
acpi_aml_mode = ACPI_AML_BATCH;
break;
case 'f':
acpi_aml_file_path = optarg;
break;
case 'h':
usage(stdout, argv[0]);
goto exit;
break;
case '?':
default:
usage(stderr, argv[0]);
ret = EXIT_FAILURE;
goto exit;
break;
}
}
fd = open(acpi_aml_file_path, O_RDWR | O_NONBLOCK);
if (fd < 0) {
perror("open");
ret = EXIT_FAILURE;
goto exit;
}
acpi_aml_set_fl(STDIN_FILENO, O_NONBLOCK);
acpi_aml_set_fl(STDOUT_FILENO, O_NONBLOCK);
if (acpi_aml_mode == ACPI_AML_BATCH)
acpi_aml_flush(fd);
acpi_aml_loop(fd);
exit:
if (fd >= 0)
close(fd);
if (acpi_aml_batch_cmd)
free(acpi_aml_batch_cmd);
return ret;
}
@@ -0,0 +1,54 @@
# SPDX-License-Identifier: GPL-2.0-only
# tools/power/acpi/tools/acpidump/Makefile - ACPI tool Makefile
#
# Copyright (c) 2015, Intel Corporation
# Author: Lv Zheng <lv.zheng@intel.com>
#
include ../../Makefile.config
TOOL = acpidump
EXTRA_INSTALL = install-man
EXTRA_UNINSTALL = uninstall-man
vpath %.c \
../../../../../drivers/acpi/acpica\
./\
../../common\
../../os_specific/service_layers
CFLAGS += -DACPI_DUMP_APP -I.
TOOL_OBJS = \
apdump.o\
apfiles.o\
apmain.o\
osunixdir.o\
osunixmap.o\
osunixxf.o\
tbprint.o\
tbxfroot.o\
utascii.o\
utbuffer.o\
utcksum.o\
utdebug.o\
utexcep.o\
utglobal.o\
uthex.o\
utmath.o\
utnonansi.o\
utprint.o\
utstring.o\
utstrsuppt.o\
utstrtoul64.o\
utxferror.o\
oslinuxtbl.o\
cmfsize.o\
getopt.o
include ../../Makefile.rules
install-man: $(srctree)/man/acpidump.8
$(ECHO) " INST " acpidump.8
$(QUIET) $(INSTALL_DATA) -D $< $(DESTDIR)$(mandir)/man8/acpidump.8
uninstall-man:
$(ECHO) " UNINST " acpidump.8
$(QUIET) rm -f $(DESTDIR)$(mandir)/man8/acpidump.8
@@ -0,0 +1,85 @@
/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */
/******************************************************************************
*
* Module Name: acpidump.h - Include file for acpi_dump utility
*
* Copyright (C) 2000 - 2026, Intel Corp.
*
*****************************************************************************/
/*
* Global variables. Defined in main.c only, externed in all other files
*/
#ifdef _DECLARE_GLOBALS
#define EXTERN
#define INIT_GLOBAL(a,b) a=b
#else
#define EXTERN extern
#define INIT_GLOBAL(a,b) a
#endif
#include <acpi/acpi.h>
#include "accommon.h"
#include "actables.h"
#include "acapps.h"
/* Globals */
EXTERN u8 INIT_GLOBAL(gbl_summary_mode, FALSE);
EXTERN u8 INIT_GLOBAL(gbl_verbose_mode, FALSE);
EXTERN u8 INIT_GLOBAL(gbl_binary_mode, FALSE);
EXTERN u8 INIT_GLOBAL(gbl_dump_customized_tables, TRUE);
EXTERN u8 INIT_GLOBAL(gbl_do_not_dump_xsdt, FALSE);
EXTERN ACPI_FILE INIT_GLOBAL(gbl_output_file, NULL);
EXTERN char INIT_GLOBAL(*gbl_output_filename, NULL);
EXTERN u64 INIT_GLOBAL(gbl_rsdp_base, 0);
/* Action table used to defer requested options */
struct ap_dump_action {
char *argument;
u32 to_be_done;
};
#define AP_MAX_ACTIONS 32
#define AP_DUMP_ALL_TABLES 0
#define AP_DUMP_TABLE_BY_ADDRESS 1
#define AP_DUMP_TABLE_BY_NAME 2
#define AP_DUMP_TABLE_BY_FILE 3
#define AP_MAX_ACPI_FILES 256 /* Prevent infinite loops */
/* Minimum FADT sizes for various table addresses */
#define MIN_FADT_FOR_DSDT (ACPI_FADT_OFFSET (dsdt) + sizeof (u32))
#define MIN_FADT_FOR_FACS (ACPI_FADT_OFFSET (facs) + sizeof (u32))
#define MIN_FADT_FOR_XDSDT (ACPI_FADT_OFFSET (Xdsdt) + sizeof (u64))
#define MIN_FADT_FOR_XFACS (ACPI_FADT_OFFSET (Xfacs) + sizeof (u64))
/*
* apdump - Table get/dump routines
*/
int ap_dump_table_from_file(char *pathname);
int ap_dump_table_by_name(char *signature);
int ap_dump_table_by_address(char *ascii_address);
int ap_dump_all_tables(void);
u8 ap_is_valid_header(struct acpi_table_header *table);
u8 ap_is_valid_checksum(struct acpi_table_header *table);
u32 ap_get_table_length(struct acpi_table_header *table);
/*
* apfiles - File I/O utilities
*/
int ap_open_output_file(char *pathname);
int ap_write_to_binary_file(struct acpi_table_header *table, u32 instance);
struct acpi_table_header *ap_get_table_from_file(char *pathname,
u32 *file_size);
@@ -0,0 +1,405 @@
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
/******************************************************************************
*
* Module Name: apdump - Dump routines for ACPI tables (acpidump)
*
* Copyright (C) 2000 - 2026, Intel Corp.
*
*****************************************************************************/
#include "acpidump.h"
/* Local prototypes */
static int
ap_dump_table_buffer(struct acpi_table_header *table,
u32 instance, acpi_physical_address address);
/******************************************************************************
*
* FUNCTION: ap_is_valid_header
*
* PARAMETERS: table - Pointer to table to be validated
*
* RETURN: TRUE if the header appears to be valid. FALSE otherwise
*
* DESCRIPTION: Check for a valid ACPI table header
*
******************************************************************************/
u8 ap_is_valid_header(struct acpi_table_header *table)
{
if (!ACPI_VALIDATE_RSDP_SIG(table->signature)) {
/* Make sure signature is all ASCII and a valid ACPI name */
if (!acpi_ut_valid_nameseg(table->signature)) {
fprintf(stderr,
"Table signature (0x%8.8X) is invalid\n",
*(u32 *)table->signature);
return (FALSE);
}
/* Check for minimum table length */
if (table->length < sizeof(struct acpi_table_header)) {
fprintf(stderr, "Table length (0x%8.8X) is invalid\n",
table->length);
return (FALSE);
}
}
return (TRUE);
}
/******************************************************************************
*
* FUNCTION: ap_is_valid_checksum
*
* PARAMETERS: table - Pointer to table to be validated
*
* RETURN: TRUE if the checksum appears to be valid. FALSE otherwise.
*
* DESCRIPTION: Check for a valid ACPI table checksum.
*
******************************************************************************/
u8 ap_is_valid_checksum(struct acpi_table_header *table)
{
acpi_status status;
struct acpi_table_rsdp *rsdp;
if (ACPI_VALIDATE_RSDP_SIG(table->signature)) {
/*
* Checksum for RSDP.
* Note: Other checksums are computed during the table dump.
*/
rsdp = ACPI_CAST_PTR(struct acpi_table_rsdp, table);
status = acpi_tb_validate_rsdp(rsdp);
} else {
/* We don't have to check for a CDAT here, since CDAT is not in the RSDT/XSDT */
status = acpi_ut_verify_checksum(table, table->length);
}
if (ACPI_FAILURE(status)) {
fprintf(stderr, "%4.4s: Warning: wrong checksum in table\n",
table->signature);
return (FALSE);
}
return (TRUE);
}
/******************************************************************************
*
* FUNCTION: ap_get_table_length
*
* PARAMETERS: table - Pointer to the table
*
* RETURN: Table length
*
* DESCRIPTION: Obtain table length according to table signature.
*
******************************************************************************/
u32 ap_get_table_length(struct acpi_table_header *table)
{
struct acpi_table_rsdp *rsdp;
/* Check if table is valid */
if (!ap_is_valid_header(table)) {
return (0);
}
if (ACPI_VALIDATE_RSDP_SIG(table->signature)) {
rsdp = ACPI_CAST_PTR(struct acpi_table_rsdp, table);
return (acpi_tb_get_rsdp_length(rsdp));
}
/* Normal ACPI table */
return (table->length);
}
/******************************************************************************
*
* FUNCTION: ap_dump_table_buffer
*
* PARAMETERS: table - ACPI table to be dumped
* instance - ACPI table instance no. to be dumped
* address - Physical address of the table
*
* RETURN: None
*
* DESCRIPTION: Dump an ACPI table in standard ASCII hex format, with a
* header that is compatible with the acpi_xtract utility.
*
******************************************************************************/
static int
ap_dump_table_buffer(struct acpi_table_header *table,
u32 instance, acpi_physical_address address)
{
u32 table_length;
table_length = ap_get_table_length(table);
/* Print only the header if requested */
if (gbl_summary_mode) {
acpi_tb_print_table_header(address, table);
return (0);
}
/* Dump to binary file if requested */
if (gbl_binary_mode) {
return (ap_write_to_binary_file(table, instance));
}
/*
* Dump the table with header for use with acpixtract utility.
* Note: simplest to just always emit a 64-bit address. acpi_xtract
* utility can handle this.
*/
fprintf(gbl_output_file, "%4.4s @ 0x%8.8X%8.8X\n",
table->signature, ACPI_FORMAT_UINT64(address));
acpi_ut_dump_buffer_to_file(gbl_output_file,
ACPI_CAST_PTR(u8, table), table_length,
DB_BYTE_DISPLAY, 0);
fprintf(gbl_output_file, "\n");
return (0);
}
/******************************************************************************
*
* FUNCTION: ap_dump_all_tables
*
* PARAMETERS: None
*
* RETURN: Status
*
* DESCRIPTION: Get all tables from the RSDT/XSDT (or at least all of the
* tables that we can possibly get).
*
******************************************************************************/
int ap_dump_all_tables(void)
{
struct acpi_table_header *table;
u32 instance = 0;
acpi_physical_address address;
acpi_status status;
int table_status;
u32 i;
/* Get and dump all available ACPI tables */
for (i = 0; i < AP_MAX_ACPI_FILES; i++) {
status =
acpi_os_get_table_by_index(i, &table, &instance, &address);
if (ACPI_FAILURE(status)) {
/* AE_LIMIT means that no more tables are available */
if (status == AE_LIMIT) {
return (0);
} else if (i == 0) {
fprintf(stderr,
"Could not get ACPI tables, %s\n",
acpi_format_exception(status));
return (-1);
} else {
fprintf(stderr,
"Could not get ACPI table at index %u, %s\n",
i, acpi_format_exception(status));
continue;
}
}
table_status = ap_dump_table_buffer(table, instance, address);
ACPI_FREE(table);
if (table_status) {
break;
}
}
/* Something seriously bad happened if the loop terminates here */
return (-1);
}
/******************************************************************************
*
* FUNCTION: ap_dump_table_by_address
*
* PARAMETERS: ascii_address - Address for requested ACPI table
*
* RETURN: Status
*
* DESCRIPTION: Get an ACPI table via a physical address and dump it.
*
******************************************************************************/
int ap_dump_table_by_address(char *ascii_address)
{
acpi_physical_address address;
struct acpi_table_header *table;
acpi_status status;
int table_status;
u64 long_address;
/* Convert argument to an integer physical address */
status = acpi_ut_strtoul64(ascii_address, &long_address);
if (ACPI_FAILURE(status)) {
fprintf(stderr, "%s: Could not convert to a physical address\n",
ascii_address);
return (-1);
}
address = (acpi_physical_address)long_address;
status = acpi_os_get_table_by_address(address, &table);
if (ACPI_FAILURE(status)) {
fprintf(stderr, "Could not get table at 0x%8.8X%8.8X, %s\n",
ACPI_FORMAT_UINT64(address),
acpi_format_exception(status));
return (-1);
}
table_status = ap_dump_table_buffer(table, 0, address);
ACPI_FREE(table);
return (table_status);
}
/******************************************************************************
*
* FUNCTION: ap_dump_table_by_name
*
* PARAMETERS: signature - Requested ACPI table signature
*
* RETURN: Status
*
* DESCRIPTION: Get an ACPI table via a signature and dump it. Handles
* multiple tables with the same signature (SSDTs).
*
******************************************************************************/
int ap_dump_table_by_name(char *signature)
{
char local_signature[ACPI_NAMESEG_SIZE + 1];
u32 instance;
struct acpi_table_header *table;
acpi_physical_address address;
acpi_status status;
int table_status;
if (strlen(signature) != ACPI_NAMESEG_SIZE) {
fprintf(stderr,
"Invalid table signature [%s]: must be exactly 4 characters\n",
signature);
return (-1);
}
/* Table signatures are expected to be uppercase */
strcpy(local_signature, signature);
acpi_ut_strupr(local_signature);
/* To be friendly, handle tables whose signatures do not match the name */
if (ACPI_COMPARE_NAMESEG(local_signature, "FADT")) {
strcpy(local_signature, ACPI_SIG_FADT);
} else if (ACPI_COMPARE_NAMESEG(local_signature, "MADT")) {
strcpy(local_signature, ACPI_SIG_MADT);
}
/* Dump all instances of this signature (to handle multiple SSDTs) */
for (instance = 0; instance < AP_MAX_ACPI_FILES; instance++) {
status = acpi_os_get_table_by_name(local_signature, instance,
&table, &address);
if (ACPI_FAILURE(status)) {
/* AE_LIMIT means that no more tables are available */
if (status == AE_LIMIT) {
return (0);
}
fprintf(stderr,
"Could not get ACPI table with signature [%s], %s\n",
local_signature, acpi_format_exception(status));
return (-1);
}
table_status = ap_dump_table_buffer(table, instance, address);
ACPI_FREE(table);
if (table_status) {
break;
}
}
/* Something seriously bad happened if the loop terminates here */
return (-1);
}
/******************************************************************************
*
* FUNCTION: ap_dump_table_from_file
*
* PARAMETERS: pathname - File containing the binary ACPI table
*
* RETURN: Status
*
* DESCRIPTION: Dump an ACPI table from a binary file
*
******************************************************************************/
int ap_dump_table_from_file(char *pathname)
{
struct acpi_table_header *table;
u32 file_size = 0;
int table_status = -1;
/* Get the entire ACPI table from the file */
table = ap_get_table_from_file(pathname, &file_size);
if (!table) {
return (-1);
}
if (!acpi_ut_valid_nameseg(table->signature)) {
fprintf(stderr,
"No valid ACPI signature was found in input file %s\n",
pathname);
}
/* File must be at least as long as the table length */
if (table->length > file_size) {
fprintf(stderr,
"Table length (0x%X) is too large for input file (0x%X) %s\n",
table->length, file_size, pathname);
goto exit;
}
if (gbl_verbose_mode) {
fprintf(stderr,
"Input file: %s contains table [%4.4s], 0x%X (%u) bytes\n",
pathname, table->signature, file_size, file_size);
}
table_status = ap_dump_table_buffer(table, 0, 0);
exit:
ACPI_FREE(table);
return (table_status);
}
@@ -0,0 +1,229 @@
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
/******************************************************************************
*
* Module Name: apfiles - File-related functions for acpidump utility
*
* Copyright (C) 2000 - 2026, Intel Corp.
*
*****************************************************************************/
#include "acpidump.h"
/* Local prototypes */
static int ap_is_existing_file(char *pathname);
/******************************************************************************
*
* FUNCTION: ap_is_existing_file
*
* PARAMETERS: pathname - Output filename
*
* RETURN: 0 on success
*
* DESCRIPTION: Query for file overwrite if it already exists.
*
******************************************************************************/
static int ap_is_existing_file(char *pathname)
{
#if !defined(_GNU_EFI) && !defined(_EDK2_EFI)
struct stat stat_info;
int in_char;
if (!stat(pathname, &stat_info)) {
fprintf(stderr,
"Target path already exists, overwrite? [y|n] ");
in_char = fgetc(stdin);
if (in_char == '\n') {
in_char = fgetc(stdin);
}
if (in_char != 'y' && in_char != 'Y') {
return (-1);
}
}
#endif
return (0);
}
/******************************************************************************
*
* FUNCTION: ap_open_output_file
*
* PARAMETERS: pathname - Output filename
*
* RETURN: Open file handle
*
* DESCRIPTION: Open a text output file for acpidump. Checks if file already
* exists.
*
******************************************************************************/
int ap_open_output_file(char *pathname)
{
ACPI_FILE file;
/* If file exists, prompt for overwrite */
if (ap_is_existing_file(pathname) != 0) {
return (-1);
}
/* Point stdout to the file */
file = fopen(pathname, "w");
if (!file) {
fprintf(stderr, "Could not open output file: %s\n", pathname);
return (-1);
}
/* Save the file and path */
gbl_output_file = file;
gbl_output_filename = pathname;
return (0);
}
/******************************************************************************
*
* FUNCTION: ap_write_to_binary_file
*
* PARAMETERS: table - ACPI table to be written
* instance - ACPI table instance no. to be written
*
* RETURN: Status
*
* DESCRIPTION: Write an ACPI table to a binary file. Builds the output
* filename from the table signature.
*
******************************************************************************/
int ap_write_to_binary_file(struct acpi_table_header *table, u32 instance)
{
char filename[ACPI_NAMESEG_SIZE + 16];
char instance_str[16];
ACPI_FILE file;
acpi_size actual;
u32 table_length;
/* Obtain table length */
table_length = ap_get_table_length(table);
/* Construct lower-case filename from the table local signature */
if (ACPI_VALIDATE_RSDP_SIG(table->signature)) {
ACPI_COPY_NAMESEG(filename, ACPI_RSDP_NAME);
} else {
ACPI_COPY_NAMESEG(filename, table->signature);
}
filename[0] = (char)tolower((int)filename[0]);
filename[1] = (char)tolower((int)filename[1]);
filename[2] = (char)tolower((int)filename[2]);
filename[3] = (char)tolower((int)filename[3]);
filename[ACPI_NAMESEG_SIZE] = 0;
/* Handle multiple SSDts - create different filenames for each */
if (instance > 0) {
snprintf(instance_str, sizeof(instance_str), "%u", instance);
strcat(filename, instance_str);
}
strcat(filename, FILE_SUFFIX_BINARY_TABLE);
if (gbl_verbose_mode) {
fprintf(stderr,
"Writing [%4.4s] to binary file: %s 0x%X (%u) bytes\n",
table->signature, filename, table->length,
table->length);
}
/* Open the file and dump the entire table in binary mode */
file = fopen(filename, "wb");
if (!file) {
fprintf(stderr, "Could not open output file: %s\n", filename);
return (-1);
}
actual = fwrite(table, 1, table_length, file);
if (actual != table_length) {
fprintf(stderr, "Error writing binary output file: %s\n",
filename);
fclose(file);
return (-1);
}
fclose(file);
return (0);
}
/******************************************************************************
*
* FUNCTION: ap_get_table_from_file
*
* PARAMETERS: pathname - File containing the binary ACPI table
* out_file_size - Where the file size is returned
*
* RETURN: Buffer containing the ACPI table. NULL on error.
*
* DESCRIPTION: Open a file and read it entirely into a new buffer
*
******************************************************************************/
struct acpi_table_header *ap_get_table_from_file(char *pathname,
u32 *out_file_size)
{
struct acpi_table_header *buffer = NULL;
ACPI_FILE file;
u32 file_size;
acpi_size actual;
/* Must use binary mode */
file = fopen(pathname, "rb");
if (!file) {
fprintf(stderr, "Could not open input file: %s\n", pathname);
return (NULL);
}
/* Need file size to allocate a buffer */
file_size = cm_get_file_size(file);
if (file_size == ACPI_UINT32_MAX) {
fprintf(stderr,
"Could not get input file size: %s\n", pathname);
goto cleanup;
}
/* Allocate a buffer for the entire file */
buffer = ACPI_ALLOCATE_ZEROED(file_size);
if (!buffer) {
fprintf(stderr,
"Could not allocate file buffer of size: %u\n",
file_size);
goto cleanup;
}
/* Read the entire file */
actual = fread(buffer, 1, file_size, file);
if (actual != file_size) {
fprintf(stderr, "Could not read input file: %s\n", pathname);
ACPI_FREE(buffer);
buffer = NULL;
goto cleanup;
}
*out_file_size = file_size;
cleanup:
fclose(file);
return (buffer);
}
@@ -0,0 +1,366 @@
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
/******************************************************************************
*
* Module Name: apmain - Main module for the acpidump utility
*
* Copyright (C) 2000 - 2026, Intel Corp.
*
*****************************************************************************/
#define _DECLARE_GLOBALS
#include "acpidump.h"
/*
* acpidump - A portable utility for obtaining system ACPI tables and dumping
* them in an ASCII hex format suitable for binary extraction via acpixtract.
*
* Obtaining the system ACPI tables is an OS-specific operation.
*
* This utility can be ported to any host operating system by providing a
* module containing system-specific versions of these interfaces:
*
* acpi_os_get_table_by_address
* acpi_os_get_table_by_index
* acpi_os_get_table_by_name
*
* See the ACPICA Reference Guide for the exact definitions of these
* interfaces. Also, see these ACPICA source code modules for example
* implementations:
*
* source/os_specific/service_layers/oswintbl.c
* source/os_specific/service_layers/oslinuxtbl.c
*/
/* Local prototypes */
static void ap_display_usage(void);
static int ap_do_options(int argc, char **argv);
static int ap_insert_action(char *argument, u32 to_be_done);
/* Table for deferred actions from command line options */
struct ap_dump_action action_table[AP_MAX_ACTIONS];
u32 current_action = 0;
#define AP_UTILITY_NAME "ACPI Binary Table Dump Utility"
#define AP_SUPPORTED_OPTIONS "?a:bc:f:hn:o:r:sv^xz"
/******************************************************************************
*
* FUNCTION: ap_display_usage
*
* DESCRIPTION: Usage message for the acpi_dump utility
*
******************************************************************************/
static void ap_display_usage(void)
{
ACPI_USAGE_HEADER("acpidump [options]");
ACPI_OPTION("-b", "Dump tables to binary files");
ACPI_OPTION("-h -?", "This help message");
ACPI_OPTION("-o <File>", "Redirect output to file");
ACPI_OPTION("-r <Address>", "Dump tables from specified RSDP");
ACPI_OPTION("-s", "Print table summaries only");
ACPI_OPTION("-v", "Display version information");
ACPI_OPTION("-vd", "Display build date and time");
ACPI_OPTION("-z", "Verbose mode");
ACPI_USAGE_TEXT("\nTable Options:\n");
ACPI_OPTION("-a <Address>", "Get table via a physical address");
ACPI_OPTION("-c <on|off>", "Turning on/off customized table dumping");
ACPI_OPTION("-f <BinaryFile>", "Get table via a binary file");
ACPI_OPTION("-n <Signature>", "Get table via a name/signature");
ACPI_OPTION("-x", "Do not use but dump XSDT");
ACPI_OPTION("-x -x", "Do not use or dump XSDT");
ACPI_USAGE_TEXT("\n"
"Invocation without parameters dumps all available tables\n"
"Multiple mixed instances of -a, -f, and -n are supported\n\n");
}
/******************************************************************************
*
* FUNCTION: ap_insert_action
*
* PARAMETERS: argument - Pointer to the argument for this action
* to_be_done - What to do to process this action
*
* RETURN: Status
*
* DESCRIPTION: Add an action item to the action table
*
******************************************************************************/
static int ap_insert_action(char *argument, u32 to_be_done)
{
/* Insert action and check for table overflow */
action_table[current_action].argument = argument;
action_table[current_action].to_be_done = to_be_done;
current_action++;
if (current_action > AP_MAX_ACTIONS) {
fprintf(stderr, "Too many table options (max %d)\n",
AP_MAX_ACTIONS);
return (-1);
}
return (0);
}
/******************************************************************************
*
* FUNCTION: ap_do_options
*
* PARAMETERS: argc/argv - Standard argc/argv
*
* RETURN: Status
*
* DESCRIPTION: Command line option processing. The main actions for getting
* and dumping tables are deferred via the action table.
*
*****************************************************************************/
static int ap_do_options(int argc, char **argv)
{
int j;
acpi_status status;
/* Command line options */
while ((j =
acpi_getopt(argc, argv, AP_SUPPORTED_OPTIONS)) != ACPI_OPT_END)
switch (j) {
/*
* Global options
*/
case 'b': /* Dump all input tables to binary files */
gbl_binary_mode = TRUE;
continue;
case 'c': /* Dump customized tables */
if (!strcmp(acpi_gbl_optarg, "on")) {
gbl_dump_customized_tables = TRUE;
} else if (!strcmp(acpi_gbl_optarg, "off")) {
gbl_dump_customized_tables = FALSE;
} else {
fprintf(stderr,
"%s: Cannot handle this switch, please use on|off\n",
acpi_gbl_optarg);
return (-1);
}
continue;
case 'h':
case '?':
ap_display_usage();
return (1);
case 'o': /* Redirect output to a single file */
if (ap_open_output_file(acpi_gbl_optarg)) {
return (-1);
}
continue;
case 'r': /* Dump tables from specified RSDP */
status =
acpi_ut_strtoul64(acpi_gbl_optarg, &gbl_rsdp_base);
if (ACPI_FAILURE(status)) {
fprintf(stderr,
"%s: Could not convert to a physical address\n",
acpi_gbl_optarg);
return (-1);
}
continue;
case 's': /* Print table summaries only */
gbl_summary_mode = TRUE;
continue;
case 'x': /* Do not use XSDT */
if (!acpi_gbl_do_not_use_xsdt) {
acpi_gbl_do_not_use_xsdt = TRUE;
} else {
gbl_do_not_dump_xsdt = TRUE;
}
continue;
case 'v': /* -v: (Version): signon already emitted, just exit */
switch (acpi_gbl_optarg[0]) {
case '^': /* -v: (Version) */
fprintf(stderr,
ACPI_COMMON_SIGNON(AP_UTILITY_NAME));
return (1);
case 'd':
fprintf(stderr,
ACPI_COMMON_SIGNON(AP_UTILITY_NAME));
printf(ACPI_COMMON_BUILD_TIME);
return (1);
default:
printf("Unknown option: -v%s\n",
acpi_gbl_optarg);
return (-1);
}
break;
case 'z': /* Verbose mode */
gbl_verbose_mode = TRUE;
fprintf(stderr, ACPI_COMMON_SIGNON(AP_UTILITY_NAME));
continue;
/*
* Table options
*/
case 'a': /* Get table by physical address */
if (ap_insert_action
(acpi_gbl_optarg, AP_DUMP_TABLE_BY_ADDRESS)) {
return (-1);
}
break;
case 'f': /* Get table from a file */
if (ap_insert_action
(acpi_gbl_optarg, AP_DUMP_TABLE_BY_FILE)) {
return (-1);
}
break;
case 'n': /* Get table by input name (signature) */
if (ap_insert_action
(acpi_gbl_optarg, AP_DUMP_TABLE_BY_NAME)) {
return (-1);
}
break;
default:
ap_display_usage();
return (-1);
}
/* If there are no actions, this means "get/dump all tables" */
if (current_action == 0) {
if (ap_insert_action(NULL, AP_DUMP_ALL_TABLES)) {
return (-1);
}
}
return (0);
}
/******************************************************************************
*
* FUNCTION: main
*
* PARAMETERS: argc/argv - Standard argc/argv
*
* RETURN: Status
*
* DESCRIPTION: C main function for acpidump utility
*
******************************************************************************/
#if !defined(_GNU_EFI) && !defined(_EDK2_EFI)
int ACPI_SYSTEM_XFACE main(int argc, char *argv[])
#else
int ACPI_SYSTEM_XFACE acpi_main(int argc, char *argv[])
#endif
{
int status = 0;
struct ap_dump_action *action;
u32 file_size;
u32 i;
ACPI_DEBUG_INITIALIZE(); /* For debug version only */
acpi_os_initialize();
gbl_output_file = ACPI_FILE_OUT;
acpi_gbl_integer_byte_width = 8;
/* Process command line options */
status = ap_do_options(argc, argv);
if (status > 0) {
return (0);
}
if (status < 0) {
return (status);
}
/* Get/dump ACPI table(s) as requested */
for (i = 0; i < current_action; i++) {
action = &action_table[i];
switch (action->to_be_done) {
case AP_DUMP_ALL_TABLES:
status = ap_dump_all_tables();
break;
case AP_DUMP_TABLE_BY_ADDRESS:
status = ap_dump_table_by_address(action->argument);
break;
case AP_DUMP_TABLE_BY_NAME:
status = ap_dump_table_by_name(action->argument);
break;
case AP_DUMP_TABLE_BY_FILE:
status = ap_dump_table_from_file(action->argument);
break;
default:
fprintf(stderr,
"Internal error, invalid action: 0x%X\n",
action->to_be_done);
return (-1);
}
if (status) {
return (status);
}
}
if (gbl_output_filename) {
if (gbl_verbose_mode) {
/* Summary for the output file */
file_size = cm_get_file_size(gbl_output_file);
fprintf(stderr,
"Output file %s contains 0x%X (%u) bytes\n\n",
gbl_output_filename, file_size, file_size);
}
fclose(gbl_output_file);
}
return (status);
}
@@ -0,0 +1,14 @@
# SPDX-License-Identifier: GPL-2.0-only
# tools/power/acpi/tools/acpidump/Makefile - ACPI tool Makefile
#
# Copyright (c) 2015, Intel Corporation
# Author: Lv Zheng <lv.zheng@intel.com>
#
include ../../Makefile.config
TOOL = ec
TOOL_OBJS = \
ec_access.o
include ../../Makefile.rules
@@ -0,0 +1,237 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* ec_access.c
*
* Copyright (C) 2010 SUSE Linux Products GmbH
* Author:
* Thomas Renninger <trenn@suse.de>
*/
#include <fcntl.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <libgen.h>
#include <unistd.h>
#include <getopt.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#define EC_SPACE_SIZE 256
#define SYSFS_PATH "/sys/kernel/debug/ec/ec0/io"
/* TBD/Enhancements:
- Provide param for accessing different ECs (not supported by kernel yet)
*/
static int read_mode = -1;
static int sleep_time;
static int write_byte_offset = -1;
static int read_byte_offset = -1;
static uint8_t write_value = -1;
void usage(char progname[], int exit_status)
{
printf("Usage:\n");
printf("1) %s -r [-s sleep]\n", basename(progname));
printf("2) %s -b byte_offset\n", basename(progname));
printf("3) %s -w byte_offset -v value\n\n", basename(progname));
puts("\t-r [-s sleep] : Dump EC registers");
puts("\t If sleep is given, sleep x seconds,");
puts("\t re-read EC registers and show changes");
puts("\t-b offset : Read value at byte_offset (in hex)");
puts("\t-w offset -v value : Write value at byte_offset");
puts("\t-h : Print this help\n\n");
puts("Offsets and values are in hexadecimal number system.");
puts("The offset and value must be between 0 and 0xff.");
exit(exit_status);
}
void parse_opts(int argc, char *argv[])
{
int c;
while ((c = getopt(argc, argv, "rs:b:w:v:h")) != -1) {
switch (c) {
case 'r':
if (read_mode != -1)
usage(argv[0], EXIT_FAILURE);
read_mode = 1;
break;
case 's':
if (read_mode != -1 && read_mode != 1)
usage(argv[0], EXIT_FAILURE);
sleep_time = atoi(optarg);
if (sleep_time <= 0) {
sleep_time = 0;
usage(argv[0], EXIT_FAILURE);
printf("Bad sleep time: %s\n", optarg);
}
break;
case 'b':
if (read_mode != -1)
usage(argv[0], EXIT_FAILURE);
read_mode = 1;
read_byte_offset = strtoul(optarg, NULL, 16);
break;
case 'w':
if (read_mode != -1)
usage(argv[0], EXIT_FAILURE);
read_mode = 0;
write_byte_offset = strtoul(optarg, NULL, 16);
break;
case 'v':
write_value = strtoul(optarg, NULL, 16);
break;
case 'h':
usage(argv[0], EXIT_SUCCESS);
default:
fprintf(stderr, "Unknown option!\n");
usage(argv[0], EXIT_FAILURE);
}
}
if (read_mode == 0) {
if (write_byte_offset < 0 ||
write_byte_offset >= EC_SPACE_SIZE) {
fprintf(stderr, "Wrong byte offset 0x%.2x, valid: "
"[0-0x%.2x]\n",
write_byte_offset, EC_SPACE_SIZE - 1);
usage(argv[0], EXIT_FAILURE);
}
if (write_value < 0 ||
write_value >= 255) {
fprintf(stderr, "Wrong byte offset 0x%.2x, valid:"
"[0-0xff]\n", write_byte_offset);
usage(argv[0], EXIT_FAILURE);
}
}
if (read_mode == 1 && read_byte_offset != -1) {
if (read_byte_offset < -1 ||
read_byte_offset >= EC_SPACE_SIZE) {
fprintf(stderr, "Wrong byte offset 0x%.2x, valid: "
"[0-0x%.2x]\n",
read_byte_offset, EC_SPACE_SIZE - 1);
usage(argv[0], EXIT_FAILURE);
}
}
/* Add additional parameter checks here */
}
void dump_ec(int fd)
{
char buf[EC_SPACE_SIZE];
char buf2[EC_SPACE_SIZE];
int byte_off, bytes_read;
bytes_read = read(fd, buf, EC_SPACE_SIZE);
if (bytes_read == -1)
err(EXIT_FAILURE, "Could not read from %s\n", SYSFS_PATH);
if (bytes_read != EC_SPACE_SIZE)
fprintf(stderr, "Could only read %d bytes\n", bytes_read);
printf(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
for (byte_off = 0; byte_off < bytes_read; byte_off++) {
if ((byte_off % 16) == 0)
printf("\n%.2X: ", byte_off);
printf(" %.2x ", (uint8_t)buf[byte_off]);
}
printf("\n");
if (!sleep_time)
return;
printf("\n");
lseek(fd, 0, SEEK_SET);
sleep(sleep_time);
bytes_read = read(fd, buf2, EC_SPACE_SIZE);
if (bytes_read == -1)
err(EXIT_FAILURE, "Could not read from %s\n", SYSFS_PATH);
if (bytes_read != EC_SPACE_SIZE)
fprintf(stderr, "Could only read %d bytes\n", bytes_read);
printf(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
for (byte_off = 0; byte_off < bytes_read; byte_off++) {
if ((byte_off % 16) == 0)
printf("\n%.2X: ", byte_off);
if (buf[byte_off] == buf2[byte_off])
printf(" %.2x ", (uint8_t)buf2[byte_off]);
else
printf("*%.2x ", (uint8_t)buf2[byte_off]);
}
printf("\n");
}
void read_ec_val(int fd, int byte_offset)
{
uint8_t buf;
int error;
error = lseek(fd, byte_offset, SEEK_SET);
if (error != byte_offset)
err(EXIT_FAILURE, "Cannot set offset to 0x%.2x", byte_offset);
error = read(fd, &buf, 1);
if (error != 1)
err(EXIT_FAILURE, "Could not read byte 0x%.2x from %s\n",
byte_offset, SYSFS_PATH);
printf("0x%.2x\n", buf);
return;
}
void write_ec_val(int fd, int byte_offset, uint8_t value)
{
int error;
error = lseek(fd, byte_offset, SEEK_SET);
if (error != byte_offset)
err(EXIT_FAILURE, "Cannot set offset to 0x%.2x", byte_offset);
error = write(fd, &value, 1);
if (error != 1)
err(EXIT_FAILURE, "Cannot write value 0x%.2x to offset 0x%.2x",
value, byte_offset);
}
int main(int argc, char *argv[])
{
int file_mode = O_RDONLY;
int fd;
parse_opts(argc, argv);
if (read_mode == 0)
file_mode = O_WRONLY;
else if (read_mode == 1)
file_mode = O_RDONLY;
else
usage(argv[0], EXIT_FAILURE);
fd = open(SYSFS_PATH, file_mode);
if (fd == -1)
err(EXIT_FAILURE, "%s", SYSFS_PATH);
if (read_mode)
if (read_byte_offset == -1)
dump_ec(fd);
else if (read_byte_offset < 0 ||
read_byte_offset >= EC_SPACE_SIZE)
usage(argv[0], EXIT_FAILURE);
else
read_ec_val(fd, read_byte_offset);
else
write_ec_val(fd, write_byte_offset, write_value);
close(fd);
exit(EXIT_SUCCESS);
}
@@ -0,0 +1,23 @@
# SPDX-License-Identifier: GPL-2.0+
include ../../Makefile.config
TOOL = pfrut
EXTRA_INSTALL = install-man
EXTRA_UNINSTALL = uninstall-man
CFLAGS += -Wall -O2
CFLAGS += -DPFRUT_HEADER='"../../../../../include/uapi/linux/pfrut.h"'
LDFLAGS += -luuid
TOOL_OBJS = \
pfrut.o
include ../../Makefile.rules
install-man: $(srctree)/man/pfrut.8
$(ECHO) " INST " pfrut.8
$(QUIET) $(INSTALL_DATA) -D $< $(DESTDIR)$(mandir)/man8/pfrut.8
uninstall-man:
$(ECHO) " UNINST " pfrut.8
$(QUIET) rm -f $(DESTDIR)$(mandir)/man8/pfrut.8
@@ -0,0 +1,441 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Platform Firmware Runtime Update tool to do Management
* Mode code injection/driver update and telemetry retrieval.
*
* This tool uses the interfaces provided by pfr_update and
* pfr_telemetry drivers. These interfaces are exposed via
* /dev/pfr_update and /dev/pfr_telemetry. Write operation
* on the /dev/pfr_update is to load the EFI capsule into
* kernel space. Mmap/read operations on /dev/pfr_telemetry
* could be used to read the telemetry data to user space.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <getopt.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <uuid/uuid.h>
#include PFRUT_HEADER
char *capsule_name;
int action, query_cap, log_type, log_level, log_read, log_getinfo,
revid, log_revid;
int set_log_level, set_log_type,
set_revid, set_log_revid;
char *progname;
#define LOG_ERR 0
#define LOG_WARN 1
#define LOG_INFO 2
#define LOG_VERB 4
#define LOG_EXEC_IDX 0
#define LOG_HISTORY_IDX 1
#define REVID_1 1
#define REVID_2 2
static int valid_log_level(int level)
{
return level == LOG_ERR || level == LOG_WARN ||
level == LOG_INFO || level == LOG_VERB;
}
static int valid_log_type(int type)
{
return type == LOG_EXEC_IDX || type == LOG_HISTORY_IDX;
}
static inline int valid_log_revid(int id)
{
return id == REVID_1 || id == REVID_2;
}
static void help(void)
{
fprintf(stderr,
"usage: %s [OPTIONS]\n"
" code injection:\n"
" -l, --load\n"
" -s, --stage\n"
" -a, --activate\n"
" -u, --update [stage and activate]\n"
" -q, --query\n"
" -d, --revid update\n"
" telemetry:\n"
" -G, --getloginfo\n"
" -T, --type(0:execution, 1:history)\n"
" -L, --level(0, 1, 2, 4)\n"
" -R, --read\n"
" -D, --revid log\n",
progname);
}
char *option_string = "l:sauqd:GT:L:RD:h";
static struct option long_options[] = {
{"load", required_argument, 0, 'l'},
{"stage", no_argument, 0, 's'},
{"activate", no_argument, 0, 'a'},
{"update", no_argument, 0, 'u'},
{"query", no_argument, 0, 'q'},
{"getloginfo", no_argument, 0, 'G'},
{"type", required_argument, 0, 'T'},
{"level", required_argument, 0, 'L'},
{"read", no_argument, 0, 'R'},
{"setrev", required_argument, 0, 'd'},
{"setrevlog", required_argument, 0, 'D'},
{"help", no_argument, 0, 'h'},
{}
};
static void parse_options(int argc, char **argv)
{
int option_index = 0;
char *pathname, *endptr;
int opt;
pathname = strdup(argv[0]);
progname = basename(pathname);
while ((opt = getopt_long_only(argc, argv, option_string,
long_options, &option_index)) != -1) {
switch (opt) {
case 'l':
capsule_name = optarg;
break;
case 's':
action = 1;
break;
case 'a':
action = 2;
break;
case 'u':
action = 3;
break;
case 'q':
query_cap = 1;
break;
case 'G':
log_getinfo = 1;
break;
case 'T':
log_type = strtol(optarg, &endptr, 0);
if (*endptr || (log_type != 0 && log_type != 1)) {
printf("Number expected: type(0:execution, 1:history) - Quit.\n");
exit(1);
}
set_log_type = 1;
break;
case 'L':
log_level = strtol(optarg, &endptr, 0);
if (*endptr ||
(log_level != 0 && log_level != 1 &&
log_level != 2 && log_level != 4)) {
printf("Number expected: level(0, 1, 2, 4) - Quit.\n");
exit(1);
}
set_log_level = 1;
break;
case 'R':
log_read = 1;
break;
case 'd':
revid = atoi(optarg);
set_revid = 1;
break;
case 'D':
log_revid = atoi(optarg);
set_log_revid = 1;
break;
case 'h':
help();
exit(0);
default:
break;
}
}
}
void print_cap(struct pfru_update_cap_info *cap)
{
char *uuid;
uuid = malloc(37);
if (!uuid) {
perror("Can not allocate uuid buffer\n");
exit(1);
}
printf("update capability:%d\n", cap->update_cap);
uuid_unparse(cap->code_type, uuid);
printf("code injection image type:%s\n", uuid);
printf("fw_version:%d\n", cap->fw_version);
printf("code_rt_version:%d\n", cap->code_rt_version);
uuid_unparse(cap->drv_type, uuid);
printf("driver update image type:%s\n", uuid);
printf("drv_rt_version:%d\n", cap->drv_rt_version);
printf("drv_svn:%d\n", cap->drv_svn);
uuid_unparse(cap->platform_id, uuid);
printf("platform id:%s\n", uuid);
uuid_unparse(cap->oem_id, uuid);
printf("oem id:%s\n", uuid);
printf("oem information length:%d\n", cap->oem_info_len);
free(uuid);
}
int main(int argc, char *argv[])
{
int fd_update, fd_update_log, fd_capsule;
struct pfrt_log_data_info data_info;
struct pfrt_log_info info;
struct pfru_update_cap_info cap;
void *addr_map_capsule;
struct stat st;
char *log_buf;
int ret;
if (getuid() != 0) {
printf("Please run the tool as root - Exiting.\n");
return 1;
}
parse_options(argc, argv);
fd_update = open("/dev/acpi_pfr_update0", O_RDWR);
if (fd_update < 0) {
printf("PFRU device not supported - Quit...\n");
return 1;
}
fd_update_log = open("/dev/acpi_pfr_telemetry0", O_RDWR);
if (fd_update_log < 0) {
printf("PFRT device not supported - Quit...\n");
close(fd_update);
return 1;
}
if (query_cap) {
ret = ioctl(fd_update, PFRU_IOC_QUERY_CAP, &cap);
if (ret)
perror("Query Update Capability info failed.");
else
print_cap(&cap);
close(fd_update);
close(fd_update_log);
return ret;
}
if (log_getinfo) {
ret = ioctl(fd_update_log, PFRT_LOG_IOC_GET_DATA_INFO, &data_info);
if (ret) {
perror("Get telemetry data info failed.");
close(fd_update);
close(fd_update_log);
return 1;
}
ret = ioctl(fd_update_log, PFRT_LOG_IOC_GET_INFO, &info);
if (ret) {
perror("Get telemetry info failed.");
close(fd_update);
close(fd_update_log);
return 1;
}
printf("log_level:%d\n", info.log_level);
printf("log_type:%d\n", info.log_type);
printf("log_revid:%d\n", info.log_revid);
printf("max_data_size:%d\n", data_info.max_data_size);
printf("chunk1_size:%d\n", data_info.chunk1_size);
printf("chunk2_size:%d\n", data_info.chunk2_size);
printf("rollover_cnt:%d\n", data_info.rollover_cnt);
printf("reset_cnt:%d\n", data_info.reset_cnt);
close(fd_update);
close(fd_update_log);
return 0;
}
info.log_level = -1;
info.log_type = -1;
info.log_revid = -1;
if (set_log_level) {
if (!valid_log_level(log_level)) {
printf("Invalid log level %d\n",
log_level);
} else {
info.log_level = log_level;
}
}
if (set_log_type) {
if (!valid_log_type(log_type)) {
printf("Invalid log type %d\n",
log_type);
} else {
info.log_type = log_type;
}
}
if (set_log_revid) {
if (!valid_log_revid(log_revid)) {
printf("Invalid log revid %d, unchanged.\n",
log_revid);
} else {
info.log_revid = log_revid;
}
}
ret = ioctl(fd_update_log, PFRT_LOG_IOC_SET_INFO, &info);
if (ret) {
perror("Log information set failed.(log_level, log_type, log_revid)");
close(fd_update);
close(fd_update_log);
return 1;
}
if (set_revid) {
ret = ioctl(fd_update, PFRU_IOC_SET_REV, &revid);
if (ret) {
perror("pfru update revid set failed");
close(fd_update);
close(fd_update_log);
return 1;
}
printf("pfru update revid set to %d\n", revid);
}
if (capsule_name) {
fd_capsule = open(capsule_name, O_RDONLY);
if (fd_capsule < 0) {
perror("Can not open capsule file...");
close(fd_update);
close(fd_update_log);
return 1;
}
if (fstat(fd_capsule, &st) < 0) {
perror("Can not fstat capsule file...");
close(fd_capsule);
close(fd_update);
close(fd_update_log);
return 1;
}
addr_map_capsule = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED,
fd_capsule, 0);
if (addr_map_capsule == MAP_FAILED) {
perror("Failed to mmap capsule file.");
close(fd_capsule);
close(fd_update);
close(fd_update_log);
return 1;
}
ret = write(fd_update, (char *)addr_map_capsule, st.st_size);
printf("Load %d bytes of capsule file into the system\n",
ret);
if (ret == -1) {
perror("Failed to load capsule file");
munmap(addr_map_capsule, st.st_size);
close(fd_capsule);
close(fd_update);
close(fd_update_log);
return 1;
}
munmap(addr_map_capsule, st.st_size);
close(fd_capsule);
printf("Load done.\n");
}
if (action) {
if (action == 1) {
ret = ioctl(fd_update, PFRU_IOC_STAGE, NULL);
} else if (action == 2) {
ret = ioctl(fd_update, PFRU_IOC_ACTIVATE, NULL);
} else if (action == 3) {
ret = ioctl(fd_update, PFRU_IOC_STAGE_ACTIVATE, NULL);
} else {
close(fd_update);
close(fd_update_log);
return 1;
}
printf("Update finished, return %d\n", ret);
}
close(fd_update);
if (log_read) {
void *p_mmap;
int max_data_sz;
ret = ioctl(fd_update_log, PFRT_LOG_IOC_GET_DATA_INFO, &data_info);
if (ret) {
perror("Get telemetry data info failed.");
close(fd_update_log);
return 1;
}
max_data_sz = data_info.max_data_size;
if (!max_data_sz) {
printf("No telemetry data available.\n");
close(fd_update_log);
return 1;
}
log_buf = malloc(max_data_sz + 1);
if (!log_buf) {
perror("log_buf allocate failed.");
close(fd_update_log);
return 1;
}
p_mmap = mmap(NULL, max_data_sz, PROT_READ, MAP_SHARED, fd_update_log, 0);
if (p_mmap == MAP_FAILED) {
perror("mmap error.");
close(fd_update_log);
free(log_buf);
return 1;
}
memcpy(log_buf, p_mmap, max_data_sz);
log_buf[max_data_sz] = '\0';
printf("%s\n", log_buf);
free(log_buf);
munmap(p_mmap, max_data_sz);
}
close(fd_update_log);
return 0;
}