From f3b37e5da3b2f1199f588e8d0d885813aa450e40 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Mon, 13 Nov 2017 09:08:39 -0600 Subject: [PATCH] fs/procfs/fs_procfsprogrem: Add /proc/progmem. This is an alternative way to get the information that was previoulsy available in apps/system/free. apps/system/free was removed beause it made illegal calls into the OS violating the portable interface. This new procfs entry provides the same information with no such violation. --- arch/Kconfig | 4 + arch/arm/Kconfig | 10 +- arch/arm/src/efm32/Kconfig | 1 + arch/arm/src/samv7/Kconfig | 2 + drivers/mtd/mtd_progmem.c | 7 +- fs/procfs/Kconfig | 13 +- fs/procfs/Make.defs | 4 + fs/procfs/fs_procfs.c | 5 + fs/procfs/fs_procfsprogmem.c | 393 +++++++++++++++++++++++++++++++++++ include/nuttx/progmem.h | 3 + 10 files changed, 431 insertions(+), 11 deletions(-) create mode 100644 fs/procfs/fs_procfsprogmem.c diff --git a/arch/Kconfig b/arch/Kconfig index a621f6f163..1efa5d52c2 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -194,6 +194,10 @@ config ARCH_HAVE_POWEROFF bool default n +config ARCH_HAVE_PROGMEM + bool + default n + config ARCH_HAVE_RESET bool default n diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index f87e9148d6..c9fcbb127a 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -244,9 +244,10 @@ config ARCH_CHIP_STM32 select ARCH_HAVE_MPU select ARCH_HAVE_I2CRESET select ARCH_HAVE_HEAPCHECK + select ARCH_HAVE_PROGMEM + select ARCH_HAVE_SPI_BITORDER select ARCH_HAVE_TICKLESS select ARCH_HAVE_TIMEKEEPING - select ARCH_HAVE_SPI_BITORDER select ARM_HAVE_MPU_UNIFIED select ARMV7M_HAVE_STACKCHECK ---help--- @@ -275,13 +276,14 @@ config ARCH_CHIP_STM32F7 config ARCH_CHIP_STM32L4 bool "STMicro STM32 L4" - select ARCH_HAVE_CMNVECTOR select ARCH_CORTEXM4 - select ARCH_HAVE_MPU + select ARCH_HAVE_CMNVECTOR select ARCH_HAVE_I2CRESET select ARCH_HAVE_HEAPCHECK - select ARCH_HAVE_TICKLESS + select ARCH_HAVE_MPU + select ARCH_HAVE_PROGMEM select ARCH_HAVE_SPI_BITORDER + select ARCH_HAVE_TICKLESS select ARM_HAVE_MPU_UNIFIED select ARMV7M_CMNVECTOR select ARMV7M_HAVE_STACKCHECK diff --git a/arch/arm/src/efm32/Kconfig b/arch/arm/src/efm32/Kconfig index 877cca1074..8cfba344fc 100644 --- a/arch/arm/src/efm32/Kconfig +++ b/arch/arm/src/efm32/Kconfig @@ -135,6 +135,7 @@ config EFM32_RMU config EFM32_FLASHPROG bool "Enable Erase/Write flash function (MSC) " default n + select ARCH_HAVE_PROGMEM select ARCH_HAVE_RAMFUNCS config EFM32_RMU_DEBUG diff --git a/arch/arm/src/samv7/Kconfig b/arch/arm/src/samv7/Kconfig index 5350bc4315..c63dbe3b1d 100644 --- a/arch/arm/src/samv7/Kconfig +++ b/arch/arm/src/samv7/Kconfig @@ -753,6 +753,8 @@ endif # SAMV7_WDT || SAMV7_RSWDT menuconfig SAMV7_PROGMEM bool "FLASH program memory" + default n + select ARCH_HAVE_PROGMEM ---help--- Enable support FLASH interfaces as defined in include/nuttx/progmem.h diff --git a/drivers/mtd/mtd_progmem.c b/drivers/mtd/mtd_progmem.c index 9785a4c360..d46bed5ac5 100644 --- a/drivers/mtd/mtd_progmem.c +++ b/drivers/mtd/mtd_progmem.c @@ -49,9 +49,7 @@ #include #include -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ +#ifdef CONFIG_ARCH_HAVE_PROGMEM /**************************************************************************** * Private Types @@ -102,6 +100,7 @@ static int progmem_ioctl(FAR struct mtd_dev_s *dev, int cmd, /**************************************************************************** * Private Data ****************************************************************************/ + /* This structure holds the state of the MTD driver */ static struct progmem_dev_s g_progmem = @@ -411,3 +410,5 @@ FAR struct mtd_dev_s *progmem_initialize(void) return (FAR struct mtd_dev_s *)priv; } + +#endif /* CONFIG_ARCH_HAVE_PROGMEM */ diff --git a/fs/procfs/Kconfig b/fs/procfs/Kconfig index 4e55b51f58..d5595c9f97 100644 --- a/fs/procfs/Kconfig +++ b/fs/procfs/Kconfig @@ -90,10 +90,10 @@ config FS_PROCFS_EXCLUDE_NET depends on NET default n -config FS_PROCFS_EXCLUDE_ROUTE - bool "Exclude routing table" - depends on !FS_PROCFS_EXCLUDE_NET && NET_ROUTE - default n +config FS_PROCFS_EXCLUDE_PROGMEM + bool "Exclude progmem" + depends on ARCH_HAVE_PROGMEM + default y config FS_PROCFS_EXCLUDE_MTD bool "Exclude mtd" @@ -105,6 +105,11 @@ config FS_PROCFS_EXCLUDE_PARTITIONS depends on MTD_PARTITION default n +config FS_PROCFS_EXCLUDE_ROUTE + bool "Exclude routing table" + depends on !FS_PROCFS_EXCLUDE_NET && NET_ROUTE + default n + config FS_PROCFS_EXCLUDE_SMARTFS bool "Exclude fs/smartfs" depends on FS_SMARTFS diff --git a/fs/procfs/Make.defs b/fs/procfs/Make.defs index 434e85799e..31dbf7b818 100644 --- a/fs/procfs/Make.defs +++ b/fs/procfs/Make.defs @@ -40,6 +40,10 @@ ASRCS += CSRCS += fs_procfs.c fs_procfsutil.c fs_procfsproc.c fs_procfsuptime.c CSRCS += fs_procfscpuload.c fs_procfskmm.c +ifeq ($(CONFIG_ARCH_HAVE_PROGMEM),y) +CSRCS += fs_procfsprogmem.c +endif + # Include procfs build support DEPPATH += --dep-path procfs diff --git a/fs/procfs/fs_procfs.c b/fs/procfs/fs_procfs.c index 07aaec449b..3c1d4809e4 100644 --- a/fs/procfs/fs_procfs.c +++ b/fs/procfs/fs_procfs.c @@ -79,6 +79,7 @@ extern const struct procfs_operations proc_operations; extern const struct procfs_operations cpuload_operations; extern const struct procfs_operations kmm_operations; +extern const struct procfs_operations progmem_operations; extern const struct procfs_operations module_operations; extern const struct procfs_operations uptime_operations; @@ -165,6 +166,10 @@ static const struct procfs_entry_s g_procfs_entries[] = { "partitions", &part_procfsoperations, PROCFS_FILE_TYPE }, #endif +#if defined(CONFIG_ARCH_HAVE_PROGMEM) && !defined(CONFIG_FS_PROCFS_EXCLUDE_PROGMEM) + { "progmem", &progmem_operations, PROCFS_FILE_TYPE }, +#endif + #if !defined(CONFIG_FS_PROCFS_EXCLUDE_UPTIME) { "uptime", &uptime_operations, PROCFS_FILE_TYPE }, #endif diff --git a/fs/procfs/fs_procfsprogmem.c b/fs/procfs/fs_procfsprogmem.c new file mode 100644 index 0000000000..600af860d8 --- /dev/null +++ b/fs/procfs/fs_procfsprogmem.c @@ -0,0 +1,393 @@ +/**************************************************************************** + * fs/procfs/fs_procfsprogmem.c + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#if defined(CONFIG_ARCH_HAVE_PROGMEM) && !defined(CONFIG_FS_PROCFS_EXCLUDE_PROGMEM) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Determines the size of an intermediate buffer that must be large enough + * to handle the longest line generated by this logic. + */ + +#define PROGMEM_LINELEN 54 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure describes one open "file" */ + +struct progmem_file_s +{ + struct procfs_file_s base; /* Base open file structure */ + unsigned int linesize; /* Number of valid characters in line[] */ + char line[PROGMEM_LINELEN]; /* Pre-allocated buffer for formatted lines */ +}; + +struct progmem_info_s +{ + int arena; /* Total size of available progmem. */ + int ordblks; /* This is the number of free chunks */ + int mxordblk; /* Size of the largest free chunk */ + int uordblks; /* Total size of memory for allocated chunks */ + int fordblks; /* Total size of memory for free chunks.*/ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void progmem_getinfo(FAR struct progmem_info_s *progmem); + +/* File system methods */ + +static int progmem_open(FAR struct file *filep, FAR const char *relpath, + int oflags, mode_t mode); +static int progmem_close(FAR struct file *filep); +static ssize_t progmem_read(FAR struct file *filep, FAR char *buffer, + size_t buflen); +static int progmem_dup(FAR const struct file *oldp, + FAR struct file *newp); +static int progmem_stat(FAR const char *relpath, FAR struct stat *buf); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* See fs_mount.c -- this structure is explicitly externed there. + * We use the old-fashioned kind of initializers so that this will compile + * with any compiler. + */ + +const struct procfs_operations progmem_operations = +{ + progmem_open, /* open */ + progmem_close, /* close */ + progmem_read, /* read */ + NULL, /* write */ + progmem_dup, /* dup */ + NULL, /* opendir */ + NULL, /* closedir */ + NULL, /* readdir */ + NULL, /* rewinddir */ + progmem_stat /* stat */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: progmem_getinfo + * + * Description: + * The moral equivalent of mallinfo() for prog mem + * + * TODO Max block size only works on uniform prog mem + * + ****************************************************************************/ + +static void progmem_getinfo(FAR struct progmem_info_s *progmem) +{ + size_t page = 0; + size_t stpage = 0xffff; + size_t pagesize = 0; + ssize_t status; + + progmem->arena = 0; + progmem->fordblks = 0; + progmem->uordblks = 0; + progmem->mxordblk = 0; + + for (status = 0, page = 0; status >= 0; page++) + { + status = up_progmem_ispageerased(page); + pagesize = up_progmem_pagesize(page); + + progmem->arena += pagesize; + + /* Is this beginning of new free space section */ + + if (status == 0) + { + if (stpage == 0xffff) + { + stpage = page; + } + + progmem->fordblks += pagesize; + } + else if (status != 0) + { + progmem->uordblks += pagesize; + + if (stpage != 0xffff && up_progmem_isuniform()) + { + stpage = page - stpage; + if (stpage > progmem->mxordblk) + { + progmem->mxordblk = stpage; + } + + stpage = 0xffff; + } + } + } + + progmem->mxordblk *= pagesize; +} + +/**************************************************************************** + * Name: progmem_open + ****************************************************************************/ + +static int progmem_open(FAR struct file *filep, FAR const char *relpath, + int oflags, mode_t mode) +{ + FAR struct progmem_file_s *procfile; + + finfo("Open '%s'\n", relpath); + + /* PROCFS is read-only. Any attempt to open with any kind of write + * access is not permitted. + * + * REVISIT: Write-able proc files could be quite useful. + */ + + if ((oflags & O_WRONLY) != 0 || (oflags & O_RDONLY) == 0) + { + ferr("ERROR: Only O_RDONLY supported\n"); + return -EACCES; + } + + /* "progmem" is the only acceptable value for the relpath */ + + if (strcmp(relpath, "progmem") != 0) + { + ferr("ERROR: relpath is '%s'\n", relpath); + return -ENOENT; + } + + /* Allocate a container to hold the file attributes */ + + procfile = (FAR struct progmem_file_s *) + kmm_zalloc(sizeof(struct progmem_file_s)); + if (procfile == NULL) + { + ferr("ERROR: Failed to allocate file attributes\n"); + return -ENOMEM; + } + + /* Save the attributes as the open-specific state in filep->f_priv */ + + filep->f_priv = (FAR void *)procfile; + return OK; +} + +/**************************************************************************** + * Name: progmem_close + ****************************************************************************/ + +static int progmem_close(FAR struct file *filep) +{ + FAR struct progmem_file_s *procfile; + + /* Recover our private data from the struct file instance */ + + procfile = (FAR struct progmem_file_s *)filep->f_priv; + DEBUGASSERT(procfile); + + /* Release the file attributes structure */ + + kmm_free(procfile); + filep->f_priv = NULL; + return OK; +} + +/**************************************************************************** + * Name: progmem_read + ****************************************************************************/ + +static ssize_t progmem_read(FAR struct file *filep, FAR char *buffer, + size_t buflen) +{ + FAR struct progmem_file_s *procfile; + struct progmem_info_s progmem; + size_t linesize; + size_t copysize; + size_t totalsize; + off_t offset; + + finfo("buffer=%p buflen=%d\n", buffer, (int)buflen); + + DEBUGASSERT(filep != NULL && buffer != NULL && buflen > 0); + offset = filep->f_pos; + + /* Recover our private data from the struct file instance */ + + procfile = (FAR struct progmem_file_s *)filep->f_priv; + DEBUGASSERT(procfile); + + /* The first line is the headers */ + + linesize = snprintf(procfile->line, PROGMEM_LINELEN, + " total used free largest\n"); + copysize = procfs_memcpy(procfile->line, linesize, buffer, buflen, + &offset); + totalsize = copysize; + + if (totalsize < buflen) + { + buffer += copysize; + buflen -= copysize; + + /* The second line is the memory data */ + + progmem_getinfo(&progmem); + + linesize = snprintf(procfile->line, PROGMEM_LINELEN, + "Prog: %11d%11d%11d%11d\n", + progmem.arena, progmem.uordblks, progmem.fordblks, + progmem.mxordblk); + copysize = procfs_memcpy(procfile->line, linesize, buffer, buflen, + &offset); + totalsize += copysize; + } + + /* Update the file offset */ + + filep->f_pos += totalsize; + return totalsize; +} + +/**************************************************************************** + * Name: progmem_dup + * + * Description: + * Duplicate open file data in the new file structure. + * + ****************************************************************************/ + +static int progmem_dup(FAR const struct file *oldp, FAR struct file *newp) +{ + FAR struct progmem_file_s *oldattr; + FAR struct progmem_file_s *newattr; + + finfo("Dup %p->%p\n", oldp, newp); + + /* Recover our private data from the old struct file instance */ + + oldattr = (FAR struct progmem_file_s *)oldp->f_priv; + DEBUGASSERT(oldattr); + + /* Allocate a new container to hold the task and attribute selection */ + + newattr = (FAR struct progmem_file_s *) + kmm_malloc(sizeof(struct progmem_file_s)); + if (!newattr) + { + ferr("ERROR: Failed to allocate file attributes\n"); + return -ENOMEM; + } + + /* The copy the file attributes from the old attributes to the new */ + + memcpy(newattr, oldattr, sizeof(struct progmem_file_s)); + + /* Save the new attributes in the new file structure */ + + newp->f_priv = (FAR void *)newattr; + return OK; +} + +/**************************************************************************** + * Name: progmem_stat + * + * Description: Return information about a file or directory + * + ****************************************************************************/ + +static int progmem_stat(FAR const char *relpath, FAR struct stat *buf) +{ + /* "progmem" is the only acceptable value for the relpath */ + + if (strcmp(relpath, "progmem") != 0) + { + ferr("ERROR: relpath is '%s'\n", relpath); + return -ENOENT; + } + + /* "progmem" is the name for a read-only file */ + + memset(buf, 0, sizeof(struct stat)); + buf->st_mode = S_IFREG | S_IROTH | S_IRGRP | S_IRUSR; + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#endif /* CONFIG_ARCH_HAVE_PROGMEM && !CONFIG_FS_PROCFS_EXCLUDE_PROGMEM */ diff --git a/include/nuttx/progmem.h b/include/nuttx/progmem.h index a5ed707a61..367f66af8c 100644 --- a/include/nuttx/progmem.h +++ b/include/nuttx/progmem.h @@ -45,6 +45,8 @@ #include +#ifdef CONFIG_ARCH_HAVE_PROGMEM + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -207,4 +209,5 @@ ssize_t up_progmem_write(size_t addr, FAR const void *buf, size_t count); } #endif +#endif /* CONFIG_ARCH_HAVE_PROGMEM */ #endif /* __INCLUDE_NUTTX_PROGMEM_H */