summaryrefslogtreecommitdiff
path: root/ubi-utils/src/ubiinfo
diff options
context:
space:
mode:
Diffstat (limited to 'ubi-utils/src/ubiinfo')
-rw-r--r--ubi-utils/src/ubiinfo/ubiflash.h185
-rw-r--r--ubi-utils/src/ubiinfo/ubiinfo.c406
-rw-r--r--ubi-utils/src/ubiinfo/ubiipl.h87
3 files changed, 678 insertions, 0 deletions
diff --git a/ubi-utils/src/ubiinfo/ubiflash.h b/ubi-utils/src/ubiinfo/ubiflash.h
new file mode 100644
index 0000000..6883879
--- /dev/null
+++ b/ubi-utils/src/ubiinfo/ubiflash.h
@@ -0,0 +1,185 @@
+#ifndef _UBI_FLASH_H
+#define _UBI_FLASH_H
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program 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.
+ *
+ * This program 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * FLASH related data structures and constants for UBI.
+ * UBI scan analysis.
+ *
+ * IPL Initial Program Loader
+ * SPL Secondary Program Loader
+ */
+
+#include <stdint.h>
+#include <asm/byteorder.h>
+#include <mtd/ubi-header.h>
+
+#define UBI_BLOCK_IDENT_MAX 16
+
+/* Block status information constants */
+enum blockstat {
+ /* IO Error */
+ STAT_IO_FAILED = 1, /* 0xffffffff */
+ /* Block is bad */
+ STAT_BLOCK_BAD = 2, /* 0xfffffffe */
+ /* ECC unrecoverable error */
+ STAT_ECC_ERROR = 3, /* 0xfffffffd */
+ /* CRC checksum failed */
+ STAT_CRC_ERROR = 4, /* 0xfffffffc */
+ /* Magic number not available */
+ STAT_NO_MAGIC = 5, /* 0xfffffffb */
+ /* No image available */
+ STAT_NO_IMAGE = 6,
+ /* Image is invalid */
+ STAT_INVALID_IMAGE = 7,
+ /* Image is defect */
+ STAT_DEFECT_IMAGE = 8,
+};
+
+/*
+ * Flash types
+ */
+enum flashtypes {
+ FLASH_TYPE_NAND = 1,
+ FLASH_TYPE_NOR,
+};
+
+/* Nand read buffer size: 2KiB + 64byte spare */
+#define NAND_READ_BUF_SIZE (2048 + 64)
+
+/* Size of the CRC table */
+#define CRC32_TABLE_SIZE 256
+
+/* Image is not available marker for image offs */
+#define UBI_IMAGE_NOT_AVAILABLE 0xFFFFFFFF
+
+/* Increment this number, whenever you change the structure */
+#define UBI_SCAN_INFO_VERSION 2
+
+/* Time measurement as far as the code size allows us to do this */
+#define UBI_TIMESTAMPS 16
+
+/**
+ * struct ubi_scan_info - RAM table filled by IPL scan
+ *
+ * @version: Version of the structure
+ * @bootstatus: Boot status of the current boot
+ * @flashtype: Flash type (NAND/NOR)
+ * @flashid: ID of the flash chip
+ * @flashmfr: Manufacturer ID of the flash chip
+ * @flashsize: Size of the FLASH
+ * @blocksize: Eraseblock size
+ * @blockshift: Shift count to calc block number from offset
+ * @nrblocks: Number of erase blocks on flash
+ * @pagesize: Pagesize (NAND)
+ * @blockinfo: Pointer to an array of block status information
+ * filled by FLASH scan
+ * @images: Pointer to FLASH block translation table sorted
+ * by image type and load order
+ * @imageblocks: Number of blocks found per image
+ * @imageoffs: Offset per imagetype to the first
+ * block in the translation table
+ * @imagedups duplicate blocks (max. one per volume)
+ * @imagelen: Length of the loaded image
+ * @crc32_table: CRC32 table buffer
+ * @page_buf: Page buffer for NAND FLASH
+ */
+struct ubi_scan_info {
+ int version;
+ unsigned int bootstatus;
+ unsigned int flashtype;
+ unsigned int flashid;
+ unsigned int flashmfr;
+ unsigned int flashsize;
+ unsigned int blocksize;
+ unsigned int blockshift;
+ unsigned int nrblocks;
+ unsigned int pagesize;
+
+ struct ubi_vid_hdr *blockinfo;
+ struct ubi_vid_hdr **images;
+ unsigned int imageblocks[UBI_BLOCK_IDENT_MAX];
+ unsigned int imageoffs[UBI_BLOCK_IDENT_MAX];
+ struct ubi_vid_hdr *imagedups[UBI_BLOCK_IDENT_MAX];
+ unsigned int imagelen;
+ uint32_t crc32_table[CRC32_TABLE_SIZE];
+ uint8_t page_buf[NAND_READ_BUF_SIZE];
+ unsigned int times[UBI_TIMESTAMPS];
+};
+
+/* External function definition */
+extern int flash_read(void *buf, unsigned int offs, int len);
+extern int flash_read_slice(struct ubi_scan_info *fi, void *buf,
+ unsigned int offs, int len);
+extern void ipl_main(struct ubi_scan_info *fi);
+
+#ifndef CFG_EXAMPLE_IPL
+extern int ipl_scan(struct ubi_scan_info *fi);
+extern int ipl_load(struct ubi_scan_info *fi, int nr, uint8_t *loadaddr);
+
+#define IPL_STATIC
+
+#else
+#define IPL_STATIC static
+#endif
+
+/**
+ * get_boot_status - get the boot status register
+ *
+ * Shift the lower 16 bit into the upper 16 bit and return
+ * the result.
+ */
+uint32_t get_boot_status(void);
+
+/**
+ * set_boot_status - Set the boot status register
+ *
+ * @status: The status value to set
+ *
+ */
+void set_boot_status(uint32_t status);
+
+static inline unsigned int ubi_vid_offset(struct ubi_scan_info *fi)
+{
+ if (fi->flashtype == FLASH_TYPE_NOR)
+ return UBI_EC_HDR_SIZE;
+ else
+ return fi->pagesize - UBI_VID_HDR_SIZE;
+}
+
+static inline unsigned int ubi_data_offset(struct ubi_scan_info *fi)
+{
+ if (fi->flashtype == FLASH_TYPE_NOR)
+ return UBI_EC_HDR_SIZE + UBI_VID_HDR_SIZE;
+ else
+ return fi->pagesize;
+}
+
+/**
+ * IPL checkpoints
+ */
+#define CHKP_HWINIT 0x3030
+#define CHKP_IPLSCAN_FAILED 0x3034
+#define CHKP_SPL_START 0x3037
+#define CHKP_SPLLOAD_STATUS 0x3130
+
+extern void checkpoint(uint32_t cpoint);
+extern void switch_watchdog(void);
+
+#endif
diff --git a/ubi-utils/src/ubiinfo/ubiinfo.c b/ubi-utils/src/ubiinfo/ubiinfo.c
new file mode 100644
index 0000000..6f7443b
--- /dev/null
+++ b/ubi-utils/src/ubiinfo/ubiinfo.c
@@ -0,0 +1,406 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program 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.
+ *
+ * This program 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Print out information about the UBI table this IPL is using. This
+ * can be used afterwards to analyze misbehavior of the IPL code. The
+ * input this program requires is the last 1 MiB DDRAM of our system
+ * where the scanning table is placed into.
+ *
+ * Author: Frank Haverkamp <haver@vnet.ibm.com>
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <argp.h>
+#include <getopt.h>
+#include <stdint.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+
+#define __unused __attribute__((unused))
+
+/* This should hopefully be constant and the same in all
+ * configurations.
+ */
+#define CFG_IPLSIZE 512
+#define CFG_SPLCODE 512
+#define MEMTOP 0x06600000 /* Sunray 102 MiB */
+#define MEMSIZE 0x00100000 /* 1 MiB */
+#define CODE_SIZE (64 * 1024)
+
+/* FIXME Except of the memory size this should be defined via
+ * parameters
+ *
+ * CFG_MEMTOP_BAMBOO 0x02000000
+ * CFG_MEMTOP_SUNRAY 0x06600000
+ */
+
+#include "ubiipl.h"
+#include "ubiflash.h"
+
+#define MIN(x,y) ((x)<(y)?(x):(y))
+
+#define ERR_RET(rc) { \
+ fprintf(stderr, "%s:%d failed rc=%d\n", __func__, \
+ __LINE__, (rc)); \
+ return (rc); \
+ }
+
+#define VERSION "1.3"
+
+static error_t parse_opt (int key, char *arg, struct argp_state *state);
+const char *argp_program_version = VERSION;
+const char *argp_program_bug_address = "<haver@vnet.ibm.com>";
+
+static char doc[] = "\nVersion: " VERSION "\n\t"
+ " at "__DATE__" "__TIME__"\n"
+ "\n"
+ "Test program\n";
+
+static struct argp_option options[] = {
+ /* common settings */
+ { .name = "verbose",
+ .key = 'v',
+ .arg = "<level>",
+ .flags = 0,
+ .doc = "Set verbosity level to <level>",
+ .group = OPTION_ARG_OPTIONAL },
+
+ { .name = "memtop",
+ .key = 'm',
+ .arg = "<memtop>",
+ .flags = 0,
+ .doc = "Set top of memory, 102 MiB for Sunray and 16 MiB for Bamboo",
+ .group = OPTION_ARG_OPTIONAL },
+
+ { .name = NULL,
+ .key = 0,
+ .arg = NULL,
+ .flags = 0,
+ .doc = NULL,
+ .group = 0 },
+};
+
+typedef struct test_args {
+ int verbose;
+ unsigned long memtop;
+ char *arg1;
+ char **options;
+} test_args;
+
+static struct test_args g_args = {
+ .memtop = MEMTOP,
+ .verbose = 0,
+ .arg1 = NULL,
+ .options = NULL,
+};
+
+static struct argp argp = {
+ options: options,
+ parser: parse_opt,
+ args_doc: "[last_1MiB_memory.bin]",
+ doc: doc,
+ children: NULL,
+ help_filter: NULL,
+ argp_domain: NULL,
+};
+
+static int verbose = 0;
+
+/**
+ * @brief Parse the arguments passed into the test case.
+ *
+ * @param key The parameter.
+ * @param arg Argument passed to parameter.
+ * @param state Location to put information on parameters.
+ *
+ * @return error_t
+ */
+static error_t
+parse_opt(int key, char *arg, struct argp_state *state)
+{
+ /* Get the `input' argument from `argp_parse', which we
+ know is a pointer to our arguments structure. */
+ test_args *args = state->input;
+
+ switch (key) {
+ /* common settings */
+ case 'v': /* --verbose=<level> */
+ verbose = args->verbose = strtoul(arg, (char **)NULL, 0);
+ break;
+
+ case 'm': /* --memtop */
+ args->memtop = strtoul(arg, (char **)NULL, 0);
+ break;
+
+ case ARGP_KEY_NO_ARGS:
+ /* argp_usage(state); */
+ break;
+
+ case ARGP_KEY_ARG:
+ args->arg1 = arg;
+ /* Now we consume all the rest of the arguments.
+ `state->next' is the index in `state->argv' of the
+ next argument to be parsed, which is the first STRING
+ we're interested in, so we can just use
+ `&state->argv[state->next]' as the value for
+ arguments->strings.
+
+ _In addition_, by setting `state->next' to the end
+ of the arguments, we can force argp to stop parsing
+ here and return. */
+
+ args->options = &state->argv[state->next];
+ state->next = state->argc;
+ break;
+
+ case ARGP_KEY_END:
+ /* print out message if no arguments are given but PFI
+ write should be done */
+ break;
+
+ default:
+ return(ARGP_ERR_UNKNOWN);
+ }
+ return 0;
+}
+
+static void
+hexdump(const char *buf, int len)
+{
+ char line[16];
+ char str[256];
+ char dummy[256];
+ int j = 0;
+
+ while (len > 0) {
+ int i;
+
+ strcpy(str, " ");
+
+ for (j = 0; j < MIN(16, len); j++)
+ line[j] = *buf++;
+
+ for (i = 0; i < j; i++) {
+ if (!(i & 3)) {
+ sprintf(dummy, " %.2x", line[i] & 0xff);
+ strcat(str, dummy);
+ } else {
+ sprintf(dummy, "%.2x", line[i] & 0xff);
+ strcat(str, dummy);
+ }
+ }
+
+ /* Print empty space */
+ for (; i < 16; i++)
+ if (!(i & 1))
+ strcat(str, " ");
+ else
+ strcat(str, " ");
+
+ strcat(str, " ");
+ for (i = 0; i < j; i++) {
+ if (isprint(line[i])) {
+ sprintf(dummy, "%c", line[i]);
+ strcat(str, dummy);
+ } else {
+ strcat(str, ".");
+ }
+ }
+ printf("%s\n", str);
+ len -= 16;
+ }
+}
+
+static void
+print_status_help(void)
+{
+ printf("Error Codes from IPL\n");
+ printf(" IO Error %d\n", STAT_IO_FAILED);
+ printf(" Block is bad %d\n", STAT_BLOCK_BAD);
+ printf(" ECC unrec error %d\n", STAT_ECC_ERROR);
+ printf(" CRC csum failed %d\n", STAT_CRC_ERROR);
+ printf(" Magic not avail %d\n", STAT_NO_MAGIC);
+ printf(" No image avail %d\n", STAT_NO_IMAGE);
+ printf(" Image is invalid %d\n", STAT_INVALID_IMAGE);
+ printf(" Image is defect %d\n\n", STAT_DEFECT_IMAGE);
+
+}
+
+static void
+print_ubi_scan_info(struct ubi_scan_info *fi)
+{
+ int i;
+
+ printf("ubi_scan_info\n");
+ printf(" version %08x\n", ntohl(fi->version));
+ printf(" bootstatus %08x\n", ntohl(fi->bootstatus));
+ printf(" flashtype %08x\n", ntohl(fi->flashtype));
+ printf(" flashid %08x\n", ntohl(fi->flashid));
+ printf(" flashmfgr %08x\n", ntohl(fi->flashmfr));
+ printf(" flashsize %d bytes (%dM)\n",
+ ntohl(fi->flashsize), ntohl(fi->flashsize) / (1024 * 1024));
+ printf(" blocksize %d bytes\n", ntohl(fi->blocksize));
+ printf(" blockshift %d\n", ntohl(fi->blockshift));
+ printf(" nrblocks %d\n", ntohl(fi->nrblocks));
+ printf(" pagesize %d\n", ntohl(fi->pagesize));
+ printf(" imagelen %d\n", ntohl(fi->imagelen));
+ printf(" blockinfo %08x\n", ntohl((int)fi->blockinfo));
+
+ printf(" nr imageblocks imageoffs\n");
+ for (i = 0; i < UBI_BLOCK_IDENT_MAX; i++)
+ printf(" [%2d] %08x %08x\n", i,
+ ntohl(fi->imageblocks[i]),
+ ntohl(fi->imageoffs[i]));
+
+ for (i = 0; i < UBI_TIMESTAMPS; i++) {
+ if (!ntohl(fi->times[i]))
+ continue;
+ printf("time[%3d] = %08x %.3f sec\n", i, ntohl(fi->times[i]),
+ (double)ntohl(fi->times[i]) / 500000000.0);
+ }
+
+ printf("crc32_table\n");
+ hexdump((char *)&fi->crc32_table, sizeof(fi->crc32_table));
+ printf("\npage_buf\n");
+ hexdump((char *)&fi->page_buf, sizeof(fi->page_buf));
+
+ printf("\n");
+
+}
+
+static void
+print_ubi_block_info(struct ubi_scan_info *fi,
+ struct ubi_vid_hdr *bi, int nr)
+{
+ int i;
+ int unknown = 0;
+
+ printf("\nBINFO\n");
+
+ for (i = 0; i < nr; i++) {
+ if ((int)ubi32_to_cpu(bi[i].magic) != UBI_VID_HDR_MAGIC) {
+ printf("block=%d %08x\n",
+ i, i * ntohl(fi->blocksize));
+#if 0
+ printf(".");
+ if ((unknown & 0x3f) == 0x3f)
+ printf("\n");
+ unknown++;
+#else
+ hexdump((char *)&bi[i],
+ sizeof(struct ubi_vid_hdr));
+#endif
+ } else {
+ if (unknown)
+ printf("\n");
+ printf("block=%d %08x\n"
+ " leb_ver=0x%x data_size=%d "
+ "lnum=%d used_ebs=0x%x\n"
+ " data_crc=%08x hdr_crc=%08x\n",
+ i, i * ntohl(fi->blocksize),
+ ubi32_to_cpu(bi[i].leb_ver),
+ ubi32_to_cpu(bi[i].data_size),
+ ubi32_to_cpu(bi[i].lnum),
+ ubi32_to_cpu(bi[i].used_ebs),
+ ubi32_to_cpu(bi[i].data_crc),
+ ubi32_to_cpu(bi[i].hdr_crc));
+ hexdump((char *)&bi[i],
+ sizeof(struct ubi_vid_hdr));
+ unknown = 0;
+ }
+ }
+}
+
+static int do_read(unsigned int memtop, char *buf, int buf_len __unused)
+{
+ unsigned long finfo_addr;
+ unsigned long binfo_addr;
+ unsigned long images_addr;
+ unsigned long nrblocks;
+ unsigned long bi_size;
+ unsigned long images_size;
+ struct ubi_scan_info *fi;
+ struct ubi_vid_hdr *bi;
+ char *images;
+ unsigned long memaddr = memtop - MEMSIZE;
+
+ print_status_help();
+
+ /* Read and print FINFO */
+ finfo_addr = MEMSIZE - CFG_IPLSIZE * 1024;
+
+ printf("read info at addr %08lx\n", finfo_addr);
+ fi = (struct ubi_scan_info *)(buf + finfo_addr);
+
+ binfo_addr = ntohl((unsigned long)fi->blockinfo) - memaddr;
+ images_addr = ntohl((unsigned long)fi->images) - memaddr;
+ nrblocks = ntohl(fi->nrblocks);
+
+ printf("BINFO %08lx\n", binfo_addr);
+
+ bi_size = nrblocks * sizeof(struct ubi_vid_hdr);
+ images_size = nrblocks * sizeof(unsigned int);
+
+ printf("FINFO\n");
+ print_ubi_scan_info(fi);
+ /* hexdump((char *)fi, sizeof(*fi)); */
+
+ /* Read and print BINFO */
+ bi = (struct ubi_vid_hdr *)(buf + binfo_addr);
+ print_ubi_block_info(fi, bi, nrblocks);
+
+ /* Read and print IMAGES */
+ images = buf + images_addr;
+ printf("\nIMAGES\n");
+ hexdump(images, images_size);
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ char buf[MEMSIZE];
+ FILE *fp;
+ int rc;
+
+ argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &g_args);
+
+ if (!g_args.arg1) {
+ fprintf(stderr, "Please specify a file "
+ "name for memory dump!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ memset(buf, 0xAB, sizeof(buf));
+
+ fp = fopen(g_args.arg1, "r");
+ if (!fp)
+ exit(EXIT_FAILURE);
+ rc = fread(buf, 1, sizeof(buf), fp);
+ if (rc != sizeof(buf))
+ exit(EXIT_FAILURE);
+ fclose(fp);
+ do_read(g_args.memtop, buf, sizeof(buf));
+
+ exit(EXIT_SUCCESS);
+}
diff --git a/ubi-utils/src/ubiinfo/ubiipl.h b/ubi-utils/src/ubiinfo/ubiipl.h
new file mode 100644
index 0000000..3a8b900
--- /dev/null
+++ b/ubi-utils/src/ubiinfo/ubiipl.h
@@ -0,0 +1,87 @@
+#ifndef _UBI_IPL_H
+#define _UBI_IPL_H
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program 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.
+ *
+ * This program 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Constants calculated from the CFG_XXX defines
+ *
+ * Declaration of the loader function which is invoked by the
+ * assembler part of the IPL
+ */
+
+/* Size of IPL - is 4K for NAND and can also be 4K for NOR */
+#define IPL_SIZE 4096
+
+/* Needed in asm code to upload the data, needed in C-code for CRC32 */
+#define IPL_RAMADDR (CFG_MEMTOP - IPL_SIZE)
+
+#if !defined(__ASSEMBLY__)
+
+#include <stdint.h>
+#include <mtd/ubi-header.h>
+
+/* Address of the flash info structure */
+#define FINFO_ADDR (struct ubi_scan_info *) (CFG_MEMTOP - CFG_IPLSIZE * 1024)
+
+/* Size of the flash info structure */
+#define FINFO_SIZE sizeof(struct ubi_scan_info)
+
+/* Blockinfo array address */
+#define BINFO_ADDR (struct ubi_vid_hdr *) ((void *)FINFO_ADDR + FINFO_SIZE)
+
+/* Number of erase blocks */
+#define NR_ERASE_BLOCKS ((CFG_FLASHSIZE * 1024) / CFG_BLOCKSIZE)
+
+/* Blockinfo size */
+#define BINFO_SIZE (NR_ERASE_BLOCKS * sizeof(struct ubi_vid_hdr))
+
+/* Images array address */
+#define IMAGES_ADDR (struct ubi_vid_hdr **) ((void *)BINFO_ADDR + BINFO_SIZE)
+
+/* Images array size */
+#define IMAGES_SIZE (NR_ERASE_BLOCKS * sizeof(unsigned int))
+
+/* Total size of flash info + blockinfo + images */
+#define INFO_SIZE ((FINFO_SIZE + BINFO_SIZE + IMAGES_SIZE) / sizeof(uint32_t))
+
+/* Load address of the SPL */
+#define SPL_ADDR (void *) ((void *)FINFO_ADDR - CFG_SPLCODE * 1024)
+
+#define IPL_SIZE_CRC32 (IPL_SIZE - sizeof(uint32_t))
+#define IPL_RAMADDR_CRC32 ((void *)(IPL_RAMADDR + sizeof(uint32_t)))
+
+/*
+ * Linker script magic to ensure that load_spl() is linked to the
+ * right place
+ */
+#define __crc32 __attribute__((__section__(".crc32")))
+#define __entry __attribute__((__section__(".entry.text")))
+#define __unused __attribute__((unused))
+
+#define MIN(x,y) ((x)<(y)?(x):(y))
+
+#define stop_on_error(x) \
+ { while (1); }
+
+void __entry load_spl(void);
+void hardware_init(void);
+
+#endif /* __ASSEMBLY__ */
+
+#endif