fdt: Add initial FDT support and procfs for userspace export

VELAPLATFO-12536

This provides the initial hooks for Flattened Device Tree support
with QEMU RV. It also provides a new procfs file that exposes the
fdt to userspace much like the /sys/firmware/fdt endpoint in Linux.
See https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-firmware-ofw

Nodes in the fdt are not yet usable by the OS.

Signed-off-by: Brennan Ashton <bashton@brennanashton.com>
Signed-off-by: liaoao <liaoao@xiaomi.com>
This commit is contained in:
Brennan Ashton
2023-05-07 00:13:31 -07:00
committed by Xiang Xiao
parent dfdb3aa2f4
commit 46b0f6d6ee
14 changed files with 528 additions and 8 deletions
+1
View File
@@ -41,6 +41,7 @@
__start: __start:
/* Preserve a1 as it contains the pointer to DTB */
/* Load mhartid (cpuid) */ /* Load mhartid (cpuid) */
csrr a0, mhartid csrr a0, mhartid
+14 -5
View File
@@ -36,6 +36,10 @@
# include "qemu_rv_mm_init.h" # include "qemu_rv_mm_init.h"
#endif #endif
#ifdef CONFIG_DEVICE_TREE
# include <nuttx/fdt.h>
#endif
/**************************************************************************** /****************************************************************************
* Pre-processor Definitions * Pre-processor Definitions
****************************************************************************/ ****************************************************************************/
@@ -97,9 +101,9 @@ uintptr_t g_idle_topstack = QEMU_RV_IDLESTACK_TOP;
****************************************************************************/ ****************************************************************************/
#ifdef CONFIG_BUILD_KERNEL #ifdef CONFIG_BUILD_KERNEL
void qemu_rv_start_s(int mhartid) void qemu_rv_start_s(int mhartid, const char *dtb)
#else #else
void qemu_rv_start(int mhartid) void qemu_rv_start(int mhartid, const char *dtb)
#endif #endif
{ {
/* Configure FPU */ /* Configure FPU */
@@ -115,6 +119,10 @@ void qemu_rv_start(int mhartid)
qemu_rv_clear_bss(); qemu_rv_clear_bss();
#endif #endif
#ifdef CONFIG_DEVICE_TREE
fdt_register(dtb);
#endif
showprogress('A'); showprogress('A');
#ifdef USE_EARLYSERIALINIT #ifdef USE_EARLYSERIALINIT
@@ -155,7 +163,7 @@ cpux:
* Name: qemu_rv_start * Name: qemu_rv_start
****************************************************************************/ ****************************************************************************/
void qemu_rv_start(int mhartid) void qemu_rv_start(int mhartid, const char *dtb)
{ {
/* NOTE: still in M-mode */ /* NOTE: still in M-mode */
@@ -209,12 +217,13 @@ void qemu_rv_start(int mhartid)
WRITE_CSR(mepc, (uintptr_t)qemu_rv_start_s); WRITE_CSR(mepc, (uintptr_t)qemu_rv_start_s);
/* Set a0 to mhartid explicitly and enter to S-mode */ /* Set a0 to mhartid and a1 to dtb explicitly and enter to S-mode */
asm volatile ( asm volatile (
"mv a0, %0 \n" "mv a0, %0 \n"
"mv a1, %1 \n"
"mret \n" "mret \n"
:: "r" (mhartid) :: "r" (mhartid), "r" (dtb)
); );
} }
#endif #endif
@@ -31,6 +31,7 @@ CONFIG_BOARD_LOOPSPERMSEC=6366
CONFIG_BUILTIN=y CONFIG_BUILTIN=y
CONFIG_DEBUG_FULLOPT=y CONFIG_DEBUG_FULLOPT=y
CONFIG_DEBUG_SYMBOLS=y CONFIG_DEBUG_SYMBOLS=y
CONFIG_DEVICE_TREE=y
CONFIG_DEV_ZERO=y CONFIG_DEV_ZERO=y
CONFIG_ELF=y CONFIG_ELF=y
CONFIG_EXAMPLES_HELLO=m CONFIG_EXAMPLES_HELLO=m
+1
View File
@@ -54,3 +54,4 @@ source "drivers/math/Kconfig"
source "drivers/segger/Kconfig" source "drivers/segger/Kconfig"
source "drivers/usrsock/Kconfig" source "drivers/usrsock/Kconfig"
source "drivers/dma/Kconfig" source "drivers/dma/Kconfig"
source "drivers/devicetree/Kconfig"
+1
View File
@@ -32,6 +32,7 @@ include bch/Make.defs
include can/Make.defs include can/Make.defs
include clk/Make.defs include clk/Make.defs
include crypto/Make.defs include crypto/Make.defs
include devicetree/Make.defs
include dma/Make.defs include dma/Make.defs
include math/Make.defs include math/Make.defs
include motor/Make.defs include motor/Make.defs
+24
View File
@@ -0,0 +1,24 @@
# ##############################################################################
# drivers/devicetree/CMakeLists.txt
#
# 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.
#
# ##############################################################################
if(CONFIG_DEVICE_TREE)
set(SRCS fdt.c)
target_sources(drivers PRIVATE ${SRCS})
endif()
+10
View File
@@ -0,0 +1,10 @@
#
# For a description of the syntax of this configuration file,
# see the file kconfig-language.txt in the NuttX tools repository.
#
menuconfig DEVICE_TREE
bool "Device Tree Support"
default n
---help---
Interface for interacting with devicetree.
+28
View File
@@ -0,0 +1,28 @@
############################################################################
# drivers/devicetree/Make.defs
#
# 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.
#
############################################################################
ifeq ($(CONFIG_DEVICE_TREE),y)
CSRCS += fdt.c
DEPPATH += --dep-path devicetree
VPATH += :devicetree
endif
+86
View File
@@ -0,0 +1,86 @@
/****************************************************************************
* drivers/devicetree/fdt.c
*
* 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 <stddef.h>
#include <endian.h>
#include <errno.h>
#include <assert.h>
#include <nuttx/compiler.h>
#include <nuttx/fdt.h>
/****************************************************************************
* Private Data
****************************************************************************/
/* Location of the fdt data for this system. */
static FAR const char *g_fdt_base = NULL;
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: fdt_register
*
* Description:
* Store the pointer to the flattened device tree and verify that it at
* least appears to be valid. This function will not fully parse the FDT.
*
* Return:
* Return -EINVAL if the fdt header does not have the expected magic value.
* otherwise return OK. If OK is not returned the existing entry for FDT
* is not modified.
*
****************************************************************************/
int fdt_register(FAR const char *fdt_base)
{
struct fdt_header_s *fdt_header;
DEBUGASSERT(fdt_base);
fdt_header = (struct fdt_header_s *)fdt_base;
if (fdt_header->magic != be32toh(FDT_MAGIC))
{
return -EINVAL; /* Bad magic byte read */
}
g_fdt_base = fdt_base;
return OK;
}
/****************************************************************************
* Name: fdt_get
*
* Description:
* Return the pointer to a raw FDT. NULL is returned if no FDT has been
* loaded.
*
****************************************************************************/
FAR const char *fdt_get(void)
{
return g_fdt_base;
}
+8
View File
@@ -56,6 +56,14 @@ config FS_PROCFS_EXCLUDE_ENVIRON
Causes the environment variable information to be excluded from the Causes the environment variable information to be excluded from the
procfs system. This will reduce code space slightly. procfs system. This will reduce code space slightly.
config FS_PROCFS_EXCLUDE_FDT
bool "Exclude flattened device tree blob"
depends on DEVICE_TREE
default DEFAULT_SMALL
---help---
Causes the flatted device tree information to be excluded from the
procfs system. This will reduce code space slightly.
config FS_PROCFS_EXCLUDE_IOBINFO config FS_PROCFS_EXCLUDE_IOBINFO
bool "Exclude iobinfo" bool "Exclude iobinfo"
depends on MM_IOB depends on MM_IOB
+3 -3
View File
@@ -22,9 +22,9 @@ ifeq ($(CONFIG_FS_PROCFS),y)
# Files required for procfs file system support # Files required for procfs file system support
CSRCS += fs_procfs.c fs_procfscpuinfo.c fs_procfscpuload.c CSRCS += fs_procfs.c fs_procfscpuinfo.c fs_procfscpuload.c
CSRCS += fs_procfscritmon.c fs_procfsiobinfo.c fs_procfsmeminfo.c CSRCS += fs_procfscritmon.c fs_procfsfdt.c fs_procfsiobinfo.c
CSRCS += fs_procfsproc.c fs_procfstcbinfo.c fs_procfsuptime.c CSRCS += fs_procfsmeminfo.c fs_procfsproc.c fs_procfstcbinfo.c
CSRCS += fs_procfsutil.c fs_procfsversion.c CSRCS += fs_procfsuptime.c fs_procfsutil.c fs_procfsversion.c
# Include procfs build support # Include procfs build support
+5
View File
@@ -55,6 +55,7 @@
extern const struct procfs_operations g_cpuinfo_operations; extern const struct procfs_operations g_cpuinfo_operations;
extern const struct procfs_operations g_cpuload_operations; extern const struct procfs_operations g_cpuload_operations;
extern const struct procfs_operations g_critmon_operations; extern const struct procfs_operations g_critmon_operations;
extern const struct procfs_operations g_fdt_operations;
extern const struct procfs_operations g_iobinfo_operations; extern const struct procfs_operations g_iobinfo_operations;
extern const struct procfs_operations g_irq_operations; extern const struct procfs_operations g_irq_operations;
extern const struct procfs_operations g_meminfo_operations; extern const struct procfs_operations g_meminfo_operations;
@@ -108,6 +109,10 @@ static const struct procfs_entry_s g_procfs_entries[] =
{ "critmon", &g_critmon_operations, PROCFS_FILE_TYPE }, { "critmon", &g_critmon_operations, PROCFS_FILE_TYPE },
#endif #endif
#if defined(CONFIG_DEVICE_TREE) && !defined(CONFIG_FS_PROCFS_EXCLUDE_FDT)
{ "fdt", &g_fdt_operations, PROCFS_FILE_TYPE },
#endif
#ifndef CONFIG_FS_PROCFS_EXCLUDE_BLOCKS #ifndef CONFIG_FS_PROCFS_EXCLUDE_BLOCKS
{ "fs/blocks", &g_mount_operations, PROCFS_FILE_TYPE }, { "fs/blocks", &g_mount_operations, PROCFS_FILE_TYPE },
#endif #endif
+258
View File
@@ -0,0 +1,258 @@
/****************************************************************************
* fs/procfs/fs_procfsfdt.c
*
* 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 <nuttx/config.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <endian.h>
#include <nuttx/kmalloc.h>
#include <nuttx/fdt.h>
#include <nuttx/fs/fs.h>
#include <nuttx/fs/procfs.h>
#if defined(CONFIG_DEVICE_TREE) && !defined(CONFIG_FS_PROCFS_EXCLUDE_FDT)
/****************************************************************************
* Private Types
****************************************************************************/
/* This structure describes one open "file" */
struct fdt_file_s
{
struct procfs_file_s base; /* Base open file structure */
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* File system methods */
static int fdt_open(FAR struct file *filep, FAR const char *relpath,
int oflags, mode_t mode);
static int fdt_close(FAR struct file *filep);
static ssize_t fdt_read(FAR struct file *filep, FAR char *buffer,
size_t buflen);
static int fdt_dup(FAR const struct file *oldp,
FAR struct file *newp);
static int fdt_stat(FAR const char *relpath, FAR struct stat *buf);
/****************************************************************************
* 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 g_fdt_operations =
{
fdt_open, /* open */
fdt_close, /* close */
fdt_read, /* read */
NULL, /* write */
fdt_dup, /* dup */
NULL, /* opendir */
NULL, /* closedir */
NULL, /* readdir */
NULL, /* rewinddir */
fdt_stat /* stat */
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: fdt_open
****************************************************************************/
static int fdt_open(FAR struct file *filep, FAR const char *relpath,
int oflags, mode_t mode)
{
FAR struct fdt_file_s *attr;
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;
}
/* Allocate a container to hold the file attributes */
attr = kmm_zalloc(sizeof(struct fdt_file_s));
if (attr == 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 = attr;
return OK;
}
/****************************************************************************
* Name: fdt_close
****************************************************************************/
static int fdt_close(FAR struct file *filep)
{
FAR struct fdt_file_s *attr;
/* Recover our private data from the struct file instance */
attr = filep->f_priv;
DEBUGASSERT(attr);
/* Release the file attributes structure */
kmm_free(attr);
filep->f_priv = NULL;
return OK;
}
/****************************************************************************
* Name: fdt_read
****************************************************************************/
static ssize_t fdt_read(FAR struct file *filep, FAR char *buffer,
size_t buflen)
{
FAR const char *fdt;
FAR struct fdt_header_s *fdt_header;
off_t offset;
ssize_t ret;
finfo("buffer=%p buflen=%zu\n", buffer, buflen);
DEBUGASSERT(filep != NULL && buffer != NULL && buflen > 0);
/* Load FDT and parse extents. */
fdt = fdt_get();
if (fdt == NULL)
{
ferr("FDT cannot be read.\n");
return -ENOENT;
}
/* Transfer the fdt to user receive buffer */
fdt_header = (struct fdt_header_s *)fdt;
offset = filep->f_pos;
ret = procfs_memcpy(fdt, be32toh(fdt_header->totalsize),
buffer, buflen, &offset);
/* Update the file offset */
if (ret > 0)
{
filep->f_pos += ret;
}
return ret;
}
/****************************************************************************
* Name: fdt_dup
*
* Description:
* Duplicate open file data in the new file structure.
*
****************************************************************************/
static int fdt_dup(FAR const struct file *oldp, FAR struct file *newp)
{
FAR struct fdt_file_s *oldattr;
FAR struct fdt_file_s *newattr;
finfo("Dup %p->%p\n", oldp, newp);
/* Recover our private data from the old struct file instance */
oldattr = oldp->f_priv;
DEBUGASSERT(oldattr);
/* Allocate a new container to hold the task and attribute selection */
newattr = kmm_malloc(sizeof(struct fdt_file_s));
if (newattr == NULL)
{
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 fdt_file_s));
/* Save the new attributes in the new file structure */
newp->f_priv = newattr;
return OK;
}
/****************************************************************************
* Name: fdt_stat
*
* Description: Return information about a file or directory
*
****************************************************************************/
static int fdt_stat(FAR const char *relpath, FAR struct stat *buf)
{
/* "fdt" 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_DEVICE_TREE && CONFIG_FS_PROCFS_EXCLUDE_FDT */
+88
View File
@@ -0,0 +1,88 @@
/****************************************************************************
* include/nuttx/fdt.h
*
* 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.
*
****************************************************************************/
#ifndef __INCLUDE_NUTTX_FDT_H
#define __INCLUDE_NUTTX_FDT_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <nuttx/compiler.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define FDT_MAGIC 0xd00dfeed
/****************************************************************************
* Public Types
****************************************************************************/
struct fdt_header_s
{
uint32_t magic;
uint32_t totalsize;
uint32_t off_dt_struct;
uint32_t off_dt_strings;
uint32_t off_mem_rsvmap;
uint32_t version;
uint32_t last_comp_version;
uint32_t boot_cpuid_phys;
uint32_t size_dt_strings;
uint32_t size_dt_struct;
};
/****************************************************************************
* Public Functions Definitions
****************************************************************************/
/****************************************************************************
* Name: fdt_register
*
* Description:
* Store the pointer to the flattened device tree and verify that it at
* least appears to be valid. This function will not fully parse the FDT.
*
* Return:
* Return -EINVAL if the fdt header does not have the expected magic value.
* otherwise return OK. If OK is not returned the existing entry for FDT
* is not modified.
*
****************************************************************************/
int fdt_register(FAR const char *fdt_base);
/****************************************************************************
* Name: fdt_get
*
* Description:
* Return the pointer to a raw FDT. NULL is returned if no FDT has been
* loaded.
*
****************************************************************************/
FAR const char *fdt_get(void);
#endif /* __INCLUDE_NUTTX_FDT_H */