Progress on eSPI support for NXP P1021 TPM.

pull/302/head
David Garske 2023-05-04 13:47:37 -07:00
parent ef35f473c9
commit 0f110e4cd9
16 changed files with 319 additions and 42 deletions

View File

@ -331,6 +331,7 @@ ifeq ($(TARGET),nxp_p1021)
# Use the SP math all assembly accelerations # Use the SP math all assembly accelerations
CFLAGS+=-DWOLFSSL_SP_PPC CFLAGS+=-DWOLFSSL_SP_PPC
endif endif
SPI_TARGET=nxp
endif endif
ifeq ($(TARGET),ti_hercules) ifeq ($(TARGET),ti_hercules)

9
config/examples/nxp-p1021.config 100644 → 100755
View File

@ -20,12 +20,13 @@ SPMATH?=0
SPMATHALL?=1 SPMATHALL?=1
RAM_CODE?=0 RAM_CODE?=0
DUALBANK_SWAP?=0 DUALBANK_SWAP?=0
WOLFTPM?=0 WOLFTPM?=1
# Flash Sector (Block) Size (16KB) # Flash Sector (Block) Size (16KB)
WOLFBOOT_SECTOR_SIZE=0x4000 WOLFBOOT_SECTOR_SIZE=0x4000
# Maximum size of wolfBoot stage 1 loader # Maximum size of wolfBoot stage 1 loader (can be increased for debugging)
# Needs to be 4KB 0x1000 to fit into boot ROM loaded region
WOLFBOOT_STAGE1_SIZE=0x1000 WOLFBOOT_STAGE1_SIZE=0x1000
# wolfBoot partition size (128KB) # wolfBoot partition size (128KB)
@ -39,7 +40,7 @@ WOLFBOOT_PARTITION_SIZE?=0x1000000
# Location in Flash for stage 1 loader (XIP from boot ROM) # Location in Flash for stage 1 loader (XIP from boot ROM)
WOLFBOOT_STAGE1_FLASH_ADDR=0x0 WOLFBOOT_STAGE1_FLASH_ADDR=0x0
# Location in Flash for wolfBoot # Location in Flash for wolfBoot
WOLFBOOT_ORIGIN=0x4000 WOLFBOOT_ORIGIN=0x8000
# Location in Flash for Application Partition # Location in Flash for Application Partition
WOLFBOOT_PARTITION_BOOT_ADDRESS?= 0x200000 WOLFBOOT_PARTITION_BOOT_ADDRESS?= 0x200000
# Location in Flash for Update Partition # Location in Flash for Update Partition
@ -49,7 +50,7 @@ WOLFBOOT_PARTITION_SWAP_ADDRESS?= 0x2200000
## Loader Destinations (DDR) ## ## Loader Destinations (DDR) ##
# Address in RAM to load stage 1 loader # Address in RAM to load stage 1 loader (can't be 0x0)
WOLFBOOT_STAGE1_BASE_ADDR=0x4000 WOLFBOOT_STAGE1_BASE_ADDR=0x4000
# Address in RAM to load wolfBoot # Address in RAM to load wolfBoot

View File

@ -1162,6 +1162,22 @@ make clean && make
| swap block | 0x02200000 | | swap block | 0x02200000 |
### Debugging NXP P1021 PPC
Use `V=1` to show verbose output for build steps.
Use `DEBUG=1` to enable debug symbols.
The first stage loader must fit into 4KB. To build this in release and assemble a debug version of wolfBoot use the following steps:
```
make clean
make stage1
make DEBUG=1 wolfboot.bin
make DEBUG=1 test-app/image_v1_signed.bin
make factory_wstage1.bin
```
## NXP QorIQ T2080 PPC ## NXP QorIQ T2080 PPC
The NXP QorIQ T2080 is a PPC e6500 based processor (four cores). Support has been tested with the NAII 68PPC2. The NXP QorIQ T2080 is a PPC e6500 based processor (four cores). Support has been tested with the NAII 68PPC2.

119
hal/nxp_p1021.c 100755 → 100644
View File

