You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2021/12/23 02:48:18 UTC

[incubator-nuttx] 02/02: mpfs: introduce OpenSBI

This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit b128ce334fa52532227f2e8d35fcfe64007369c8
Author: Eero Nurkkala <ee...@offcode.fi>
AuthorDate: Mon Dec 20 14:20:47 2021 +0200

    mpfs: introduce OpenSBI
    
    OpenSBI may be compiled as an external library. OpenSBI commit d249d65
    (Dec. 11, 2021) needs to be reverted as it causes memcpy / memcmp to
    end up in the wrong section. That issue has yet no known workaround.
    
    OpenSBI may be lauched from the hart0 (e51). It will start the U-Boot
    and eventually the Linux kernel on harts 1-4.
    
    OpenSBI, once initialized properly, will trap and handle illegal
    instructions (for example, CSR time) and unaligned address accesses
    among other things.
    
    Due to size size limitations for the mpfs eNVM area where the NuttX
    is located, we actually set up the OpenSBI on its own section which
    is in the bottom of the DDR memory. Special care must be taken so that
    the kernel doesn't override the OpenSBI. For example, the Linux device
    tree may reserve some space from the beginning:
    
      opensbi_reserved: opensbi@80000000 {
          reg = <0x80000000 0x200000>;
          label = "opensbi-reserved";
      };
    
    The resulting nuttx.bin file is very large, but objcopy is used to
    create the final binary images for the regions (eNVM and DDR) using
    the nuttx elf file.
    
    Co-authored-by: Petro Karashchenko <pe...@gmail.com>
    Signed-off-by: Eero Nurkkala <ee...@offcode.fi>
---
 LICENSE                                            |  32 +-
 arch/risc-v/Kconfig                                |   2 +
 arch/risc-v/src/Makefile                           |  15 +
 arch/risc-v/src/mpfs/Kconfig                       |   7 +
 arch/risc-v/src/mpfs/Make.defs                     |   5 +
 arch/risc-v/src/mpfs/mpfs_head.S                   |   4 +
 arch/risc-v/src/mpfs/mpfs_opensbi.c                | 525 +++++++++++++++++++++
 arch/risc-v/src/mpfs/mpfs_opensbi_utils.S          | 276 +++++++++++
 arch/risc-v/src/opensbi/.gitignore                 |   3 +
 arch/risc-v/src/opensbi/Kconfig                    |  12 +
 arch/risc-v/src/opensbi/Make.defs                  |  89 ++++
 .../risc-v/mpfs/icicle/configs/opensbi/defconfig   | 118 +++++
 boards/risc-v/mpfs/icicle/scripts/Make.defs        |   6 +-
 .../mpfs/icicle/scripts/ld-envm-opensbi.script     | 123 +++++
 14 files changed, 1215 insertions(+), 2 deletions(-)

diff --git a/LICENSE b/LICENSE
index a2a035c..d25a1a6 100644
--- a/LICENSE
+++ b/LICENSE
@@ -2499,4 +2499,34 @@ arch/arm/src/nrf52/sdk-nrfxlib
    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.
\ No newline at end of file
+   OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+arch/risc-v/src/mpfs/mpfs_opensbi_utils.S
+=========================================
+OpenSBI is based on the 2-Clause BSD License:
+
+The 2-Clause BSD License
+SPDX short identifier: BSD-2-Clause
+
+Copyright (c) 2019 Western Digital Corporation or its affiliates and other
+contributors.
+
+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.
+
+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 HOLDER 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.
diff --git a/arch/risc-v/Kconfig b/arch/risc-v/Kconfig
index 834f51d..cb279f1 100644
--- a/arch/risc-v/Kconfig
+++ b/arch/risc-v/Kconfig
@@ -148,6 +148,8 @@ config ARCH_RISCV_INTXCPT_EXTREGS
 
 endif
 
+source "arch/risc-v/src/opensbi/Kconfig"
+
 if ARCH_RV32IM
 source "arch/risc-v/src/rv32im/Kconfig"
 endif
diff --git a/arch/risc-v/src/Makefile b/arch/risc-v/src/Makefile
index cbff2cf..72d8727 100644
--- a/arch/risc-v/src/Makefile
+++ b/arch/risc-v/src/Makefile
@@ -20,6 +20,9 @@
 
 include $(TOPDIR)/Make.defs
 include chip/Make.defs
+ifeq ($(CONFIG_OPENSBI),y)
+include opensbi/Make.defs
+endif
 
 ifeq ($(CONFIG_ARCH_RV32I),y)           # Base Integer support
 ARCH_SUBDIR = rv32i
@@ -37,6 +40,9 @@ INCLUDES += ${shell $(INCDIR) "$(CC)" $(ARCH_SRCDIR)$(DELIM)chip}
 INCLUDES += ${shell $(INCDIR) "$(CC)" $(ARCH_SRCDIR)$(DELIM)common}
 INCLUDES += ${shell $(INCDIR) "$(CC)" $(ARCH_SRCDIR)$(DELIM)$(ARCH_SUBDIR)}
 INCLUDES += ${shell $(INCDIR) "$(CC)" $(TOPDIR)$(DELIM)sched}
+#ifeq ($(CONFIG_OPENSBI),y)
+INCLUDES += $(shell $(INCDIR) "$(CC)" $(ARCH_SRCDIR)$(DELIM)opensbi$(DELIM)opensbi-3rdparty$(DELIM)include)
+#endif
 
 CPPFLAGS += $(INCLUDES)
 CFLAGS += $(INCLUDES)
@@ -63,9 +69,15 @@ STARTUP_OBJS ?= $(HEAD_OBJ)
 # Flat build or kernel-mode objects
 
 ASRCS = $(CHIP_ASRCS) $(CMN_ASRCS)
+ifeq ($(CONFIG_OPENSBI),y)
+ASRCS += $(OPENSBI_ASRCS)
+endif
 AOBJS = $(ASRCS:.S=$(OBJEXT))
 
 CSRCS = $(CHIP_CSRCS) $(CMN_CSRCS)
+ifeq ($(CONFIG_OPENSBI),y)
+CSRCS += $(OPENSBI_CSRCS)
+endif
 COBJS = $(CSRCS:.c=$(OBJEXT))
 
 SRCS = $(ASRCS) $(CSRCS)
@@ -113,6 +125,9 @@ endif
 
 VPATH += chip
 VPATH += common
+ifeq ($(CONFIG_OPENSBI),y)
+VPATH += opensbi
+endif
 VPATH += $(ARCH_SUBDIR)
 VPATH += $(CHIP_DIR)
 
