This is an automated email from the ASF dual-hosted git repository. ligd pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit c774939c9e15bbb9115f336e98c628ee93e51acf Author: liwenxiang1 <[email protected]> AuthorDate: Fri Feb 7 10:53:01 2025 +0800 arch/x64: add acpi procfs add acpi procfs function Signed-off-by: liwenxiang1 <[email protected]> arch/x64:Fix the issue of dereferencing before null check Signed-off-by: liwenxiang1 <[email protected]> --- arch/x86_64/include/acpi.h | 24 ++ arch/x86_64/src/common/CMakeLists.txt | 1 + arch/x86_64/src/common/Make.defs | 1 + arch/x86_64/src/common/x86_64_acpi.c | 94 +++++++ arch/x86_64/src/common/x86_64_acpi_procfs.c | 373 ++++++++++++++++++++++++++++ arch/x86_64/src/common/x86_64_initialize.c | 4 + 6 files changed, 497 insertions(+) diff --git a/arch/x86_64/include/acpi.h b/arch/x86_64/include/acpi.h index ab2355f2b99..ac5a6e930eb 100644 --- a/arch/x86_64/include/acpi.h +++ b/arch/x86_64/include/acpi.h @@ -30,6 +30,7 @@ #include <nuttx/config.h> #include <nuttx/compiler.h> +#include <sys/types.h> /**************************************************************************** * Pre-processor Definitions @@ -297,6 +298,29 @@ int acpi_lapic_get(int cpu, struct acpi_lapic_s **lapic); void acpi_dump(void); #endif +/**************************************************************************** + * Name: acpi_table_get + * + * Description: + * Cache acpi tables as a copy. + * + ****************************************************************************/ + +ssize_t acpi_table_get(const char *name, void **data); + +/**************************************************************************** + * Name: acpi_procfs_register + * + * Description: + * Register the acpi_procfs procfs file system entry + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure + * + ****************************************************************************/ + +int acpi_procfs_register(void); + #undef EXTERN #if defined(__cplusplus) } diff --git a/arch/x86_64/src/common/CMakeLists.txt b/arch/x86_64/src/common/CMakeLists.txt index b512c212dcc..b71072fbefa 100644 --- a/arch/x86_64/src/common/CMakeLists.txt +++ b/arch/x86_64/src/common/CMakeLists.txt @@ -48,6 +48,7 @@ endif() if(CONFIG_ARCH_X86_64_ACPI) list(APPEND SRCS x86_64_acpi.c) + list(APPEND SRCS x86_64_acpi_procfs.c) endif() if(CONFIG_SCHED_THREAD_LOCAL) diff --git a/arch/x86_64/src/common/Make.defs b/arch/x86_64/src/common/Make.defs index b5e81443423..a5a21aff0a6 100644 --- a/arch/x86_64/src/common/Make.defs +++ b/arch/x86_64/src/common/Make.defs @@ -44,6 +44,7 @@ endif ifeq ($(CONFIG_ARCH_X86_64_ACPI),y) CMN_CSRCS += x86_64_acpi.c +CMN_CSRCS += x86_64_acpi_procfs.c endif ifeq ($(CONFIG_SCHED_THREAD_LOCAL),y) diff --git a/arch/x86_64/src/common/x86_64_acpi.c b/arch/x86_64/src/common/x86_64_acpi.c index 0685ea5c932..ac30c097d2b 100644 --- a/arch/x86_64/src/common/x86_64_acpi.c +++ b/arch/x86_64/src/common/x86_64_acpi.c @@ -31,6 +31,7 @@ #include <stdint.h> #include <arch/acpi.h> +#include <nuttx/kmalloc.h> #include "x86_64_internal.h" @@ -60,6 +61,7 @@ struct acpi_s struct acpi_xsdt_s *xsdt; struct acpi_madt_s *madt; struct acpi_mcfg_s *mcfg; + struct acpi_facp_s *facp; }; /**************************************************************************** @@ -477,9 +479,101 @@ int acpi_init(uintptr_t rsdp) acpi_table_find(ACPI_SIG_MCFG, (struct acpi_sdt_s **)&acpi->mcfg); + /* Get FACP */ + + acpi_table_find(ACPI_SIG_FACP, (struct acpi_sdt_s **)&acpi->facp); + return OK; } +/**************************************************************************** + * Name: acpi_table_get + * + * Description: + * Cache acpi tables as a copy. + * + ****************************************************************************/ + +ssize_t acpi_table_get(const char *name, void **data) +{ + struct acpi_sdt_s *dsdt = NULL; + struct acpi_s *acpi = &g_acpi; + ssize_t len = 0; + + /* Copy APIC */ + + if (strncmp(name, ACPI_SIG_APIC, 4) == 0) + { + if (data != NULL && acpi->madt) + { + *data = kmm_zalloc(acpi->madt->sdt.length); + if (!*data) + { + ferr("ERROR: Failed to allocate apic table\n"); + return -ENOMEM; + } + + len = acpi->madt->sdt.length; + memcpy(*data, acpi->madt, len); + } + } + else if (strncmp(name, ACPI_SIG_MCFG, 4) == 0) + { + if (data != NULL && acpi->mcfg) + { + *data = kmm_zalloc(acpi->mcfg->sdt.length); + if (!*data) + { + ferr("ERROR: Failed to allocate mcfs table\n"); + return -ENOMEM; + } + + len = acpi->mcfg->sdt.length; + memcpy(*data, acpi->mcfg, len); + } + } + else if (strncmp(name, ACPI_SIG_FACP, 4) == 0) + { + if (data != NULL && acpi->facp) + { + *data = kmm_zalloc(acpi->facp->sdt.length); + if (!*data) + { + ferr("ERROR: Failed to allocate facp table\n"); + return -ENOMEM; + } + + len = acpi->facp->sdt.length; + memcpy(*data, acpi->facp, len); + } + } + else if (strncmp(name, ACPI_SIG_DSDT, 4) == 0) + { + dsdt = (struct acpi_sdt_s *)(uintptr_t)acpi->facp->dsdt; + if (data != NULL && dsdt) + { + acpi_map_region((uintptr_t)dsdt, sizeof(struct acpi_sdt_s)); + acpi_map_region((uintptr_t)dsdt + sizeof(struct acpi_sdt_s), + dsdt->length - sizeof(struct acpi_sdt_s)); + *data = kmm_zalloc(dsdt->length); + if (!*data) + { + ferr("ERROR: Failed to allocate dsdt table\n"); + return -ENOMEM; + } + + len = dsdt->length; + memcpy(*data, dsdt, len); + } + } + else + { + return -ENOENT; + } + + return len; +} + /**************************************************************************** * Name: acpi_madt_get * diff --git a/arch/x86_64/src/common/x86_64_acpi_procfs.c b/arch/x86_64/src/common/x86_64_acpi_procfs.c new file mode 100644 index 00000000000..0fab8503adb --- /dev/null +++ b/arch/x86_64/src/common/x86_64_acpi_procfs.c @@ -0,0 +1,373 @@ +/**************************************************************************** + * arch/x86_64/src/common/x86_64_acpi_procfs.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <sys/stat.h> +#include <stdio.h> +#include <fcntl.h> +#include <string.h> +#include <assert.h> +#include <debug.h> +#include <errno.h> + +#include <sys/param.h> + +#include <nuttx/nuttx.h> +#include <nuttx/fs/fs.h> +#include <nuttx/fs/procfs.h> +#include <nuttx/kmalloc.h> +#include <arch/acpi.h> + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure describes one open "file" */ + +struct acpi_file_s +{ + struct procfs_file_s base; /* Base open file structure */ + void *data; /* data pointer */ + size_t length; /* data len */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* File system methods */ + +static int acpi_open(struct file *filep, const char *relpath, + int oflags, mode_t mode); +static int acpi_close(struct file *filep); + +static ssize_t acpi_read(struct file *filep, char *buffer, + size_t buflen); + +static int acpi_opendir(const char *relpath, + struct fs_dirent_s **dir); +static int acpi_closedir(struct fs_dirent_s *dir); +static int acpi_readdir(struct fs_dirent_s *dir, + struct dirent *entry); + +static int acpi_stat(const char *relpath, struct stat *buf); + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* See fs_mount.c -- this structure is explicitly extern'ed there. + * We use the old-fashioned kind of initializers so that this will compile + * with any compiler. + */ + +const struct procfs_operations g_acpi_operations = +{ + acpi_open, /* open */ + acpi_close, /* close */ + acpi_read, /* read */ + NULL, /* write */ + NULL, /* poll */ + NULL, /* dup */ + + acpi_opendir, /* opendir */ + acpi_closedir, /* closedir */ + acpi_readdir, /* readdir */ + NULL, /* rewinddir */ + + acpi_stat /* stat */ +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const char *g_acpi_files[] = +{ + "FACP", + "DSDT", + "APIC", + "MCFG", +}; + +#if defined(CONFIG_FS_PROCFS_REGISTER) +static const struct procfs_entry_s g_acpi_procfs = +{ + "acpi", + &g_acpi_operations, + PROCFS_DIR_TYPE, + 0444 +}; + +static const struct procfs_entry_s g_acpi_file_procfs = +{ + "acpi/**", + &g_acpi_operations, + PROCFS_FILE_TYPE, + 0 +}; +#endif + +/**************************************************************************** + * Name: acpi_open + ****************************************************************************/ + +static int acpi_open(struct file *filep, const char *relpath, + int oflags, mode_t mode) +{ + struct acpi_file_s *acpifile; + ssize_t len; + + finfo("Open '%s'\n", relpath); + + /* This PROCFS file is read-only. Any attempt to open with write access + * is not permitted. + */ + + if ((oflags & O_WRONLY) != 0 || (oflags & O_RDONLY) == 0) + { + ferr("ERROR: Only O_RDONLY supported\n"); + return -EACCES; + } + + relpath += strlen("acpi/"); + + /* Allocate a container to hold the file attributes */ + + acpifile = kmm_zalloc(sizeof(struct acpi_file_s)); + if (!acpifile) + { + ferr("ERROR: Failed to allocate file attributes\n"); + return -ENOMEM; + } + + len = acpi_table_get(relpath, &acpifile->data); + acpifile->length = len; + filep->f_pos = 0; + + /* Save the attributes as the open-specific state in filep->f_priv */ + + filep->f_priv = acpifile; + + return OK; +} + +/**************************************************************************** + * Name: acpi_close + ****************************************************************************/ + +static int acpi_close(struct file *filep) +{ + struct acpi_file_s *acpifile; + + /* Recover our private data from the struct file instance */ + + acpifile = (struct acpi_file_s *)filep->f_priv; + + DEBUGASSERT(acpifile); + + /* Release the file attributes structure */ + + kmm_free(acpifile->data); + kmm_free(acpifile); + + filep->f_priv = NULL; + return OK; +} + +/**************************************************************************** + * Name: acpi_read + ****************************************************************************/ + +static ssize_t acpi_read(struct file *filep, char *buffer, + size_t buflen) +{ + struct acpi_file_s *acpifile; + + acpifile = (struct acpi_file_s *)filep->f_priv; + + if (filep->f_pos > acpifile->length) + { + buflen = 0; + } + else if (filep->f_pos + buflen > acpifile->length) + { + buflen = acpifile->length - filep->f_pos; + } + + memcpy(buffer, acpifile->data + filep->f_pos, buflen); + filep->f_pos += buflen; + + return buflen; +} + +/**************************************************************************** + * Name: acpi_opendir + * + * Description: + * Open a directory for read access + * + ****************************************************************************/ + +static int acpi_opendir(const char *relpath, + struct fs_dirent_s **dir) +{ + struct procfs_dir_priv_s *level1; + + finfo("relpath: \"%s\"\n", relpath ? relpath : "NULL"); + DEBUGASSERT(relpath); + + /* Assume that path refers to the 1st level subdirectory. Allocate the + * level1 the dirent structure before checking. + */ + + level1 = kmm_zalloc(sizeof(struct procfs_dir_priv_s)); + if (level1 == NULL) + { + ferr("ERROR: Failed to allocate the level1 directory structure\n"); + return -ENOMEM; + } + + /* Initialize base structure components */ + + level1->level = 1; + level1->nentries = nitems(g_acpi_files); + + *dir = (struct fs_dirent_s *)level1; + return OK; +} + +/**************************************************************************** + * Name: acpi_closedir + * + * Description: Close the directory listing + * + ****************************************************************************/ + +static int acpi_closedir(struct fs_dirent_s *dir) +{ + DEBUGASSERT(dir); + kmm_free(dir); + return OK; +} + +/**************************************************************************** + * Name: acpi_readdir + * + * Description: Read the next directory entry + * + ****************************************************************************/ + +static int acpi_readdir(struct fs_dirent_s *dir, + struct dirent *entry) +{ + struct procfs_dir_priv_s *level1; + int index; + int fpos; + + DEBUGASSERT(dir); + + level1 = (struct procfs_dir_priv_s *)dir; + + index = level1->index; + if (index >= level1->nentries) + { + /* We signal the end of the directory by returning the special + * error -ENOENT + */ + + finfo("Entry %d: End of directory\n", index); + return -ENOENT; + } + + fpos = index % nitems(g_acpi_files); + + entry->d_type = DTYPE_FILE; + snprintf(entry->d_name, NAME_MAX + 1, "%s", + g_acpi_files[fpos]); + + level1->index++; + return OK; +} + +/**************************************************************************** + * Name: acpi_stat + * + * Description: Return information about a file or directory + * + ****************************************************************************/ + +static int acpi_stat(const char *relpath, struct stat *buf) +{ + memset(buf, 0, sizeof(struct stat)); + + if (strcmp(relpath, "acpi") == 0 || strcmp(relpath, "acpi/") == 0) + { + buf->st_mode = S_IFDIR | S_IROTH | S_IRGRP | S_IRUSR; + } + else + { + int ret = acpi_table_get(relpath + sizeof("acpi"), NULL); + if (ret < 0) + { + return ret; + } + + buf->st_mode = S_IFREG | S_IROTH | S_IRGRP | S_IRUSR; + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: acpi_procfs_register + * + * Description: + * Register the acpi_procfs procfs file system entry + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure + * + ****************************************************************************/ +#if defined(CONFIG_FS_PROCFS_REGISTER) +int acpi_procfs_register(void) +{ + int ret; + + ret = procfs_register(&g_acpi_procfs); + if (ret >= 0) + { + ret = procfs_register(&g_acpi_file_procfs); + } + + DEBUGASSERT(ret >= 0); + return ret; +} +#endif + diff --git a/arch/x86_64/src/common/x86_64_initialize.c b/arch/x86_64/src/common/x86_64_initialize.c index 06520dcb129..55d0d0a313d 100644 --- a/arch/x86_64/src/common/x86_64_initialize.c +++ b/arch/x86_64/src/common/x86_64_initialize.c @@ -173,5 +173,9 @@ void up_initialize(void) acpi_dump(); #endif +#if defined(CONFIG_ARCH_X86_64_ACPI) && defined(CONFIG_FS_PROCFS_REGISTER) + acpi_procfs_register(); +#endif + board_autoled_on(LED_IRQSENABLED); }