@ -34,6 +34,10 @@
#define ENABLE_CONF_IO #define ENABLE_CONF_IO
#endif #endif
#ifdef WOLFBOOT_TPM
#define ENABLE_ESPI
#endif
/* TODO */ /* TODO */
/* Ethernet */ /* Ethernet */
/* QUICC */ /* QUICC */
@ -51,7 +55,8 @@ static int test_flash(void);
/* P1021 Platform */ /* P1021 Platform */
#define SYS_CLK (533000000) /* 533MHz */ //#define SYS_CLK (533000000) /* 533MHz */
#define SYS_CLK (400000000) /* 400MHz */
#define RESET_BPTR ((volatile uint32_t*)(CCSRBAR + 0x42)) /* Boot page translation register */ #define RESET_BPTR ((volatile uint32_t*)(CCSRBAR + 0x42)) /* Boot page translation register */
@ -380,6 +385,113 @@ enum elbc_amask_sizes {
#define ECM_BASE (CCSRBAR + 0x1000) #define ECM_BASE (CCSRBAR + 0x1000)
#define ECM_EEBACR ((volatile uint32_t*)(ECM_BASE + 0x0)) /* ECM CCB address configuration register */ #define ECM_EEBACR ((volatile uint32_t*)(ECM_BASE + 0x0)) /* ECM CCB address configuration register */
/* eSPI */
#define ESPI_MAX_CS_NUM 4
#define ESPI_MAX_RX_LEN (1 << 16)
#define ESPI_BASE (CCSRBAR + 0x7000)
#define ESPI_SPMODE ((volatile uint32_t*)(ESPI_BASE + 0x00)) /* controls eSPI general operation mode */
#define ESPI_SPIE ((volatile uint32_t*)(ESPI_BASE + 0x04)) /* controls interrupts and report events */
#define ESPI_SPIM ((volatile uint32_t*)(ESPI_BASE + 0x08)) /* enables/masks interrupts */
#define ESPI_SPCOM ((volatile uint32_t*)(ESPI_BASE + 0x0C)) /* command frame information */
#define ESPI_SPITF ((volatile uint32_t*)(ESPI_BASE + 0x10)) /* transmit FIFO access register */
#define ESPI_SPIRF ((volatile uint32_t*)(ESPI_BASE + 0x14)) /* 32-bit read-only receive data register */
#define ESPI_SPCSMODE(x) ((volatile uint32_t*)(ESPI_BASE + 0x20 + ((cs) * 4))) /* controls master operation with chip select 0-3 */
#define ESPI_SPMODE_EN (0x80000000) /* Enable eSPI */
#define ESPI_SPMODE_TXTHR(x) ((x) << 8) /* Tx FIFO threshold (1-32) */
#define ESPI_SPMODE_RXTHR(x) ((x) << 0) /* Rx FIFO threshold (0-31) */
#define ESPI_SPCOM_CS(x) ((x) << 30) /* Chip select-chip select for which transaction is destined */
#define ESPI_SPCOM_RXSKIP(x) ((x) << 16) /* Number of characters skipped for reception from frame start */
#define ESPI_SPCOM_TRANLEN(x) (((x) - 1) << 0) /* Transaction length */
#define ESPI_SPIE_RNE (1 << 9) /* recevie not empty */
#define ESPI_SPIE_TNF (1 << 8) /* transmit not full */
#define ESPI_CSMODE_CI 0x80000000 /* Inactive high */
#define ESPI_CSMODE_CP 0x40000000 /* Begin edge clock */
#define ESPI_CSMODE_REV 0x20000000 /* MSB first */
#define ESPI_CSMODE_DIV16 0x10000000 /* divide system clock by 16 */
#define ESPI_CSMODE_PM(x) (((x) & 0xF) << 24) /* presale modulus select */
#define ESPI_CSMODE_POL 0x00100000 /* asserted low */
#define ESPI_CSMODE_LEN(x) ((((x) - 1) & 0xF) << 16) /* Character length in bits per character */
#define ESPI_CSMODE_CSBEF(x) (((x) & 0xF) << 12) /* CS assertion time in bits before frame start */
#define ESPI_CSMODE_CSAFT(x) (((x) & 0xF) << 8) /* CS assertion time in bits after frame end */
#define ESPI_CSMODE_CSCG(x) (((x) & 0xF) << 3) /* Clock gaps between transmitted frames according to this size */
#ifdef ENABLE_ESPI
void hal_espi_init(uint32_t cs, uint32_t clock_hz, uint32_t mode)
{
uint32_t spibrg = SYS_CLK / 2, pm, csmode;
/* Enable eSPI with TX threadshold 4 and TX threshold 3 */
set32(ESPI_SPMODE, (ESPI_SPMODE_EN | ESPI_SPMODE_TXTHR(4) |
ESPI_SPMODE_RXTHR(3)));
set32(ESPI_SPIE, 0xffffffff); /* Clear all eSPI events */
set32(ESPI_SPIM, 0x00000000); /* Mask all eSPI interrupts */
csmode = (ESPI_CSMODE_REV | ESPI_CSMODE_POL | ESPI_CSMODE_LEN(8) |
ESPI_CSMODE_CSBEF(0) | ESPI_CSMODE_CSAFT(0) | ESPI_CSMODE_CSCG(1));
/* calculate clock divisor */
if (spibrg / clock_hz > 16) {
csmode |= ESPI_CSMODE_DIV16;
pm = (spibrg / (clock_hz * 16));
}
else {
pm = (spibrg / (clock_hz));
}
if (pm > 0)
pm--;
csmode |= ESPI_CSMODE_PM(pm);
if (mode & 1)
csmode |= ESPI_CSMODE_CP;
if (mode & 2)
csmode |= ESPI_CSMODE_CI;
/* configure CS */
set32(ESPI_SPCSMODE(cs), csmode);
}
int hal_espi_xfer(int cs, const uint8_t* tx, uint8_t* rx, uint32_t sz)
{
uint32_t reg, blks;
/* assert CS */
set32(ESPI_SPCOM, ESPI_SPCOM_CS(cs) | ESPI_SPCOM_TRANLEN(sz));
set32(ESPI_SPIE, 0xffffffff); /* Clear all eSPI events */
/* calculate the number of 4 byte blocks rounded up */
blks = (sz + 3) / 4;
while (blks--) {
/* wait till TX fifo has room */
while ((get32(ESPI_SPIE) & ESPI_SPIE_TNF) == 0);
reg = *((uint32_t*)tx);
set32(ESPI_SPITF, reg);
tx += 4;
/* wait till RX has data */
while ((get32(ESPI_SPIE) & ESPI_SPIE_RNE) == 0);
reg = get32(ESPI_SPIRF);
*((uint32_t*)rx) = reg;
rx += 4;
}
/* toggle ESPI_SPMODE_EN - to deassert CS */
reg = get32(ESPI_SPMODE);
set32(ESPI_SPMODE, reg & ~ESPI_SPMODE_EN);
set32(ESPI_SPMODE, reg);
return 0;
}
void hal_espi_deinit(void)
{
/* do nothing */
}
#endif /* ENABLE_ESPI */
static void set_law(uint8_t idx, uint32_t addr, uint32_t trgt_id, static void set_law(uint8_t idx, uint32_t addr, uint32_t trgt_id,
@ -932,10 +1044,7 @@ void hal_init(void)
#ifdef DEBUG_UART #ifdef DEBUG_UART
uart_init(); uart_init();
uart_write("wolfBoot HAL Init\r\n", 19);
#ifdef DEBUG
uart_write("wolfBoot Init\r\n", 15);
#endif
#endif #endif
#ifdef GET_PSVR #ifdef GET_PSVR

View File

@ -79,3 +79,4 @@ SECTIONS
PROVIDE(_start_heap = _end); PROVIDE(_start_heap = _end);
PROVIDE(_end_stack = _end + HEAP_SIZE + STACK_SIZE ); PROVIDE(_end_stack = _end + HEAP_SIZE + STACK_SIZE );

0
hal/renesas-ra.c 100755 → 100644
View File

View File

@ -28,6 +28,8 @@
#include "spi_drv.h" #include "spi_drv.h"
#include "spi_drv_nrf52.h" #include "spi_drv_nrf52.h"
#if defined(SPI_FLASH) || defined(WOLFBOOT_TPM)
#define SPI0 (0x40003000) #define SPI0 (0x40003000)
#define SPI1 (0x40004000) #define SPI1 (0x40004000)
#define SPI2 (0x40023000) #define SPI2 (0x40023000)
@ -122,3 +124,19 @@ void spi_release(void)
{ {
} }
#ifdef WOLFBOOT_TPM
int spi_xfer(int cs, const uint8_t* tx, uint8_t* rx, uint32_t sz)
{
uint32_t i;
spi_cs_on(SPI_CS_TPM_PIO_BASE, cs);
for (i = 0; i < sz; i++) {
spi_write((const char)tx[i]);
rx[i] = spi_read();
}
spi_cs_off(SPI_CS_TPM_PIO_BASE, cs);
return 0;
}
#endif /* WOLFBOOT_TPM */
#endif /* SPI_FLASH || WOLFBOOT_TPM */

View File

@ -0,0 +1,62 @@
/* spi_drv_nxp.c
*
* Driver for the SPI back-end of the SPI_FLASH module.
*
* Pinout: see spi_drv_nxp.h
*
* Copyright (C) 2023 wolfSSL Inc.
*
* This file is part of wolfBoot.
*
* wolfBoot is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfBoot is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#include <stdint.h>
#include <stddef.h>
#include "spi_drv.h"
#include "spi_drv_nxp.h"
#ifdef WOLFBOOT_TPM
#if defined(PLATFORM_nxp_p1021)
/* functions from nxp_p1021.c hal */
extern void hal_espi_init(uint32_t cs, uint32_t clock_hz, uint32_t mode);
extern int hal_espi_xfer(int cs, const uint8_t* tx, uint8_t* rx, uint32_t sz);
extern void hal_espi_deinit(void);
#endif
#include <wolftpm/tpm2_types.h>
void spi_init(int polarity, int phase)
{
static int initialized = 0;
if (!initialized) {
initialized++;
hal_espi_init(SPI_CS_TPM, TPM2_SPI_MAX_HZ, (polarity | (phase << 1)));
}
(void)polarity;
(void)phase;
}
void spi_release(void)
{
hal_espi_deinit();
}
int spi_xfer(int cs, const uint8_t* tx, uint8_t* rx, uint32_t sz)
{
return hal_espi_xfer(cs, tx, rx, sz);
}
#endif /* WOLFBOOT_TPM */

View File

@ -0,0 +1,32 @@
/* spi_drv_nxp.h
*
* wolfBoot is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfBoot is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#ifndef SPI_DRV_NXP_H_INCLUDED
#define SPI_DRV_NXP_H_INCLUDED
#include <stdint.h>
#if defined(PLATFORM_nxp_p1021)
/* Chip select for TPM */
#ifndef SPI_CS_TPM
#define SPI_CS_TPM 2
#endif
#endif
#endif /* !SPI_DRV_NXP_H_INCLUDED */

View File

@ -499,4 +499,18 @@ void RAMFUNCTION spi_release(void)
} }
} }
#ifdef WOLFBOOT_TPM
int spi_xfer(int cs, const uint8_t* tx, uint8_t* rx, uint32_t sz)
{
uint32_t i;
spi_cs_on(SPI_CS_TPM_PIO_BASE, cs);
for (i = 0; i < sz; i++) {
spi_write((const char)tx[i]);
rx[i] = spi_read();
}
spi_cs_off(SPI_CS_TPM_PIO_BASE, cs);
return 0;
}
#endif /* WOLFBOOT_TPM */
#endif /* SPI_FLASH || WOLFBOOT_TPM || QSPI_FLASH || OCTOSPI_FLASH */ #endif /* SPI_FLASH || WOLFBOOT_TPM || QSPI_FLASH || OCTOSPI_FLASH */