diff --git a/arch/risc-v/src/mpfs/Kconfig b/arch/risc-v/src/mpfs/Kconfig
index 7e069d3..ba75749 100755
--- a/arch/risc-v/src/mpfs/Kconfig
+++ b/arch/risc-v/src/mpfs/Kconfig
@@ -19,6 +19,13 @@ config MPFS_BOOTLOADER
 	---help---
 		This NuttX image is used as a bootloader, which will boot only on one hart, putting the others in WFI
 
+config MPFS_OPENSBI
+        bool "Use OpenSBI"
+        depends on MPFS_BOOTLOADER && OPENSBI
+        default n
+        ---help---
+                This uses a ld-envm-opensbi.script linker script and the mpfs_opensbi.c code to use external OpenSBI.
+
 config MPFS_BOOT_HART
 	int "HART used for booting"
 	depends on MPFS_BOOTLOADER
diff --git a/arch/risc-v/src/mpfs/Make.defs b/arch/risc-v/src/mpfs/Make.defs
index 309ece6..07f29aa 100755
--- a/arch/risc-v/src/mpfs/Make.defs
+++ b/arch/risc-v/src/mpfs/Make.defs
@@ -89,3 +89,8 @@ endif
 ifeq (${CONFIG_MPFS_BOOTLOADER},y)
 CHIP_CSRCS += mpfs_cache.c
 endif
+
+ifeq (${CONFIG_MPFS_OPENSBI},y)
+CHIP_ASRCS += mpfs_opensbi_utils.S
+CHIP_CSRCS += mpfs_opensbi.c
+endif
diff --git a/arch/risc-v/src/mpfs/mpfs_head.S b/arch/risc-v/src/mpfs/mpfs_head.S
index 5995066..ce774cf 100755
--- a/arch/risc-v/src/mpfs/mpfs_head.S
+++ b/arch/risc-v/src/mpfs/mpfs_head.S
@@ -163,9 +163,13 @@ __start_mpfs:
   csrw mie, zero
   csrw mip, zero
 
+#ifdef CONFIG_MPFS_OPENSBI
+  jal mpfs_opensbi_prepare_hart
+#else
   /* Jump to app (TODO: remove fixed address) */
   li a1, 0x80000000
   jr a1
+#endif
 
 .continue_boot:
 
