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

View File

@@ -41,6 +41,7 @@
__start:
/* Preserve a1 as it contains the pointer to DTB */
/* Load mhartid (cpuid) */
csrr a0, mhartid

View File

@@ -36,6 +36,10 @@
# include "qemu_rv_mm_init.h"
#endif
#ifdef CONFIG_DEVICE_TREE
# include <nuttx/fdt.h>
#endif
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
@@ -97,9 +101,9 @@ uintptr_t g_idle_topstack = QEMU_RV_IDLESTACK_TOP;
****************************************************************************/
#ifdef CONFIG_BUILD_KERNEL
void qemu_rv_start_s(int mhartid)
void qemu_rv_start_s(int mhartid, const char *dtb)
#else
void qemu_rv_start(int mhartid)
void qemu_rv_start(int mhartid, const char *dtb)
#endif
{
/* Configure FPU */
@@ -115,6 +119,10 @@ void qemu_rv_start(int mhartid)
qemu_rv_clear_bss();
#endif
#ifdef CONFIG_DEVICE_TREE
fdt_register(dtb);
#endif
showprogress('A');
#ifdef USE_EARLYSERIALINIT
@@ -155,7 +163,7 @@ cpux:
* Name: qemu_rv_start
****************************************************************************/
void qemu_rv_start(int mhartid)
void qemu_rv_start(int mhartid, const char *dtb)
{
/* NOTE: still in M-mode */
@@ -209,12 +217,13 @@ void qemu_rv_start(int mhartid)
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 (
"mv a0, %0 \n"
"mv a1, %1 \n"
"mret \n"
:: "r" (mhartid)
:: "r" (mhartid), "r" (dtb)
);
}
#endif

View File

@@ -31,6 +31,7 @@ CONFIG_BOARD_LOOPSPERMSEC=6366
CONFIG_BUILTIN=y
CONFIG_DEBUG_FULLOPT=y
CONFIG_DEBUG_SYMBOLS=y
CONFIG_DEVICE_TREE=y
CONFIG_DEV_ZERO=y
CONFIG_ELF=y
CONFIG_EXAMPLES_HELLO=m

View File

@@ -54,3 +54,4 @@ source "drivers/math/Kconfig"
source "drivers/segger/Kconfig"
source "drivers/usrsock/Kconfig"
source "drivers/dma/Kconfig"
source "drivers/devicetree/Kconfig"

View File

@@ -32,6 +32,7 @@ include bch/Make.defs
include can/Make.defs
include clk/Make.defs
include crypto/Make.defs
include devicetree/Make.defs
include dma/Make.defs
include math/Make.defs
include motor/Make.defs

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()

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.

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
drivers/devicetree/fdt.c Normal file
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;
}

View File

@@ -56,6 +56,14 @@ config FS_PROCFS_EXCLUDE_ENVIRON
Causes the environment variable information to be excluded from the
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
bool "Exclude iobinfo"
depends on MM_IOB

View File

@@ -22,9 +22,9 @@ ifeq ($(CONFIG_FS_PROCFS),y)
# Files required for procfs file system support
CSRCS += fs_procfs.c fs_procfscpuinfo.c fs_procfscpuload.c
CSRCS += fs_procfscritmon.c fs_procfsiobinfo.c fs_procfsmeminfo.c
CSRCS += fs_procfsproc.c fs_procfstcbinfo.c fs_procfsuptime.c
CSRCS += fs_procfsutil.c fs_procfsversion.c
CSRCS += fs_procfscritmon.c fs_procfsfdt.c fs_procfsiobinfo.c
CSRCS += fs_procfsmeminfo.c fs_procfsproc.c fs_procfstcbinfo.c
CSRCS += fs_procfsuptime.c fs_procfsutil.c fs_procfsversion.c
# Include procfs build support

View File

@@ -55,6 +55,7 @@
extern const struct procfs_operations g_cpuinfo_operations;
extern const struct procfs_operations g_cpuload_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_irq_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 },
#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
{ "fs/blocks", &g_mount_operations, PROCFS_FILE_TYPE },
#endif

258
fs/procfs/fs_procfsfdt.c Normal file
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
include/nuttx/fdt.h Normal file
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 */