View File

@ -29,7 +29,7 @@
#include "spi_drv.h" #include "spi_drv.h"
#include "spi_drv_zynq.h" #include "spi_drv_zynq.h"
#ifdef SPI_FLASH #if defined(SPI_FLASH) || defined(WOLFBOOT_TPM)
void spi_cs_off(uint32_t base, int pin) void spi_cs_off(uint32_t base, int pin)
{ {
@ -70,4 +70,18 @@ void spi_release(void)
} }
#endif #ifdef WOLFBOOT_TPM
int spi_xfer(int cs, const uint8_t* tx, uint8_t* rx, uint32_t sz)
{
uint32_t i;
spi_cs_on(SPI_CS_TPM_PIO_BASE, cs);
for (i = 0; i < sz; i++) {
spi_write((const char)tx[i]);
rx[i] = spi_read();
}
spi_cs_off(SPI_CS_TPM_PIO_BASE, cs);
return 0;
}
#endif /* WOLFBOOT_TPM */
#endif /* SPI_FLASH | WOLFBOOT_TPM */

View File

@ -49,15 +49,23 @@
#include "hal/spi/spi_drv_nrf52.h" #include "hal/spi/spi_drv_nrf52.h"
#endif #endif
#if defined(PLATFORM_nxp_p1021)
#include "hal/spi/spi_drv_nxp.h"
#endif
void spi_init(int polarity, int phase); void spi_init(int polarity, int phase);
void spi_release(void); void spi_release(void);
#if defined(SPI_FLASH) || defined(WOLFBOOT_TPM) #ifdef SPI_FLASH
void spi_cs_on(uint32_t base, int pin); void spi_cs_on(uint32_t base, int pin);
void spi_cs_off(uint32_t base, int pin); void spi_cs_off(uint32_t base, int pin);
void spi_write(const char byte); void spi_write(const char byte);
uint8_t spi_read(void); uint8_t spi_read(void);
#endif /* SPI_FLASH || WOLFBOOT_TPM */ #endif
#ifdef WOLFBOOT_TPM
int spi_xfer(int cs, const uint8_t* tx, uint8_t* rx, uint32_t sz);
#endif
#if defined(QSPI_FLASH) || defined(OCTOSPI_FLASH) #if defined(QSPI_FLASH) || defined(OCTOSPI_FLASH)