diff --git a/arch/risc-v/src/mpfs/mpfs_opensbi.c b/arch/risc-v/src/mpfs/mpfs_opensbi.c
new file mode 100644
index 0000000..ba874f4
--- /dev/null
+++ b/arch/risc-v/src/mpfs/mpfs_opensbi.c
@@ -0,0 +1,525 @@
+/****************************************************************************
+ * arch/risc-v/src/mpfs/mpfs_opensbi.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 <assert.h>
+#include <errno.h>
+#include <stdint.h>
+#include <riscv_internal.h>
+#include <riscv_arch.h>
+
+#include <hardware/mpfs_plic.h>
+#include <hardware/mpfs_memorymap.h>
+#include <hardware/mpfs_clint.h>
+#include <hardware/mpfs_sysreg.h>
+
+/* OpenSBI will also define NULL. Undefine NULL in order to avoid warning:
+ * 'warning: "NULL" redefined'
+ */
+
+#ifdef NULL
+  #undef NULL
+#endif
+
+#include <sbi/sbi_types.h>
+#include <sbi/riscv_atomic.h>
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_io.h>
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_hart.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_platform.h>
+#include <sbi/sbi_domain.h>
+#include <sbi/sbi_timer.h>
+#include <sbi/sbi_init.h>
+#include <sbi/sbi_scratch.h>
+#include <sbi_utils/irqchip/plic.h>
+#include <sbi_utils/ipi/aclint_mswi.h>
+#include <sbi_utils/timer/aclint_mtimer.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define MPFS_SYS_CLK               1000000000
+#define MPFS_MAX_NUM_HARTS         5
+#define MPFS_HART_COUNT            5
+
+#define MPFS_ACLINT_MSWI_ADDR      MPFS_CLINT_MSIP0
+#define MPFS_ACLINT_MTIMER_ADDR    MPFS_CLINT_MTIMECMP0
+
+#define MPFS_PMP_DEFAULT_ADDR      0xfffffffff
+#define MPFS_PMP_DEFAULT_PERM      0x000000009f
+
+#define UBOOT_LOAD_ADDR            0x80200000  /* We expect u-boot here */
+
+/* The following define is not accessible with assember.  Make sure it's in
+ * sync with the assembler usage in mpfs_opensbi_utils.S.
+ */
+
+#if SBI_PLATFORM_DEFAULT_HART_STACK_SIZE != 8192
+#  error "Fix define in file mpfs_opensbi_utils.S"
+#endif
+
+#define MPFS_SYSREG_SOFT_RESET_CR     (MPFS_SYSREG_BASE + \
+                                       MPFS_SYSREG_SOFT_RESET_CR_OFFSET)
+#define MPFS_SYSREG_SUBBLK_CLOCK_CR   (MPFS_SYSREG_BASE + \
+                                       MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct sbi_scratch_holder_s
+{
+  union
+    {
+      struct sbi_scratch scratch;
+      unsigned long buffer[SBI_SCRATCH_SIZE / sizeof(uintptr_t)];
+    };
+};
+
+typedef struct sbi_scratch_holder_s sbi_scratch_holder_t;
+
+/* Linker provided region start / end addresses */
+
+extern const uint64_t __mpfs_nuttx_start;
+extern const uint64_t __mpfs_nuttx_end;
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void mpfs_console_putc(char ch);
+static int  mpfs_early_init(bool cold_boot);
+static int  mpfs_opensbi_console_init(void);
+static int  mpfs_irqchip_init(bool cold_boot);
+static int  mpfs_ipi_init(bool cold_boot);
+static int  mpfs_timer_init(bool cold_boot);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static bool mpfs_console_ready    = false;
+
+static struct plic_data mpfs_plic =
+{
+  .addr           = MPFS_PLIC_BASE,
+  .num_src        = MPFS_HART_COUNT,
+};
+
+static struct sbi_console_device mpfs_console =
+{
+  .name           = "mpfs_uart",
+  .console_putc   = mpfs_console_putc,
+  .console_getc   = NULL,
+};
+
+static struct aclint_mtimer_data mpfs_mtimer =
+{
+  .mtime_freq     = MPFS_SYS_CLK,
+  .mtime_addr     = MPFS_ACLINT_MTIMER_ADDR + ACLINT_DEFAULT_MTIME_OFFSET,
+  .mtime_size     = ACLINT_DEFAULT_MTIME_SIZE,
+  .mtimecmp_addr  = MPFS_ACLINT_MTIMER_ADDR + ACLINT_DEFAULT_MTIMECMP_OFFSET,
+  .mtimecmp_size  = ACLINT_DEFAULT_MTIMECMP_SIZE,
+  .first_hartid   = 0,
+  .hart_count     = MPFS_HART_COUNT,
+  .has_64bit_mmio = TRUE,
+};
+
+static const struct sbi_platform_operations platform_ops =
+{
+  .console_init   = mpfs_opensbi_console_init,
+  .early_init     = mpfs_early_init,
+  .irqchip_init   = mpfs_irqchip_init,
+  .irqchip_exit   = NULL,
+  .ipi_init       = mpfs_ipi_init,
+  .ipi_exit       = NULL,
+  .timer_init     = mpfs_timer_init,
+  .timer_exit     = NULL,
+};
+
+static struct aclint_mswi_data mpfs_mswi =
+{
+  .addr           = MPFS_ACLINT_MSWI_ADDR,
+  .size           = ACLINT_MSWI_SIZE,
+  .first_hartid   = 0,
+  .hart_count     = MPFS_HART_COUNT,
+};
+
+const struct sbi_platform platform =
+{
+  .opensbi_version   = OPENSBI_VERSION,
+  .platform_version  = SBI_PLATFORM_VERSION(0x0, 0x01),
+  .name              = "Microchip PolarFire(R) SoC",
+  .features          = SBI_PLATFORM_DEFAULT_FEATURES,
+  .hart_count        = MPFS_HART_COUNT,
+  .hart_stack_size   = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
+  .platform_ops_addr = (unsigned long)&platform_ops,
+  .firmware_context  = 0
+};
+
+/* This must go into l2_scratchpad region, starting at 0x0a000000. */
+
+static sbi_scratch_holder_t g_scratches[MPFS_MAX_NUM_HARTS] \
+               __attribute__((section(".l2_scratchpad")));
+
+/* These stacks are used in the mpfs_opensbi_utils.S */
+
+uint8_t g_hart_stacks[SBI_PLATFORM_DEFAULT_HART_STACK_SIZE * \
+                      MPFS_HART_COUNT] \
+                      __attribute__((section(".ddrstorage")));
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: mpfs_hart_to_scratch
+ *
+ * Description:
+ *   Returns the scratch area start for the given hart.
+ *
+ * Input Parameters:
+ *   hartid (0,1..5)
+ *
+ * Returned Value:
+ *   The scratch area in l2_scratchpad.
+ *
+ ****************************************************************************/
+
+static unsigned long mpfs_hart_to_scratch(int hartid)
+{
+  DEBUGASSERT(hartid < MPFS_MAX_NUM_HARTS);
+
+  return (unsigned long)(&g_scratches[hartid].scratch);
+}
+
+/****************************************************************************
+ * Name: mpfs_irqchip_init
+ *
+ * Description:
+ *   Sets the interrupt priorities via the plic_cold_irqchip_init() call.
+ *   Also this provides the proper PLIC base address for further irq
+ *   property handling such as threshold levels.
+ *
+ * Input Parameters:
+ *   cold_boot   - True, if this is the hart doing the real boot
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success.  A negated errno value is returned on
+ *   failure.
+ *
+ ****************************************************************************/
+
+static int mpfs_irqchip_init(bool cold_boot)
+{
+  int rc;
+  uint32_t hartid = current_hartid();
+
+  if (cold_boot)
+    {
+      rc = plic_cold_irqchip_init(&mpfs_plic);
+
+      if (rc)
+        {
+          return rc;
+        }
+    }
+
+  return plic_warm_irqchip_init(&mpfs_plic, (hartid) ? (2 * hartid - 1) : 0,
+                                (hartid) ? (2 * hartid) : -1);
+}
+
+/****************************************************************************
+ * Name: mpfs_console_putc
+ *
+ * Description:
+ *   Sets the interrupt priorities via the plic_cold_irqchip_init() call.
+ *   Also this provides the proper PLIC base address for further irq
+ *   property handling such as threshold levels.
+ *
+ * Input Parameters:
+ *   ch   - Character to be printed out
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void mpfs_console_putc(char ch)
+{
+#ifdef CONFIG_DEBUG_FEATURES
+  if (mpfs_console_ready)
+    {
+      riscv_lowputc(ch);
+    }
+#endif
+}
+
+/****************************************************************************
+ * Name: mpfs_opensbi_console_init
+ *
+ * Description:
+ *   Initializes the console for OpenSBI usage.  OpenSBI expects this
+ *   function to be present.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Always zero indicating a success.
+ *
+ ****************************************************************************/
+
+static int mpfs_opensbi_console_init(void)
+{
+  mpfs_console_ready = true;
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: mpfs_ipi_init
+ *
+ * Description:
+ *   Initializes the IPI for OpenSBI usage.  Also adds the regions into
+ *   OpenSBI domains.
+ *
+ * Input Parameters:
+ *    cold_boot   - Indicates the primary boot hart
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success.  A negated errno value is returned on
+ *   failure.
+ *
+ ****************************************************************************/
+
+static int mpfs_ipi_init(bool cold_boot)
+{
+  int rc;
+
+  if (cold_boot)
+    {
+      rc = aclint_mswi_cold_init(&mpfs_mswi);
+      if (rc)
+        {
+          return rc;
+        }
+    }
+
+  return aclint_mswi_warm_init();
+}
+
+/****************************************************************************
+ * Name: mpfs_timer_init
+ *
+ * Description:
+ *   Initializes the clint timer interface.  Commands such as "csrr a0, time"
+ *   (reading the CSR time register) will cause an illegal instruction
+ *   exception, because the hardware has no support for it.  That command is
+ *   emulated via the CLINT timer in the OpenSBI trap handler.
+ *
+ * Input Parameters:
+ *    cold_boot   - If set, indicates the primary boot hart
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success.  A negated errno value is returned on
+ *   failure.
+ *
+ ****************************************************************************/
+
+static int mpfs_timer_init(bool cold_boot)
+{
+  int rc;
+
+  if (cold_boot)
+    {
+      rc = aclint_mtimer_cold_init(&mpfs_mtimer, NULL);
+      if (rc)
+        {
+          return rc;
+        }
+    }
+
+  return aclint_mtimer_warm_init();
+}
+
+/****************************************************************************
+ * Name: mpfs_early_init
+ *
+ * Description:
+ *   Initializes the clint timer interface.  Commands such as "csrr a0, time"
+ *   (reading the CSR time register) will cause an illegal instruction
+ *   exception, because the hardware has no support for it.  That command is
+ *   emulated via the CLINT timer in the OpenSBI trap handler.
+ *
+ * Input Parameters:
+ *    cold_boot   - If set, indicates the primary boot hart
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success.
+ *
+ ****************************************************************************/
+
+static int mpfs_early_init(bool cold_boot)
+{
+  /* We expect that e51 has terminated the following irqs with
+   * up_disable_irq():
+   *   1. MPFS_IRQ_MMC_MAIN
+   *   2. MPFS_IRQ_MTIMER
+   *
+   * U-boot will reuse eMMC and loads the kernel from there. OpenSBI will
+   * use CLINT timer.  Upstream u-boot doesn't turn the clocks on itsef.
+   */
+
+  if (!cold_boot)
+    {
+      return 0;
+    }
+
+  /* Explicitly reset eMMC */
+
+  modifyreg32(MPFS_SYSREG_SOFT_RESET_CR, 0, SYSREG_SOFT_RESET_CR_MMC);
+  modifyreg32(MPFS_SYSREG_SOFT_RESET_CR, SYSREG_SOFT_RESET_CR_MMC, 0);
+
+  /* U-boot will use serial console 1, just turn on MMUART1 clocks now in
+   * order to see also u-boot traces.
+   */
+
+  modifyreg32(MPFS_SYSREG_SOFT_RESET_CR, SYSREG_SOFT_RESET_CR_MMUART1, 0);
+  modifyreg32(MPFS_SYSREG_SUBBLK_CLOCK_CR, 0,
+              SYSREG_SUBBLK_CLOCK_CR_MMUART1);
+
+  /* There are other clocks that need to be enabled for the Linux kernel to
+   * run. For now, turn on all the clocks.
+   */
+
+  putreg32(0x0, MPFS_SYSREG_SOFT_RESET_CR);
+  putreg32(0x7fffffff, MPFS_SYSREG_SUBBLK_CLOCK_CR);
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: mpfs_opensbi_scratch_setup
+ *
+ * Description:
+ *   Initializes the scratch area per hart.  The scratch area is used to save
+ *   and restore registers (see mpfs_exception_opensbi), and to send and
+ *   reveice messages to other harts via the IPI mechanism.
+ *
+ * Input Parameters:
+ *   hartid       - hart number to be prepared
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void mpfs_opensbi_scratch_setup(uint32_t hartid)
+{
+  DEBUGASSERT(hartid < MPFS_MAX_NUM_HARTS);
+
+  g_scratches[hartid].scratch.options = SBI_SCRATCH_DEBUG_PRINTS;
+  g_scratches[hartid].scratch.hartid_to_scratch =
+      (unsigned long)mpfs_hart_to_scratch;
+  g_scratches[hartid].scratch.platform_addr = (unsigned long)&platform;
+
+  /* Our FW area in l2lim section.  OpenSBI needs to be aware of it in order
+   * to protect the area.  However, we set the PMP values already and lock
+   * them so that OpenSBI has no chance override then.
+   */
+
+  g_scratches[hartid].scratch.fw_start = __mpfs_nuttx_start;
+  g_scratches[hartid].scratch.fw_size  = __mpfs_nuttx_end;
+}
+
+/****************************************************************************
+ * Name: mpfs_opensbi_pmp_setup
+ *
+ * Description:
+ *   Initializes the PMP registers in a known default state.  All harts need
+ *   to set these registers.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void mpfs_opensbi_pmp_setup(void)
+{
+  /* All access granted */
+
+  csr_write(pmpaddr0, MPFS_PMP_DEFAULT_ADDR);
+  csr_write(pmpcfg0, MPFS_PMP_DEFAULT_PERM);
+  csr_write(pmpcfg2, 0);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: mpfs_opensbi_setup
+ *
+ * Description:
+ *   Calls the necessary OpenSBI init functions:
+ *     - Sets up the PMP registers (to avoid OpenSBI overriding them)
+ *     - Sets up the OpenSBI console
+ *     - Sets up the mscratch registers
+ *     - Sets up the firmware to be run (should be already at .next_addr)
+ *     - Calls the sbi_init() that will not return
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   None - this will never return
+ *
+ ****************************************************************************/
+
+void __attribute__((noreturn)) mpfs_opensbi_setup(void)
+{
+  uint32_t hartid = current_hartid();
+
+  mpfs_opensbi_pmp_setup();
+
+  sbi_console_set_device(&mpfs_console);
+  mpfs_opensbi_scratch_setup(hartid);
+
+  csr_write(mscratch, &g_scratches[hartid].scratch);
+  g_scratches[hartid].scratch.next_mode = PRV_S;
+  g_scratches[hartid].scratch.next_addr = UBOOT_LOAD_ADDR;
+
+  sbi_init(&g_scratches[hartid].scratch);
+
+  /* Will never get here */
+
+  DEBUGPANIC();
+}
diff --git a/arch/risc-v/src/mpfs/mpfs_opensbi_utils.S b/arch/risc-v/src/mpfs/mpfs_opensbi_utils.S
new file mode 100755
index 0000000..8f912d0
--- /dev/null
+++ b/arch/risc-v/src/mpfs/mpfs_opensbi_utils.S
@@ -0,0 +1,276 @@
+/****************************************************************************
+ * arch/risc-v/src/mpfs/mpfs_opensbi_utils.S
+ *
+ * mpfs_exception_opensbi function is based on OpenSBI fw_base.S
+ *
+ * The 2-Clause BSD License
+ * SPDX short identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates and other
+ * contributors.
+ *
+ * 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.
+ *
+ * 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 HOLDER 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 <nuttx/config.h>
+
+#include <sbi/riscv_asm.h>
+#include <sbi/sbi_platform.h>
+#include <sbi/sbi_scratch.h>
+#include <sbi/sbi_trap.h>
+#include <sbi/riscv_encoding.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifndef SBI_PLATFORM_DEFAULT_HART_STACK_SIZE
+#define SBI_PLATFORM_DEFAULT_HART_STACK_SIZE 8192
+#endif
+
+/****************************************************************************
+ * Public Symbols
+ ****************************************************************************/
+
+  .global mpfs_opensbi_prepare_hart
+  .global mpfs_exception_opensbi
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+mpfs_global_pointer:
+  .dword __global_pointer$
+
+/****************************************************************************
+ * Name: mpfs_opensbi_prepare_hart
+ *
+ * Description:
+ *   Prepares the hart for OpenSBI execution.  This installs the proper
+ *   mtvec, global pointer and the stack (per hart) for the OpenSBI.
+ *   mpfs_global_pointer is used to store the real __global_pointer$ as
+ *   seen in the .map file.  Loading gp, _global_pointer$ would default to
+ *   mv gp, gp -instruction which isn't what we want. External libraties seem
+ *   to link relative to gp. When trapping from the kernel, the gp has been
+ *   utilized for other purposes, so we need to save and restore gp at all
+ *   times.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+  .align 3
+mpfs_opensbi_prepare_hart:
+
+  /* Setup OpenSBI exception handler */
+
+  la   t0, mpfs_exception_opensbi
+  csrw mtvec, t0
+
+  /* la gp, __global_pointer$ will not work. We want to have the gp as seen
+   * in the .map file exactly. We need to restore gp in the trap handler.
+   */
+
+  la   t0, mpfs_global_pointer
+  ld   gp, 0(t0)
+
+  /* Setup stacks per hart */
+
+  csrr a0, mhartid
+  mv   t0, a0
+  li   t1, SBI_PLATFORM_DEFAULT_HART_STACK_SIZE
+  mul  t0, a0, t1
+  la   sp, g_hart_stacks
+  add  sp, sp, t0
+  jal  mpfs_opensbi_setup
+
+/****************************************************************************
+ * Name: mpfs_exception_opensbi:
+ *
+ * Description:
+ *   This is the trap entry into OpenSBI.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+  .align 3
+mpfs_exception_opensbi:
+
+  /* Swap TP and MSCRATCH */
+
+  csrrw   tp, CSR_MSCRATCH, tp
+
+  /* Save T0 in scratch space */
+
+  REG_S   t0, SBI_SCRATCH_TMP0_OFFSET(tp)
+
+  /*
+   * Set T0 to appropriate exception stack
+   *
+   * Came_From_M_Mode = ((MSTATUS.MPP < PRV_M) ? 1 : 0) - 1;
+   * Exception_Stack = TP ^ (Came_From_M_Mode & (SP ^ TP))
+   *
+   * Came_From_M_Mode = 0    ==>    Exception_Stack = TP
+   * Came_From_M_Mode = -1   ==>    Exception_Stack = SP
+   */
+
+  csrr    t0, CSR_MSTATUS
+  srl     t0, t0, MSTATUS_MPP_SHIFT
+  and     t0, t0, PRV_M
+  slti    t0, t0, PRV_M
+  add     t0, t0, -1
+  xor     sp, sp, tp
+  and     t0, t0, sp
+  xor     sp, sp, tp
+  xor     t0, tp, t0
+
+  /* Save original SP on exception stack */
+
+  REG_S   sp, (SBI_TRAP_REGS_OFFSET(sp) - SBI_TRAP_REGS_SIZE)(t0)
+
+  /* Set SP to exception stack and make room for trap registers */
+
+  add     sp, t0, -(SBI_TRAP_REGS_SIZE)
+
+  /* Restore T0 from scratch space */
+
+  REG_L   t0, SBI_SCRATCH_TMP0_OFFSET(tp)
+
+  /* Save T0 on stack */
+
+  REG_S   t0, SBI_TRAP_REGS_OFFSET(t0)(sp)
+
+  /* Swap TP and MSCRATCH */
+
+  csrrw   tp, CSR_MSCRATCH, tp
+
+  /* Save MEPC and MSTATUS CSRs */
+
+  csrr    t0, CSR_MEPC
+  REG_S   t0, SBI_TRAP_REGS_OFFSET(mepc)(sp)
+  csrr    t0, CSR_MSTATUS
+  REG_S   t0, SBI_TRAP_REGS_OFFSET(mstatus)(sp)
+  REG_S   zero, SBI_TRAP_REGS_OFFSET(mstatusH)(sp)
+
+  /* Save all general regisers except SP and T0 */
+
+  REG_S   zero, SBI_TRAP_REGS_OFFSET(zero)(sp)
+  REG_S   ra, SBI_TRAP_REGS_OFFSET(ra)(sp)
+  REG_S   gp, SBI_TRAP_REGS_OFFSET(gp)(sp)
+  REG_S   tp, SBI_TRAP_REGS_OFFSET(tp)(sp)
+  REG_S   t1, SBI_TRAP_REGS_OFFSET(t1)(sp)
+  REG_S   t2, SBI_TRAP_REGS_OFFSET(t2)(sp)
+  REG_S   s0, SBI_TRAP_REGS_OFFSET(s0)(sp)
+  REG_S   s1, SBI_TRAP_REGS_OFFSET(s1)(sp)
+  REG_S   a0, SBI_TRAP_REGS_OFFSET(a0)(sp)
+  REG_S   a1, SBI_TRAP_REGS_OFFSET(a1)(sp)
+  REG_S   a2, SBI_TRAP_REGS_OFFSET(a2)(sp)
+  REG_S   a3, SBI_TRAP_REGS_OFFSET(a3)(sp)
+  REG_S   a4, SBI_TRAP_REGS_OFFSET(a4)(sp)
+  REG_S   a5, SBI_TRAP_REGS_OFFSET(a5)(sp)
+  REG_S   a6, SBI_TRAP_REGS_OFFSET(a6)(sp)
+  REG_S   a7, SBI_TRAP_REGS_OFFSET(a7)(sp)
+  REG_S   s2, SBI_TRAP_REGS_OFFSET(s2)(sp)
+  REG_S   s3, SBI_TRAP_REGS_OFFSET(s3)(sp)
+  REG_S   s4, SBI_TRAP_REGS_OFFSET(s4)(sp)
+  REG_S   s5, SBI_TRAP_REGS_OFFSET(s5)(sp)
+  REG_S   s6, SBI_TRAP_REGS_OFFSET(s6)(sp)
+  REG_S   s7, SBI_TRAP_REGS_OFFSET(s7)(sp)
+  REG_S   s8, SBI_TRAP_REGS_OFFSET(s8)(sp)
+  REG_S   s9, SBI_TRAP_REGS_OFFSET(s9)(sp)
+  REG_S   s10, SBI_TRAP_REGS_OFFSET(s10)(sp)
+  REG_S   s11, SBI_TRAP_REGS_OFFSET(s11)(sp)
+  REG_S   t3, SBI_TRAP_REGS_OFFSET(t3)(sp)
+  REG_S   t4, SBI_TRAP_REGS_OFFSET(t4)(sp)
+  REG_S   t5, SBI_TRAP_REGS_OFFSET(t5)(sp)
+  REG_S   t6, SBI_TRAP_REGS_OFFSET(t6)(sp)
+
+  /*  Restore GP */
+
+  la      a0, mpfs_global_pointer
+  ld      gp, 0(a0)
+
+  /* Call C routine */
+
+  add     a0, sp, zero
+  call    sbi_trap_handler
+
+  /* Restore all general regisers except A0 and T0 */
+
+  REG_L   ra, SBI_TRAP_REGS_OFFSET(ra)(a0)
+  REG_L   sp, SBI_TRAP_REGS_OFFSET(sp)(a0)
+  REG_L   gp, SBI_TRAP_REGS_OFFSET(gp)(a0)
+  REG_L   tp, SBI_TRAP_REGS_OFFSET(tp)(a0)
+  REG_L   t1, SBI_TRAP_REGS_OFFSET(t1)(a0)
+  REG_L   t2, SBI_TRAP_REGS_OFFSET(t2)(a0)
+  REG_L   s0, SBI_TRAP_REGS_OFFSET(s0)(a0)
+  REG_L   s1, SBI_TRAP_REGS_OFFSET(s1)(a0)
+  REG_L   a1, SBI_TRAP_REGS_OFFSET(a1)(a0)
+  REG_L   a2, SBI_TRAP_REGS_OFFSET(a2)(a0)
+  REG_L   a3, SBI_TRAP_REGS_OFFSET(a3)(a0)
+  REG_L   a4, SBI_TRAP_REGS_OFFSET(a4)(a0)
+  REG_L   a5, SBI_TRAP_REGS_OFFSET(a5)(a0)
+  REG_L   a6, SBI_TRAP_REGS_OFFSET(a6)(a0)
+  REG_L   a7, SBI_TRAP_REGS_OFFSET(a7)(a0)
+  REG_L   s2, SBI_TRAP_REGS_OFFSET(s2)(a0)
+  REG_L   s3, SBI_TRAP_REGS_OFFSET(s3)(a0)
+  REG_L   s4, SBI_TRAP_REGS_OFFSET(s4)(a0)
+  REG_L   s5, SBI_TRAP_REGS_OFFSET(s5)(a0)
+  REG_L   s6, SBI_TRAP_REGS_OFFSET(s6)(a0)
+  REG_L   s7, SBI_TRAP_REGS_OFFSET(s7)(a0)
+  REG_L   s8, SBI_TRAP_REGS_OFFSET(s8)(a0)
+  REG_L   s9, SBI_TRAP_REGS_OFFSET(s9)(a0)
+  REG_L   s10, SBI_TRAP_REGS_OFFSET(s10)(a0)
+  REG_L   s11, SBI_TRAP_REGS_OFFSET(s11)(a0)
+  REG_L   t3, SBI_TRAP_REGS_OFFSET(t3)(a0)
+  REG_L   t4, SBI_TRAP_REGS_OFFSET(t4)(a0)
+  REG_L   t5, SBI_TRAP_REGS_OFFSET(t5)(a0)
+  REG_L   t6, SBI_TRAP_REGS_OFFSET(t6)(a0)
+
+  /* Restore MEPC and MSTATUS CSRs */
+
+  REG_L   t0, SBI_TRAP_REGS_OFFSET(mepc)(a0)
+  csrw    CSR_MEPC, t0
+  REG_L   t0, SBI_TRAP_REGS_OFFSET(mstatus)(a0)
+  csrw    CSR_MSTATUS, t0
+
+  /* Restore T0 */
+
+  REG_L   t0, SBI_TRAP_REGS_OFFSET(t0)(a0)
+
+  /* Restore A0 */
+
+  REG_L   a0, SBI_TRAP_REGS_OFFSET(a0)(a0)
+
+  mret
diff --git a/arch/risc-v/src/opensbi/.gitignore b/arch/risc-v/src/opensbi/.gitignore
new file mode 100644
index 0000000..6dd75b4
--- /dev/null
+++ b/arch/risc-v/src/opensbi/.gitignore
@@ -0,0 +1,3 @@
+/.opensbi_unpack
+/opensbi-3rdparty
+/*tar.gz
diff --git a/arch/risc-v/src/opensbi/Kconfig b/arch/risc-v/src/opensbi/Kconfig
new file mode 100644
index 0000000..f24337e
--- /dev/null
+++ b/arch/risc-v/src/opensbi/Kconfig
@@ -0,0 +1,12 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+config OPENSBI
+	bool "OpenSBI support"
+	depends on ARCH_RISCV
+	default n
+	---help---
+		Enable or disable Open Source Supervisor Binary Interface (OpenSBI) features
+                for RISC-V.
diff --git a/arch/risc-v/src/opensbi/Make.defs b/arch/risc-v/src/opensbi/Make.defs
new file mode 100644
index 0000000..a734e2b
--- /dev/null
+++ b/arch/risc-v/src/opensbi/Make.defs
@@ -0,0 +1,89 @@
+############################################################################
+# arch/risc-v/src/opensbi/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_OPENSBI),y)
+
+DEPPATH += --dep-path opensbi/opensbi-3rdparty
+VPATH += :opensbi/opensbi-3rdparty
+
+OPENSBI_CSRCS = opensbi/opensbi-3rdparty/lib/sbi/riscv_asm.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/sbi/riscv_atomic.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/sbi/riscv_locks.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_bitmap.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_bitops.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_console.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_domain.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_ecall.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_ecall_base.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_ecall_hsm.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_ecall_legacy.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_ecall_pmu.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_ecall_replace.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_ecall_vendor.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_emulate_csr.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_fifo.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_hart.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_hsm.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_illegal_insn.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_init.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_ipi.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_math.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_misaligned_ldst.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_platform.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_pmu.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_scratch.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_string.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_system.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_timer.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_tlb.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_trap.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_unpriv.c
+
+OPENSBI_ASRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_expected_trap.S
+OPENSBI_ASRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_hfence.S
+
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/utils/ipi/aclint_mswi.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/utils/irqchip/plic.c
+OPENSBI_CSRCS += opensbi/opensbi-3rdparty/lib/utils/timer/aclint_mtimer.c
+
+OPENSBI_UNPACK  = opensbi-3rdparty
+OPENSBI_COMMIT  = 69d7e536138ae71a24028ca849d401a4d64d564b
+OPENSBI_URL     = https://github.com/riscv-software-src/opensbi/tarball
+OPENSBI_TARBALL = opensbi.tar.gz
+OPENSBI_DIR     = riscv-software-src-opensbi-69d7e53
+
+$(OPENSBI_TARBALL):
+	$(Q) echo "Downloading: OpenSBI"
+	$(Q) curl -L $(OPENSBI_URL)/$(OPENSBI_COMMIT) -o opensbi/$(OPENSBI_TARBALL)
+
+.opensbi_unpack: $(OPENSBI_TARBALL)
+	$(Q) echo "Unpacking: OpenSBI"
+	$(Q) tar xzf opensbi/$(OPENSBI_TARBALL) -C opensbi
+	$(Q) mv opensbi/$(OPENSBI_DIR) opensbi/$(OPENSBI_UNPACK)
+	$(Q) touch opensbi/.opensbi_unpack
+
+context:: .opensbi_unpack
+
+distclean::
+	$(call DELFILE, opensbi/.opensbi_unpack)
+	$(call DELFILE, opensbi/$(OPENSBI_TARBALL))
+	$(call DELDIR, opensbi/$(OPENSBI_UNPACK))
+
+endif
diff --git a/boards/risc-v/mpfs/icicle/configs/opensbi/defconfig b/boards/risc-v/mpfs/icicle/configs/opensbi/defconfig
new file mode 100644
index 0000000..80bfe1a
--- /dev/null
+++ b/boards/risc-v/mpfs/icicle/configs/opensbi/defconfig
@@ -0,0 +1,118 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed .config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that includes your
+# modifications.
+#
+# CONFIG_DISABLE_OS_API is not set
+# CONFIG_NSH_DISABLE_MW is not set
+CONFIG_ARCH="risc-v"
+CONFIG_ARCH_BOARD="icicle"
+CONFIG_ARCH_BOARD_ICICLE_MPFS=y
+CONFIG_ARCH_CHIP="mpfs"
+CONFIG_ARCH_CHIP_MPFS=y
+CONFIG_ARCH_INTERRUPTSTACK=2048
+CONFIG_ARCH_RISCV=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_BOARDCTL_MKRD=y
+CONFIG_BOARD_LOOPSPERMSEC=54000
+CONFIG_BUILTIN=y
+CONFIG_DEBUG_ASSERTIONS=y
+CONFIG_DEBUG_ERROR=y
+CONFIG_DEBUG_FEATURES=y
+CONFIG_DEBUG_FULLOPT=y
+CONFIG_DEBUG_SYMBOLS=y
+CONFIG_DEV_ZERO=y
+CONFIG_EXPERIMENTAL=y
+CONFIG_FAT_LCNAMES=y
+CONFIG_FAT_LFN=y
+CONFIG_FS_FAT=y
+CONFIG_FS_PROCFS=y
+CONFIG_FS_ROMFS=y
+CONFIG_IDLETHREAD_STACKSIZE=2048
+CONFIG_INTELHEX_BINARY=y
+CONFIG_LIBC_HOSTNAME="icicle"
+CONFIG_LIBC_PERROR_STDOUT=y
+CONFIG_LIBC_STRERROR=y
+CONFIG_MEMSET_64BIT=y
+CONFIG_MEMSET_OPTSPEED=y
+CONFIG_MMCSD=y
+CONFIG_MMCSD_SDIO=y
+CONFIG_MPFS_BOOTLOADER=y
+CONFIG_MPFS_DDR_INIT=y
+CONFIG_MPFS_EMMCSD=y
+CONFIG_MPFS_OPENSBI=y
+CONFIG_MPFS_UART0=y
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_DISABLE_BASENAME=y
+CONFIG_NSH_DISABLE_CAT=y
+CONFIG_NSH_DISABLE_CD=y
+CONFIG_NSH_DISABLE_CMP=y
+CONFIG_NSH_DISABLE_CP=y
+CONFIG_NSH_DISABLE_DD=y
+CONFIG_NSH_DISABLE_DF=y
+CONFIG_NSH_DISABLE_DIRNAME=y
+CONFIG_NSH_DISABLE_ECHO=y
+CONFIG_NSH_DISABLE_ENV=y
+CONFIG_NSH_DISABLE_EXEC=y
+CONFIG_NSH_DISABLE_EXIT=y
+CONFIG_NSH_DISABLE_EXPORT=y
+CONFIG_NSH_DISABLE_FREE=y
+CONFIG_NSH_DISABLE_GET=y
+CONFIG_NSH_DISABLE_HELP=y
+CONFIG_NSH_DISABLE_HEXDUMP=y
+CONFIG_NSH_DISABLE_IFCONFIG=y
+CONFIG_NSH_DISABLE_IFUPDOWN=y
+CONFIG_NSH_DISABLE_KILL=y
+CONFIG_NSH_DISABLE_LOSETUP=y
+CONFIG_NSH_DISABLE_LS=y
+CONFIG_NSH_DISABLE_MKDIR=y
+CONFIG_NSH_DISABLE_MKRD=y
+CONFIG_NSH_DISABLE_MOUNT=y
+CONFIG_NSH_DISABLE_MV=y
+CONFIG_NSH_DISABLE_PRINTF=y
+CONFIG_NSH_DISABLE_PS=y
+CONFIG_NSH_DISABLE_PUT=y
+CONFIG_NSH_DISABLE_PWD=y
+CONFIG_NSH_DISABLE_RM=y
+CONFIG_NSH_DISABLE_RMDIR=y
+CONFIG_NSH_DISABLE_SET=y
+CONFIG_NSH_DISABLE_SLEEP=y
+CONFIG_NSH_DISABLE_SOURCE=y
+CONFIG_NSH_DISABLE_TELNETD=y
+CONFIG_NSH_DISABLE_TEST=y
+CONFIG_NSH_DISABLE_TIME=y
+CONFIG_NSH_DISABLE_TRUNCATE=y
+CONFIG_NSH_DISABLE_UMOUNT=y
+CONFIG_NSH_DISABLE_UNAME=y
+CONFIG_NSH_DISABLE_UNSET=y
+CONFIG_NSH_DISABLE_USLEEP=y
+CONFIG_NSH_DISABLE_WGET=y
+CONFIG_NSH_DISABLE_XD=y
+CONFIG_NSH_LINELEN=160
+CONFIG_NSH_STRERROR=y
+CONFIG_OPENSBI=y
+CONFIG_PREALLOC_TIMERS=4
+CONFIG_RAM_SIZE=1048576
+CONFIG_RAM_START=0x80000000
+CONFIG_RAW_BINARY=y
+CONFIG_READLINE_CMD_HISTORY=y
+CONFIG_READLINE_TABCOMPLETION=y
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_HPWORK=y
+CONFIG_SCHED_LPWORK=y
+CONFIG_SCHED_WAITPID=y
+CONFIG_SERIAL_NPOLLWAITERS=2
+CONFIG_STACK_COLORATION=y
+CONFIG_START_MONTH=4
+CONFIG_START_YEAR=2021
+CONFIG_SYSLOG_COLOR_OUTPUT=y
+CONFIG_SYSTEM_CLE_CMD_HISTORY=y
+CONFIG_SYSTEM_COLOR_CLE=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_SYSTEM_TIME64=y
+CONFIG_TASK_NAME_SIZE=20
+CONFIG_UART0_SERIAL_CONSOLE=y
+CONFIG_USERMAIN_STACKSIZE=3072
+CONFIG_USER_ENTRYPOINT="nsh_main"
diff --git a/boards/risc-v/mpfs/icicle/scripts/Make.defs b/boards/risc-v/mpfs/icicle/scripts/Make.defs
index e1ed0ca..52167e5 100755
--- a/boards/risc-v/mpfs/icicle/scripts/Make.defs
+++ b/boards/risc-v/mpfs/icicle/scripts/Make.defs
@@ -23,7 +23,11 @@ include $(TOPDIR)/tools/Config.mk
 include $(TOPDIR)/arch/risc-v/src/rv64gc/Toolchain.defs
 
 ifeq ($(CONFIG_MPFS_BOOTLOADER),y)
-  LDSCRIPT = ld-envm.script
+  ifeq ($(CONFIG_MPFS_OPENSBI),y)
+    LDSCRIPT = ld-envm-opensbi.script
+  else
+    LDSCRIPT = ld-envm.script
+  endif
 else
   LDSCRIPT = ld.script
 endif
diff --git a/boards/risc-v/mpfs/icicle/scripts/ld-envm-opensbi.script b/boards/risc-v/mpfs/icicle/scripts/ld-envm-opensbi.script
new file mode 100755
index 0000000..2d4e20f
--- /dev/null
+++ b/boards/risc-v/mpfs/icicle/scripts/ld-envm-opensbi.script
@@ -0,0 +1,123 @@
+/****************************************************************************
+ * boards/risc-v/mpfs/icicle/scripts/ld-envm.script
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+MEMORY
+{
+    ddr  (rx)     : ORIGIN = 0x80000000, LENGTH = 4M          /* w/ cache */
+    envm (rx)     : ORIGIN = 0x20220100, LENGTH = 128K - 256  /* 256 reserved for hss headers */
+    l2lim  (rwx)  : ORIGIN = 0x08000000, LENGTH = 1024k
+    l2zerodevice (rwx) : ORIGIN = 0x0A000000, LENGTH = 512k
+}
+
+OUTPUT_ARCH("riscv")
+
+ENTRY(_stext)
+EXTERN(_vectors)
+SECTIONS
+{
+    .text.sbi : {
+      sbi*
+    } > ddr
+
+    .ddrstorage : {
+      *(.ddrstorage)
+    } > ddr
+
+    .l2_scratchpad : ALIGN(0x10)
+    {
+        __l2_scratchpad_load = LOADADDR(.l2_scratchpad);
+        __l2_scratchpad_start = .;
+        __l2_scratchpad_vma_start = .;
+        *(.l2_scratchpad)
+
+        . = ALIGN(0x10);
+        __l2_scratchpad_end = .;
+        __l2_scratchpad_vma_end = .;
+    } > l2zerodevice
+
+    PROVIDE(__mpfs_nuttx_start = ORIGIN(l2lim));
+
+    .text : {
+        _stext = ABSOLUTE(.);
+        *(.vectors)
+        *(.text .text.*)
+        *(.f-ixup)
+        *(.gnu.warning)
+        *(.rodata .rodata.* .srodata .srodata.*)
+        *(.gnu.linkonce.t.*)
+        *(.glue_7)
+        *(.glue_7t)
+        *(.got)
+        *(.gcc_except_table)
+        *(.gnu.linkonce.r.*)
+        _etext = ABSOLUTE(.);
+    } > envm
+
+    .init_section : ALIGN(4) {
+        _sinit = ABSOLUTE(.);
+        KEEP(*(.init_array .init_array.*))
+        _einit = ABSOLUTE(.);
+    } > envm
+
+    _eronly = ABSOLUTE(.);
+
+    .data : ALIGN(4) {
+        _sdata = ABSOLUTE(.);
+        *(.data .data.*)
+        *(.sdata .sdata.* .sdata2.*)
+        *(.gnu.linkonce.d.*)
+        *(.gnu.linkonce.s.*)
+        CONSTRUCTORS
+        . = ALIGN(4);
+        _edata = ABSOLUTE(.);
+    } > l2lim AT > envm
+
+    PROVIDE(__global_pointer$ = _sdata + ((_edata - _sdata) / 2));
+
+    .bss : ALIGN(4) {
+        _sbss = ABSOLUTE(.);
+        *(.bss .bss.*)
+        *(.sbss .sbss.*)
+        *(.gnu.linkonce.b.*)
+        *(.gnu.linkonce.sb.*)
+        *(COMMON)
+        . = ALIGN(4);
+        _ebss = ABSOLUTE(.);
+        . = ALIGN(32);
+        _default_stack_limit = ABSOLUTE(.);
+    } > l2lim
+
+    PROVIDE(__mpfs_nuttx_end = .);
+
+    /* Stabs debugging sections. */
+
+    .stab 0 : { *(.stab) }
+    .stabstr 0 : { *(.stabstr) }
+    .stab.excl 0 : { *(.stab.excl) }
+    .stab.exclstr 0 : { *(.stab.exclstr) }
+    .stab.index 0 : { *(.stab.index) }
+    .stab.indexstr 0 : { *(.stab.indexstr) }
+    .comment 0 : { *(.comment) }
+    .debug_abbrev 0 : { *(.debug_abbrev) }
+    .debug_info 0 : { *(.debug_info) }
+    .debug_line 0 : { *(.debug_line) }
+    .debug_pubnames 0 : { *(.debug_pubnames) }
+    .debug_aranges 0 : { *(.debug_aranges) }
+}