View File

@ -448,8 +448,7 @@ ifeq ($(WOLFTPM),1)
-D"MAX_COMMAND_SIZE=1024" -D"MAX_RESPONSE_SIZE=1024" -D"WOLFTPM2_MAX_BUFFER=1500" \ -D"MAX_COMMAND_SIZE=1024" -D"MAX_RESPONSE_SIZE=1024" -D"WOLFTPM2_MAX_BUFFER=1500" \
-D"MAX_SESSION_NUM=2" -D"MAX_DIGEST_BUFFER=973" \ -D"MAX_SESSION_NUM=2" -D"MAX_DIGEST_BUFFER=973" \
-D"WOLFTPM_SMALL_STACK" -D"WOLFTPM_SMALL_STACK"
# Chip Type: WOLFTPM_SLB9670, WOLFTPM_ST33, WOLFTPM_MCHP CFLAGS+=-D"WOLFTPM_AUTODETECT"
CFLAGS+=-D"WOLFTPM_SLB9670"
# Use TPM for hashing (slow) # Use TPM for hashing (slow)
#CFLAGS+=-D"WOLFBOOT_HASH_TPM" #CFLAGS+=-D"WOLFBOOT_HASH_TPM"
ifneq ($(SPI_FLASH),1) ifneq ($(SPI_FLASH),1)

View File

@ -717,17 +717,11 @@ static void key_sha3_384(uint8_t key_slot, uint8_t *hash)
static int TPM2_IoCb(TPM2_CTX* ctx, const byte* txBuf, byte* rxBuf, static int TPM2_IoCb(TPM2_CTX* ctx, const byte* txBuf, byte* rxBuf,
word16 xferSz, void* userCtx) word16 xferSz, void* userCtx)
{ {
(void)userCtx; int ret;
(void)ctx;
word16 i;
spi_cs_on(SPI_CS_TPM_PIO_BASE, SPI_CS_TPM);
memset(rxBuf, 0, xferSz); memset(rxBuf, 0, xferSz);
for (i = 0; i < xferSz; i++) ret = spi_xfer(SPI_CS_TPM, txBuf, rxBuf, xferSz);
{
spi_write(txBuf[i]);
rxBuf[i] = spi_read();
}
spi_cs_off(SPI_CS_TPM_PIO_BASE, SPI_CS_TPM);
/* /*
printf("\r\nSPI TX: "); printf("\r\nSPI TX: ");
printbin(txBuf, xferSz); printbin(txBuf, xferSz);
@ -735,7 +729,11 @@ static int TPM2_IoCb(TPM2_CTX* ctx, const byte* txBuf, byte* rxBuf,
printbin(rxBuf, xferSz); printbin(rxBuf, xferSz);
printf("\r\n"); printf("\r\n");
*/ */
return 0;
(void)userCtx;
(void)ctx;
return ret;
} }
#endif /* !ARCH_SIM */ #endif /* !ARCH_SIM */
@ -791,17 +789,18 @@ int wolfBoot_tpm2_init(void)
#else #else
rc = wolfTPM2_Init(&wolftpm_dev, TPM2_IoCb, NULL); rc = wolfTPM2_Init(&wolftpm_dev, TPM2_IoCb, NULL);
#endif #endif
if (rc != 0) { if (rc == 0) {
return rc;
}
/* Get device capabilities + options */ /* Get device capabilities + options */
rc = wolfTPM2_GetCapabilities(&wolftpm_dev, &caps); rc = wolfTPM2_GetCapabilities(&wolftpm_dev, &caps);
if (rc != 0) { }
return rc; if (rc == 0) {
wolfBoot_printf("Mfg %s (%d), Vendor %s, Fw %u.%u (0x%x), "
"FIPS 140-2 %d, CC-EAL4 %d\n",
caps.mfgStr, caps.mfg, caps.vendorStr, caps.fwVerMajor,
caps.fwVerMinor, caps.fwVerVendor, caps.fips140_2, caps.cc_eal4);
} }
return 0; return rc;
} }
/* Currently only supports ecc256 */ /* Currently only supports ecc256 */

View File

@ -29,6 +29,9 @@ OBJS:= \
WOLFCRYPT_OBJS:= WOLFCRYPT_OBJS:=
PUBLIC_KEY_OBJS:= PUBLIC_KEY_OBJS:=
# Forcefully disable TPM support in first stage loader
WOLFTPM=0
## Architecture/CPU configuration ## Architecture/CPU configuration
include ../arch.mk include ../arch.mk

View File

@ -40,12 +40,6 @@
#define WOLFBOOT_STAGE1_SIZE (4*1024) #define WOLFBOOT_STAGE1_SIZE (4*1024)
#endif #endif
#ifndef WOLFBOOT_STAGE1_START_ADDR
/* default is end of 4KB region (0x0FFC) */
#define WOLFBOOT_STAGE1_START_ADDR \
(WOLFBOOT_STAGE1_LOAD_ADDR + WOLFBOOT_STAGE1_SIZE - 0x4)
#endif
#ifdef BUILD_LOADER_STAGE1 #ifdef BUILD_LOADER_STAGE1
#if defined(WOLFBOOT_ARCH) && WOLFBOOT_ARCH == PPC #if defined(WOLFBOOT_ARCH) && WOLFBOOT_ARCH == PPC
@ -87,7 +81,13 @@ int main(void)
BOOTLOADER_PARTITION_SIZE /* boot-loader partition (entire) */ BOOTLOADER_PARTITION_SIZE /* boot-loader partition (entire) */
); );
if (ret >= 0) { if (ret >= 0) {
wolfboot_start = (void*)WOLFBOOT_STAGE1_START_ADDR; wolfboot_start = (void*)WOLFBOOT_STAGE1_LOAD_ADDR;
#ifdef PRINTF_ENABLED
wolfBoot_printf("Jumping to %p\r\n", wolfboot_start);
#elif defined(DEBUG_UART)
uart_write("Jump to relocated wolfboot_start\r\n", 34);
#endif
wolfboot_start(); /* never returns */ wolfboot_start(); /* never returns */
} }