nt9856x/rtos/code/application/source/cardv/SrcCode/System/sys_linuxboot.c

1241 lines
35 KiB
C
Executable File

#include <kwrap/type.h>
#include <kwrap/cpu.h>
#include <kwrap/perf.h>
#include <hdal.h>
#include <libfdt.h>
#include <compiler.h>
#include <rtosfdt.h>
#include <nvtpack.h>
#include <hwclock.h>
#include <plat/cpu.h>
#include <FwSrvApi.h>
#include <zlib.h>
#include <FreeRTOS_POSIX.h>
#include <FreeRTOS_POSIX/pthread.h>
#include "PrjCfg.h"
#include "sys_storage_partition.h"
#include "sys_linuxboot.h"
#include "sys_fdt.h"
#include <kwrap/debug.h>
#include <kwrap/util.h>
#include <arm_gic.h>
#include <FileSysTsk.h>
#include <shm_info.h>
#include "DxHunting.h"
#if HUNTING_CAMERA_MCU == ENABLE
#include "sf_mcu.h"
#endif
#define CFG_BOOTARG_EXTRA_MAX_LEN 0x100 /* for init.d script parsing by (dmesg | grep xxx) */
#define CFG_INDEP_RAMDISK ENABLE
#define CFG_LINUX_START_OFFSET 0x8000
#define CFG_BOOTARG_MAX_LEN 0x1000
#define CFG_LINUX_MAX_CODE_SIZE 0x01000000 //for 64MB dram, assume linux (ro+rw+bss) limited on this size
//#define CFG_LINUX_COMP_MAX_SIZE 0xA00000 //max uImage size
//#define CFG_RAMFS_COMP_MAX_SIZE 0x500000 //max ramdisk size
#define CFG_LINUX_COMP_MAX_SIZE 0x300000 //max uImage size
#define CFG_RAMFS_COMP_MAX_SIZE 0x320000 //max ramdisk size
#define CFG_MULTI_MKIMAGE_LEN 0x8 //mkimage's multi image always comes 8 bytes for sub-image size
#define CFG_GZ_WORK_SIZE 0x10000 //64KB are enough
#define CFG_CORE2_ENTRY_REG 0xF07F8000
#ifndef CONFIG_SYS_FDT_PAD
#define CONFIG_SYS_FDT_PAD 0x3000 // from uboot
#endif
#define CACHE_LINE 32
#define MEM_PATH_LINUX "/memory"
#define MEM_PATH_DRAM "/nvt_memory_cfg/dram"
#define MEM_PATH_LINUXTMP "/nvt_memory_cfg/linuxtmp"
#define MEM_PATH_BRIDGE "/nvt_memory_cfg/bridge"
#define MEM_PATH_FDT "/nvt_memory_cfg/fdt"
#define MEM_PATH_RTOS "/nvt_memory_cfg/rtos"
#define MEM_PATH_HDAL "/hdal-memory/media"
#define MEM_PATH_SHMEM SHMEM_PATH
// sync from uboot
#define CONFIG_BOOTARGS_COMMON "earlyprintk console=ttyS0,115200 rootwait nprofile_irq_duration=on rtos_boot=on "
#if defined(_NVT_ROOTFS_TYPE_RAMDISK_)
#define CONFIG_BOOTARGS CONFIG_BOOTARGS_COMMON "root=/dev/ram0 rootfstype=ramfs rdinit=/linuxrc "
#elif defined(_NVT_ROOTFS_TYPE_NAND_UBI_)
#define CONFIG_BOOTARGS CONFIG_BOOTARGS_COMMON "root=ubi0:rootfs rootfstype=ubifs ubi.fm_autoconvert=1 init=/linuxrc "
#elif defined(_NVT_ROOTFS_TYPE_SQUASH_)
#define CONFIG_BOOTARGS CONFIG_BOOTARGS_COMMON "rootfstype=squashfs ro "
#elif defined(_NVT_ROOTFS_TYPE_NAND_JFFS2_)
#define CONFIG_BOOTARGS CONFIG_BOOTARGS_COMMON "rootfstype=jffs2 rw "
#elif defined(_NVT_ROOTFS_TYPE_NOR_JFFS2_)
#define CONFIG_BOOTARGS CONFIG_BOOTARGS_COMMON "rootfstype=jffs2 rw "
#elif defined(_NVT_ROOTFS_TYPE_EMMC_)
#define CONFIG_BOOTARGS CONFIG_BOOTARGS_COMMON "rootfstype=ext4 rw "
#else //SD
#define CONFIG_BOOTARGS CONFIG_BOOTARGS_COMMON "root=/dev/mmcblk0p2 noinitrd rootfstype=ext3 init=/linuxrc "
#endif /* _NVT_ROOTFS_TYPE_ */
/*
* Legacy format image header,
* all data in network byte order (aka natural aka bigendian).
*/
#define IH_MAGIC 0x27051956 /* Image Magic Number */
#define IH_NMLEN 32 /* Image Name Length */
typedef struct image_header {
unsigned int ih_magic; /* Image Header Magic Number */
unsigned int ih_hcrc; /* Image Header CRC Checksum */
unsigned int ih_time; /* Image Creation Timestamp */
unsigned int ih_size; /* Image Data Size */
unsigned int ih_load; /* Data Load Address */
unsigned int ih_ep; /* Entry Point Address */
unsigned int ih_dcrc; /* Image Data CRC Checksum */
unsigned char ih_os; /* Operating System */
unsigned char ih_arch; /* CPU architecture */
unsigned char ih_type; /* Image Type */
unsigned char ih_comp; /* Compression Type */
unsigned char ih_name[IH_NMLEN]; /* Image Name */
} image_header_t;
typedef struct _GZ_BUF {
unsigned char *p_begin;
unsigned char *p_curr;
unsigned char *p_end;
} GZ_BUF;
typedef struct _UNGZIP_INPUT {
unsigned char *in;
unsigned char *out;
unsigned int insize;
unsigned int outsize;
GZ_BUF gz_buf; //only for CFG_CORE2_DECOMP_RAMDISK
} UNGZIP_INPUT;
typedef enum _RAMDISK_METHOD {
RAMDISK_METHOD_PARTIAL, ///< partial load and decompress
RAMDISK_METHOD_FULL, ///< full loaded the decompress by thread
RAMDISK_METHOD_CORE2, ///< for dual core only, use core2 decompress
RAMDISK_METHOD_NVTPACK, ///< boot linux from all-in-one on sd card
} RAMDISK_METHOD;
#if (CFG_INDEP_RAMDISK)
#if defined(_NVT_LINUX_COMPRESS_NONE_)
static RAMDISK_METHOD ramdisk_methold = RAMDISK_METHOD_FULL;
#elif 0 //defined(_NVT_LINUX_SMP_ON_)
static RAMDISK_METHOD ramdisk_methold = RAMDISK_METHOD_CORE2;
#else // default use partial decompress
static RAMDISK_METHOD ramdisk_methold = RAMDISK_METHOD_PARTIAL;
#endif
#endif //#if (CFG_INDEP_RAMDISK)
#if (CFG_INDEP_RAMDISK)
static pthread_t handle_unzip_ramdisk;
_ALIGNED(64) static UNGZIP_INPUT ungzip_input = {0};
#endif
#if POWERON_FAST_BOOT_MSG == ENABLE
#define LINUX_BOOT_MSG(fmt, args...) DBG_DUMP(fmt, args)
#else
#define LINUX_BOOT_MSG(fmt, args...)
#endif
static char extra_bootarg[CFG_BOOTARG_EXTRA_MAX_LEN] = {'\0'};
static int fdt_find_or_add_subnode(void *fdt, int parentoffset, const char *name)
{
int offset;
offset = fdt_subnode_offset(fdt, parentoffset, name);
if (offset == -FDT_ERR_NOTFOUND)
offset = fdt_add_subnode(fdt, parentoffset, name);
if (offset < 0)
printf("%s: %s: %s\n", __func__, name, fdt_strerror(offset));
return offset;
}
static int fdt_chosen(LINUXTMP_PARTITION *p_linuxtmp)
{
int nodeoffset;
int err;
char *str; /* used to set string properties */
void *fdt = (void *)p_linuxtmp->fdt_addr;
#if (((_PACKAGE_DISPLAY_) || (_PACKAGE_BOOTLOGO_)) && (!defined(_disp_off_)))
fdt32_t value=0x1;
#endif
err = fdt_check_header(fdt);
if (err < 0) {
DBG_DUMP("fdt_chosen: %s\n", fdt_strerror(err));
return err;
}
/* find or create "/chosen" node. */
nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen");
if (nodeoffset < 0)
return nodeoffset;
str = (char *)p_linuxtmp->bootargs_addr;
if (str) {
err = fdt_setprop(fdt, nodeoffset, "bootargs", str,
strlen(str) + 1);
if (err < 0) {
DBG_DUMP("WARNING: could not set bootargs %s.\n",
fdt_strerror(err));
return err;
}
}
if(p_linuxtmp->ramfs_addr) {
fdt32_t tmp = cpu_to_fdt32(p_linuxtmp->ramfs_addr);
err = fdt_setprop(fdt, nodeoffset, "linux,initrd-start", &tmp, sizeof(tmp));
if (err < 0) {
DBG_DUMP("WARNING: could not set initrd-start %s.\n",
fdt_strerror(err));
return err;
}
tmp = cpu_to_fdt32(p_linuxtmp->ramfs_addr + p_linuxtmp->ramfs_size);
err = fdt_setprop(fdt, nodeoffset, "linux,initrd-end", &tmp, sizeof(tmp));
if (err < 0) {
DBG_DUMP("WARNING: could not set initrd-end %s.\n",
fdt_strerror(err));
return err;
}
}
#if (((_PACKAGE_DISPLAY_) || (_PACKAGE_BOOTLOGO_)) && (!defined(_disp_off_)))
nodeoffset = fdt_path_offset((const void*)fdt, "/logo");
if (nodeoffset >= 0) {
value = cpu_to_fdt32(value);
fdt_setprop(fdt, nodeoffset, "enable", &value, sizeof(value));
}
#endif
return 0;
}
static int fdt_read_mem_node(const char *path, unsigned int *p_addr, unsigned int *p_size)
{
unsigned char *p_fdt = (unsigned char *)fdt_get_base();
if (p_fdt == NULL) {
DBG_ERR("p_fdt is NULL.\n");
return -1;
}
int len;
int nodeoffset;
const void *nodep; /* property node pointer */
// get linux space
nodeoffset = fdt_path_offset(p_fdt, path);
if (nodeoffset < 0) {
DBG_ERR("failed to offset for %s = %d \n", path, nodeoffset);
return -1;
}
nodep = fdt_getprop(p_fdt, nodeoffset, "reg", &len);
if (len == 0 || nodep == NULL) {
DBG_ERR("failed to access reg.\n");
return -1;
} else {
unsigned int *p_data = (unsigned int *)nodep;
*p_addr = be32_to_cpu(p_data[0]);
*p_size = be32_to_cpu(p_data[1]);
}
return 0;
}
static int fdt_get_info(FDT_INFO *p_info)
{
int er;
if ((er = fdt_read_mem_node(MEM_PATH_LINUX, &p_info->linux_addr, &p_info->linux_size)) != 0) {
return er;
}
if ((er = fdt_read_mem_node(MEM_PATH_LINUXTMP, &p_info->linuxtmp_addr, &p_info->linuxtmp_size)) != 0) {
return er;
}
if ((er = fdt_read_mem_node(MEM_PATH_FDT, &p_info->fdt_addr, &p_info->fdt_size)) != 0) {
return er;
}
if ((er = fdt_read_mem_node(MEM_PATH_RTOS, &p_info->rtos_addr, &p_info->rtos_size)) != 0) {
return er;
}
if ((er = fdt_read_mem_node(MEM_PATH_HDAL, &p_info->hdal_addr, &p_info->hdal_size)) != 0) {
return er;
}
if ((er = fdt_read_mem_node(MEM_PATH_SHMEM, &p_info->shmem_addr, &p_info->shmem_size)) != 0) {
return er;
}
if ((er = fdt_read_mem_node(MEM_PATH_DRAM, &p_info->dram_addr, &p_info->dram_size)) != 0) {
return er;
}
return 0;
}
static int create_new_fdt(LINUXTMP_PARTITION *p_linuxtmp)
{
unsigned char *p_fdt = (unsigned char *)fdt_get_base();
if (p_fdt == NULL) {
DBG_ERR("p_fdt is NULL.\n");
return -1;
}
int new_size = ALIGN_CEIL(fdt_totalsize(p_fdt) + CONFIG_SYS_FDT_PAD, 0x1000);
if (p_linuxtmp->tmp2_begin) {
p_linuxtmp->fdt_addr = p_linuxtmp->tmp2_curr;
p_linuxtmp->fdt_size = new_size;
p_linuxtmp->tmp2_curr += new_size;
} else {
p_linuxtmp->fdt_addr = p_linuxtmp->tmp_curr;
p_linuxtmp->fdt_size = new_size;
p_linuxtmp->tmp_curr += new_size;
}
if (p_linuxtmp->tmp_curr >= p_linuxtmp->tmp_end) {
DBG_ERR("linuxtmp memory is too small, need more %d\n", p_linuxtmp->tmp_curr - p_linuxtmp->tmp_end);
return -1;
}
int err = fdt_open_into(p_fdt, (void *)p_linuxtmp->fdt_addr, new_size);
if (err != 0) {
DBG_ERR("fdt move failed!");
return -1;
}
return 0;
}
#if (CFG_INDEP_RAMDISK)
static void *gzalloc_core2(void *x, unsigned items, unsigned size)
{
void *p = ungzip_input.gz_buf.p_curr;
size *= items;
ungzip_input.gz_buf.p_curr += size;
if (ungzip_input.gz_buf.p_curr > ungzip_input.gz_buf.p_end) {
printf("gz buff not enough.\r\n");
return NULL;
} else {
memset(p, 0, size);
return p;
}
}
#endif
#if (CFG_INDEP_RAMDISK)
static void gzfree_core2(void *x, void *addr, unsigned nb)
{
}
#endif
#if (CFG_INDEP_RAMDISK)
void core2_cb(void)
{
int err;
z_stream stream = {0};
stream.next_in = (z_const Bytef *)ungzip_input.in;
stream.avail_in = ungzip_input.insize;
stream.next_out = (z_const Bytef *)ungzip_input.out;
stream.avail_out = ungzip_input.outsize;
stream.zalloc = (alloc_func)gzalloc_core2;
stream.zfree = (free_func)gzfree_core2;
stream.opaque = (voidpf)0;
err = inflateInit(&stream);
if (err != Z_OK) {
printf("Failed to inflateInit\r\n");
inflateEnd(&stream);
return;
}
err = inflate(&stream, Z_NO_FLUSH);
inflateEnd(&stream);
if (err != Z_STREAM_END) {
printf("Failed to inflate\r\n");
return;
}
// clean cache without invalidate output data
unsigned int cache_begin = (unsigned int)ungzip_input.out;
unsigned int cache_end = ALIGN_CEIL((unsigned int)ungzip_input.out+ungzip_input.outsize, CACHE_LINE);
if ((cache_begin & (CACHE_LINE-1)) != 0) {
printf("target addr not cache aligment\r\n");
return;
}
for (; cache_begin < cache_end; cache_begin+=CACHE_LINE) {
__asm__ __volatile__(
"mcr p15, 0, %0, c7, c10, 1"
:
: "r" (cache_begin)
);
}
// clean cache without invalidate indication byte
*(volatile UINT32 *)CFG_CORE2_ENTRY_REG = (UINT32)0;
__asm__ __volatile__(
"mcr p15, 0, %0, c7, c10, 1"
:
: "r" (CFG_CORE2_ENTRY_REG)
);
}
#endif
#if defined(_NVT_LINUX_COMPRESS_GZ_)
static void *gzalloc_full(void *x, unsigned items, unsigned size)
{
size *= items;
void *p = malloc(size);
if (p) {
memset(p, 0, size);
}
return p;
}
static void gzfree_full(void *x, void *addr, unsigned nb)
{
free(addr);
}
#endif
#if (CFG_INDEP_RAMDISK)
static void *thread_ungzip_ramdisk(void *ptr)
{
int err;
z_stream stream = {0};
stream.next_in = (z_const Bytef *)ungzip_input.in;
stream.avail_in = ungzip_input.insize;
stream.next_out = (z_const Bytef *)ungzip_input.out;
stream.avail_out = ungzip_input.outsize;
#if defined(_NVT_LINUX_COMPRESS_GZ_)
stream.zalloc = (alloc_func)gzalloc_full;
stream.zfree = (free_func)gzfree_full;
#endif
stream.opaque = (voidpf)0;
err = inflateInit(&stream);
if (err != Z_OK) {
DBG_ERR("Failed to inflateInit, err = %d\r\n", err);
inflateEnd(&stream);
pthread_exit((void *)-1);
return NULL;
}
err = inflate(&stream, Z_NO_FLUSH);
inflateEnd(&stream);
if (err == Z_STREAM_END) {
pthread_exit((void *)0);
return NULL;
}
pthread_exit((void *)-1);
return NULL;
}
#endif
#if (CFG_INDEP_RAMDISK)
static int load_ramdisk_core2(LINUXTMP_PARTITION *p_linuxtmp)
{
unsigned int bfc_data = p_linuxtmp->tmp_curr;
STORAGE_OBJ *p_strg = EMB_GETSTRGOBJ(STRG_OBJ_FW_ROOTFS);
if (p_strg == NULL) {
DBG_ERR("failed to get STRG_OBJ_FW_ROOTFS");
return -1;
}
//load 1st block
p_strg->Lock();
p_strg->Open();
if (p_strg->RdSectors((INT8 *)bfc_data, 0, 1) != 0) {
DBG_ERR("RdSectors for ramdisk 1st block\r\n");
return -1;
}
NVTPACK_BFC_HDR *p_hdr = (NVTPACK_BFC_HDR *)bfc_data;
if (p_hdr->uiFourCC != MAKEFOURCC('B','C','L','1')) {
DBG_ERR("BCL1 header is wrong\r\n");
return -1;
}
unsigned int bfc_size = be32_to_cpu(p_hdr->uiSizeComp) + sizeof(NVTPACK_BFC_HDR);
unsigned int comp_ramfs_addr = bfc_data + sizeof(NVTPACK_BFC_HDR);
unsigned int comp_ramfs_size = be32_to_cpu(p_hdr->uiSizeComp);
p_linuxtmp->tmp_curr += ALIGN_CEIL_64(bfc_size);
p_linuxtmp->ramfs_addr = p_linuxtmp->tmp_curr;
p_linuxtmp->ramfs_size = be32_to_cpu(p_hdr->uiSizeUnComp);
p_linuxtmp->tmp_curr = p_linuxtmp->ramfs_addr + ALIGN_CEIL_64(p_linuxtmp->ramfs_size);
// load rest of image data
unsigned int block_size = 0;
p_strg->GetParam(STRG_GET_BEST_ACCESS_SIZE, (UINT32)&block_size, 0);
if (block_size == 0) {
DBG_ERR("block_size is 0.\n");
return -1;
}
unsigned int remain_blocks = ALIGN_CEIL(bfc_size - block_size, block_size)/block_size;
if (p_strg->RdSectors((INT8 *)(bfc_data+block_size), 1, remain_blocks) != 0) {
DBG_ERR("RdSectors for ramdisk\r\n");
return -1;
}
p_strg->Close();
p_strg->Unlock();
//uncompress
ungzip_input.in = (unsigned char*)comp_ramfs_addr;
ungzip_input.out = (unsigned char*)p_linuxtmp->ramfs_addr;
ungzip_input.insize = comp_ramfs_size;
ungzip_input.outsize = p_linuxtmp->ramfs_size;
ungzip_input.gz_buf.p_begin = (unsigned char*)malloc(CFG_GZ_WORK_SIZE);
ungzip_input.gz_buf.p_curr = ungzip_input.gz_buf.p_begin;
ungzip_input.gz_buf.p_end = ungzip_input.gz_buf.p_begin + CFG_GZ_WORK_SIZE;
if (ungzip_input.gz_buf.p_begin == NULL) {
DBG_ERR("failed to malloc\n");
return -1;
}
vos_cpu_dcache_sync((VOS_ADDR)&ungzip_input, sizeof(ungzip_input), VOS_DMA_TO_DEVICE);
vos_cpu_dcache_sync((VOS_ADDR)p_linuxtmp->ramfs_addr, p_linuxtmp->ramfs_size, VOS_DMA_TO_DEVICE);
extern void core2_exec(void);
*(volatile UINT32 *)CFG_CORE2_ENTRY_REG = (UINT32)core2_exec;
vos_cpu_dcache_sync(CFG_CORE2_ENTRY_REG, 64, VOS_DMA_TO_DEVICE);
arm_gic_raise_sgi(8, 2);
return 0;
}
#endif
#if (CFG_INDEP_RAMDISK)
static int load_ramdisk_partial(LINUXTMP_PARTITION *p_linuxtmp)
{
FWSRV_CMD cmd = {0};
MEM_RANGE mem_range = {0};
FWSRV_FASTLOAD fastload = {0};
unsigned int comp_ramfs_addr = p_linuxtmp->tmp_curr;
unsigned int comp_ramfs_size = CFG_RAMFS_COMP_MAX_SIZE;
p_linuxtmp->tmp_curr += comp_ramfs_size;
LINUX_BOOT_MSG("linuxtmp used = %lx, comp_ramfs size = %lx\n", p_linuxtmp->tmp_curr - p_linuxtmp->tmp_begin, comp_ramfs_size);
if (p_linuxtmp->tmp_curr >= p_linuxtmp->tmp_end) {
DBG_ERR("linuxtmp memory is too small, need more %d\n", p_linuxtmp->tmp_curr - p_linuxtmp->tmp_end);
return -1;
}
fastload.pStrg = EMB_GETSTRGOBJ(STRG_OBJ_FW_ROOTFS);
fastload.MemComp.addr = comp_ramfs_addr;
fastload.MemComp.size = comp_ramfs_size;
if (p_linuxtmp->tmp2_begin) {
fastload.MemUnComp.addr = p_linuxtmp->tmp2_curr;
fastload.MemUnComp.size = p_linuxtmp->tmp2_end - p_linuxtmp->tmp2_curr;
} else {
fastload.MemUnComp.addr = p_linuxtmp->tmp_curr;
fastload.MemUnComp.size = p_linuxtmp->tmp_end - p_linuxtmp->tmp_curr;
}
cmd.Idx = FWSRV_CMD_IDX_FASTLOAD;
cmd.In.pData = &fastload;
cmd.In.uiNumByte = sizeof(fastload);
cmd.Out.pData = &mem_range;
cmd.Out.uiNumByte = sizeof(mem_range);
cmd.Prop.bExitCmdFinish = TRUE;
FWSRV_ER er;
if ((er=FwSrv_Open()) != FWSRV_ER_OK) {
DBG_ERR("FwSrv_Open failed!\r\n");
return -1;
}
if ((er=FwSrv_Cmd(&cmd)) != FWSRV_ER_OK) {
DBG_ERR("FwSrv_Cmd failed!\r\n");
return -1;
}
FwSrv_Close();
p_linuxtmp->ramfs_addr = mem_range.addr;
p_linuxtmp->ramfs_size = mem_range.size;
if (p_linuxtmp->tmp2_begin) {
p_linuxtmp->tmp2_curr = p_linuxtmp->ramfs_addr + ALIGN_CEIL_64(p_linuxtmp->ramfs_size);
} else {
p_linuxtmp->tmp_curr = p_linuxtmp->ramfs_addr + ALIGN_CEIL_64(p_linuxtmp->ramfs_size);
}
LINUX_BOOT_MSG("linuxtmp used = %lx, ramfs uncompressed size = %lx\n", p_linuxtmp->tmp_curr - p_linuxtmp->tmp_begin, p_linuxtmp->ramfs_size);
return 0;
}
#endif
#if (CFG_INDEP_RAMDISK)
static int load_ramdisk_full(LINUXTMP_PARTITION *p_linuxtmp)
{
unsigned int bfc_data = p_linuxtmp->tmp_curr;
STORAGE_OBJ *p_strg = EMB_GETSTRGOBJ(STRG_OBJ_FW_ROOTFS);
if (p_strg == NULL) {
DBG_ERR("failed to get STRG_OBJ_FW_ROOTFS");
return -1;
}
//load 1st block
p_strg->Lock();
p_strg->Open();
if (p_strg->RdSectors((INT8 *)bfc_data, 0, 1) != 0) {
DBG_ERR("RdSectors for ramdisk 1st block\r\n");
return -1;
}
NVTPACK_BFC_HDR *p_hdr = (NVTPACK_BFC_HDR *)bfc_data;
if (p_hdr->uiFourCC != MAKEFOURCC('B','C','L','1')) {
DBG_ERR("BCL1 header is wrong\r\n");
return -1;
}
unsigned int bfc_size = be32_to_cpu(p_hdr->uiSizeComp) + sizeof(NVTPACK_BFC_HDR);
unsigned int comp_ramfs_addr = bfc_data + sizeof(NVTPACK_BFC_HDR);
unsigned int comp_ramfs_size = be32_to_cpu(p_hdr->uiSizeComp);
p_linuxtmp->tmp_curr += ALIGN_CEIL_64(bfc_size);
if (p_linuxtmp->tmp2_begin) {
p_linuxtmp->ramfs_addr = p_linuxtmp->tmp2_curr;
p_linuxtmp->ramfs_size = be32_to_cpu(p_hdr->uiSizeUnComp);
p_linuxtmp->tmp2_curr = p_linuxtmp->ramfs_addr + ALIGN_CEIL_64(p_linuxtmp->ramfs_size);
if (p_linuxtmp->tmp2_curr >= p_linuxtmp->tmp2_end) {
DBG_ERR("rootfs is too large, need reduce %d\n", p_linuxtmp->tmp2_curr - p_linuxtmp->tmp2_end);
return -1;
}
} else {
p_linuxtmp->ramfs_addr = p_linuxtmp->tmp_curr;
p_linuxtmp->ramfs_size = be32_to_cpu(p_hdr->uiSizeUnComp);
p_linuxtmp->tmp_curr = p_linuxtmp->ramfs_addr + ALIGN_CEIL_64(p_linuxtmp->ramfs_size);
if (p_linuxtmp->tmp_curr >= p_linuxtmp->tmp_end) {
DBG_ERR("linuxtmp memory is too small, need more %d\n", p_linuxtmp->tmp_curr - p_linuxtmp->tmp_end);
return -1;
}
}
// load rest of image data
unsigned int block_size = 0;
p_strg->GetParam(STRG_GET_BEST_ACCESS_SIZE, (UINT32)&block_size, 0);
if (block_size == 0) {
DBG_ERR("block_size is 0.\n");
return -1;
}
unsigned int remain_blocks = ALIGN_CEIL(bfc_size - block_size, block_size)/block_size;
if (p_strg->RdSectors((INT8 *)(bfc_data+block_size), 1, remain_blocks) != 0) {
DBG_ERR("RdSectors for ramdisk\r\n");
return -1;
}
p_strg->Close();
p_strg->Unlock();
//uncompress
ungzip_input.in = (unsigned char*)comp_ramfs_addr;
ungzip_input.out = (unsigned char*)p_linuxtmp->ramfs_addr;
ungzip_input.insize = comp_ramfs_size;
ungzip_input.outsize = p_linuxtmp->ramfs_size;
int pthread_ret = pthread_create(&handle_unzip_ramdisk, NULL, thread_ungzip_ramdisk , NULL);
if (0 != pthread_ret) {
DBG_ERR("create thread_ungzip_ramdisk failed, ret %d\r\n", pthread_ret);
return -1;
}
return 0;
}
#endif
static int find_index_nvtpack(LINUXTMP_PARTITION *p_linuxtmp, char *partition_name)
{
#if (_PACKAGE_FILESYS_ && _PACKAGE_SDCARD_)
unsigned char *p_fdt = (unsigned char *)fdt_get_base();
if (p_fdt == NULL) {
DBG_ERR("p_fdt is NULL\r\n");
return -1;
}
// find out nvtpack index to partition_rootfs
int i;
char *path_fdt = NULL;
char *pathes_fdt[] = {
"/nor/nvtpack",
"/nand/nvtpack",
"/mmc@f0510000/nvtpack",
};
for (i = 0; i < 3; i++) {
int nodeoffset = fdt_path_offset(p_fdt, pathes_fdt[i]);
if (nodeoffset >= 0) {
path_fdt = pathes_fdt[i];
break;
}
}
if (path_fdt == NULL) {
DBG_ERR("unable to find nvtpack in fdt on sd card\r\n");
return -1;
}
for (i = 0; i < 64; i++) {
char path[64] = {0};
sprintf(path, "%s/index/id%d", path_fdt, i);
int nodeoffset = fdt_path_offset(p_fdt, path);
if (nodeoffset < 0) {
continue;
}
int len = 0;
const void *nodep = fdt_getprop(p_fdt, nodeoffset, "partition_name", &len);
if (nodep == NULL || len == 0) {
continue;
}
if (strncmp((const char *)nodep, partition_name, len) == 0) {
return i;
}
}
return -1;
#else
DBG_ERR("unsupported\r\n");
return -1;
#endif
}
#if (CFG_INDEP_RAMDISK)
static int load_ramdisk_nvtpack(LINUXTMP_PARTITION *p_linuxtmp)
{
#if (_PACKAGE_FILESYS_ && _PACKAGE_SDCARD_)
NVTPACK_ER er;
NVTPACK_GET_PARTITION_INPUT np_get_input;
NVTPACK_MEM mem_in = {(void *)p_linuxtmp->nvtpack_addr, (unsigned int)p_linuxtmp->nvtpack_size};
int nvtpack_rootfs_index = find_index_nvtpack(p_linuxtmp, "rootfs");
if (nvtpack_rootfs_index== -1) {
DBG_ERR("unable to find rootfs-nvtpack-index in fdt on sd card\r\n");
return -1;
}
NVTPACK_MEM rootfs_mem;
np_get_input.id = nvtpack_rootfs_index;
np_get_input.mem = mem_in;
er = nvtpack_get_partition(&np_get_input, &rootfs_mem);
if (er == NVTPACK_ER_NOT_FOUND) {
DBG_ERR("unable to find rootfs in all-in-one\r\n");
return -1;
}
NVTPACK_CHKSUM_HDR *p_sum = (NVTPACK_CHKSUM_HDR *)rootfs_mem.p_data;
if (p_sum->uiFourCC != MAKEFOURCC('C','K','S','M')) {
DBG_ERR("CKSM header is wrong on sd card\r\n");
return -1;
}
NVTPACK_BFC_HDR *p_hdr = (NVTPACK_BFC_HDR *)&p_sum[1];
if (p_hdr->uiFourCC != MAKEFOURCC('B','C','L','1')) {
DBG_ERR("rootfs BCL1 header is wrong on sd card\r\n");
return -1;
}
unsigned int comp_ramfs_addr = (unsigned int)&p_hdr[1];
unsigned int comp_ramfs_size = be32_to_cpu(p_hdr->uiSizeComp);
p_linuxtmp->ramfs_addr = p_linuxtmp->tmp_curr;
p_linuxtmp->ramfs_size = be32_to_cpu(p_hdr->uiSizeUnComp);
p_linuxtmp->tmp_curr = p_linuxtmp->ramfs_addr + ALIGN_CEIL_64(p_linuxtmp->ramfs_size);
if (p_linuxtmp->tmp_curr >= p_linuxtmp->tmp_end) {
DBG_ERR("linuxtmp memory is too small, need more %d\n", p_linuxtmp->tmp_curr - p_linuxtmp->tmp_end);
return -1;
}
//uncompress
ungzip_input.in = (unsigned char*)comp_ramfs_addr;
ungzip_input.out = (unsigned char*)p_linuxtmp->ramfs_addr;
ungzip_input.insize = comp_ramfs_size;
ungzip_input.outsize = p_linuxtmp->ramfs_size;
int pthread_ret = pthread_create(&handle_unzip_ramdisk, NULL, thread_ungzip_ramdisk , NULL);
if (0 != pthread_ret) {
DBG_ERR("create thread_ungzip_ramdisk failed, ret %d\r\n", pthread_ret);
return -1;
}
return 0;
#else
DBG_ERR("unsupported\r\n");
return -1;
#endif
}
#endif
#if (CFG_INDEP_RAMDISK)
static int load_ramdisk(LINUXTMP_PARTITION *p_linuxtmp)
{
switch(ramdisk_methold) {
case RAMDISK_METHOD_PARTIAL:
return load_ramdisk_partial(p_linuxtmp);
case RAMDISK_METHOD_FULL:
return load_ramdisk_full(p_linuxtmp);
case RAMDISK_METHOD_CORE2:
return load_ramdisk_core2(p_linuxtmp);
case RAMDISK_METHOD_NVTPACK:
return load_ramdisk_nvtpack(p_linuxtmp);
default:
DBG_ERR("unknown method: %d\r\n", ramdisk_methold);
return -1;
}
}
#endif
#if (CFG_INDEP_RAMDISK)
static int wait_ramdisk(void)
{
int join_ret;
int pthread_ret;
switch(ramdisk_methold) {
case RAMDISK_METHOD_PARTIAL:
return 0; //partial load + parital decompress have finished on load_ramdisk
case RAMDISK_METHOD_FULL:
case RAMDISK_METHOD_NVTPACK:
pthread_ret = pthread_join(handle_unzip_ramdisk, (void *)&join_ret);
if (0 != pthread_ret) {
DBG_ERR("handle_unzip_ramdisk pthread_join failed, ret %d\r\n", pthread_ret);
return -1;
}
return 0;
case RAMDISK_METHOD_CORE2:
while(*(volatile UINT32 *)CFG_CORE2_ENTRY_REG) {
vos_cpu_dcache_sync(CFG_CORE2_ENTRY_REG, sizeof(UINT32), VOS_DMA_FROM_DEVICE);
};
free(ungzip_input.gz_buf.p_begin);
return 0;
default:
DBG_ERR("unknown method: %d\r\n", ramdisk_methold);
return -1;
}
}
#endif
/* format : "A=B C=D" */
void linuxboot_set_extra_bootarg(char* bootarg)
{
snprintf(extra_bootarg, CFG_BOOTARG_EXTRA_MAX_LEN, bootarg);
}
static int make_bootargs(LINUXTMP_PARTITION *p_linuxtmp, unsigned int bootts_begin)
{
//static char bootargs[] = "root=/dev/ram0 rootfstype=ramfs rdinit=/linuxrc bootts=568047,1720128 resume_addr=0x00007e88 user_debug=0xff";
#if HUNTING_CAMERA_MCU == ENABLE
char PowerOnModeStr[32] = {'\0'};
snprintf(PowerOnModeStr, sizeof(PowerOnModeStr), "Mode=%d",sf_get_power_on_mode());
linuxboot_set_extra_bootarg(PowerOnModeStr);
#endif
p_linuxtmp->bootargs_addr = p_linuxtmp->tmp_curr;
p_linuxtmp->bootargs_size = CFG_BOOTARG_MAX_LEN + CFG_BOOTARG_EXTRA_MAX_LEN;
p_linuxtmp->tmp_curr += p_linuxtmp->bootargs_size;
if (p_linuxtmp->tmp_curr >= p_linuxtmp->tmp_end) {
DBG_ERR("linuxtmp memory is too small, need more %d\n", p_linuxtmp->tmp_curr - p_linuxtmp->tmp_end);
return -1;
}
memset((char *)p_linuxtmp->bootargs_addr, 0, p_linuxtmp->bootargs_size);
snprintf((char *)p_linuxtmp->bootargs_addr, p_linuxtmp->bootargs_size - 1, CONFIG_BOOTARGS "bootts=%u,%u user_debug=0xff %s ", bootts_begin, (unsigned int)hwclock_get_counter(), extra_bootarg);
return 0;
}
static int load_linux_from_flash(LINUXTMP_PARTITION *p_linuxtmp, FDT_INFO *p_fdt_info)
{
#if defined(_NVT_LINUX_COMPRESS_GZ_) //partital load + partial decompress
FWSRV_CMD cmd = {0};
MEM_RANGE mem_range = {0};
FWSRV_FASTLOAD fastload = {0};
p_linuxtmp->lz_linux_addr = p_linuxtmp->tmp_curr;
p_linuxtmp->lz_linux_size = CFG_LINUX_COMP_MAX_SIZE;
p_linuxtmp->tmp_curr += p_linuxtmp->lz_linux_size;
if (p_linuxtmp->tmp_curr >= p_linuxtmp->tmp_end) {
DBG_ERR("linuxtmp memory is too small, need more %d\n", p_linuxtmp->tmp_curr - p_linuxtmp->tmp_end);
return -1;
}
fastload.pStrg = EMB_GETSTRGOBJ(STRG_OBJ_FW_LINUX);
fastload.MemComp.addr = p_linuxtmp->lz_linux_addr;
fastload.MemComp.size = p_linuxtmp->lz_linux_size;
fastload.MemUnComp.addr = p_fdt_info->linux_addr + CFG_LINUX_START_OFFSET;
fastload.MemUnComp.size = p_fdt_info->linux_size - CFG_LINUX_START_OFFSET;
LINUX_BOOT_MSG("*linuxtmp used size = %lx , linux compressed / uncompressed size = %lx / %lx ******\n", p_linuxtmp->tmp_curr - p_linuxtmp->tmp_begin, fastload.MemComp.size, fastload.MemUnComp.size);
cmd.Idx = FWSRV_CMD_IDX_FASTLOAD;
cmd.In.pData = &fastload;
cmd.In.uiNumByte = sizeof(fastload);
cmd.Out.pData = &mem_range;
cmd.Out.uiNumByte = sizeof(mem_range);
cmd.Prop.bExitCmdFinish = TRUE;
FWSRV_ER er;
if ((er=FwSrv_Open()) != FWSRV_ER_OK) {
DBG_ERR("FwSrv_Open failed!\r\n");
return -1;
}
if ((er=FwSrv_Cmd(&cmd)) != FWSRV_ER_OK) {
DBG_ERR("FwSrv_Cmd failed!\r\n");
return -1;
}
FwSrv_Close();
return 0;
#elif defined(_NVT_LINUX_COMPRESS_NONE_) // only full load
unsigned int load_addr = p_fdt_info->linux_addr + CFG_LINUX_START_OFFSET - sizeof(image_header_t) - CFG_MULTI_MKIMAGE_LEN;
STORAGE_OBJ *p_strg = EMB_GETSTRGOBJ(STRG_OBJ_FW_LINUX);
//load 1st block
p_strg->Lock();
p_strg->Open();
if (p_strg->RdSectors((INT8 *)load_addr, 0, 1) != 0) {
DBG_ERR("RdSectors for linux 1st block\r\n");
return -1;
}
image_header_t *p_hdr = (image_header_t *)load_addr;
if (be32_to_cpu(p_hdr->ih_magic) != IH_MAGIC) {
DBG_ERR("IH_MAGIC is wrong\r\n");
return -1;
}
//IH_TYPE_MULTI = 4
if (p_hdr->ih_type != 4) {
DBG_ERR("ih_type != IH_TYPE_MULTI\r\n");
return -1;
}
// load rest of image data
unsigned int image_size = be32_to_cpu(p_hdr->ih_size) + sizeof(image_header_t);
unsigned int block_size = 0;
p_strg->GetParam(STRG_GET_BEST_ACCESS_SIZE, (UINT32)&block_size, 0);
if (block_size == 0) {
DBG_ERR("block_size is 0.\n");
return -1;
}
unsigned int remain_blocks = ALIGN_CEIL(image_size - block_size, block_size)/block_size;
if (p_strg->RdSectors((INT8 *)(load_addr+block_size), 1, remain_blocks) != 0) {
DBG_ERR("RdSectors for linux\r\n");
return -1;
}
p_strg->Close();
p_strg->Unlock();
return 0;
#else
DBG_ERR("unsupported NVT_LINUX_COMPRESS mode.\r\n");
return -1;
#endif
}
static int load_linux_from_nvtpack(LINUXTMP_PARTITION *p_linuxtmp, FDT_INFO *p_fdt_info)
{
NVTPACK_ER er;
NVTPACK_GET_PARTITION_INPUT np_get_input;
NVTPACK_MEM mem_in = {(void *)p_linuxtmp->nvtpack_addr, (unsigned int)p_linuxtmp->nvtpack_size};
int nvtpack_linux_index = find_index_nvtpack(p_linuxtmp, "kernel");
if (nvtpack_linux_index== -1) {
DBG_ERR("unable to find linux-nvtpack-index in fdt on sd card\r\n");
return -1;
}
NVTPACK_MEM linux_mem;
np_get_input.id = nvtpack_linux_index;
np_get_input.mem = mem_in;
er = nvtpack_get_partition(&np_get_input, &linux_mem);
if (er == NVTPACK_ER_NOT_FOUND) {
DBG_ERR("unable to find linux in all-in-one\r\n");
return -1;
}
#if defined(_NVT_LINUX_COMPRESS_GZ_) //partital load + partial decompress
NVTPACK_BFC_HDR *p_hdr = (NVTPACK_BFC_HDR *)linux_mem.p_data;
if (p_hdr->uiFourCC != MAKEFOURCC('B','C','L','1')) {
DBG_ERR("linux BCL1 header is wrong on sd card\r\n");
return -1;
}
int err;
z_stream stream = {0};
stream.next_in = (z_const Bytef *)&p_hdr[1];
stream.avail_in = be32_to_cpu(p_hdr->uiSizeComp);
stream.next_out = (z_const Bytef *)p_fdt_info->linux_addr + CFG_LINUX_START_OFFSET;
stream.avail_out = be32_to_cpu(p_hdr->uiSizeUnComp);
stream.zalloc = (alloc_func)gzalloc_full;
stream.zfree = (free_func)gzfree_full;
stream.opaque = (voidpf)0;
err = inflateInit(&stream);
if (err != Z_OK) {
DBG_ERR("Failed to inflateInit, err = %d\r\n", err);
inflateEnd(&stream);
return -1;
}
err = inflate(&stream, Z_NO_FLUSH);
inflateEnd(&stream);
if (err == Z_STREAM_END) {
return 0;
}
return -1;
#elif defined(_NVT_LINUX_COMPRESS_NONE_) // only full load
unsigned int load_addr = p_fdt_info->linux_addr + CFG_LINUX_START_OFFSET - sizeof(image_header_t) - CFG_MULTI_MKIMAGE_LEN;
image_header_t *p_hdr = (image_header_t *)load_addr;
if (be32_to_cpu(p_hdr->ih_magic) != IH_MAGIC) {
DBG_ERR("IH_MAGIC is wrong\r\n");
return -1;
}
//IH_TYPE_MULTI = 4
if (p_hdr->ih_type != 4) {
DBG_ERR("ih_type != IH_TYPE_MULTI\r\n");
return -1;
}
// load rest of image data
unsigned int image_size = be32_to_cpu(p_hdr->ih_size) + sizeof(image_header_t);
memcpy((void *)load_addr, linux_mem.p_data, image_size);
return 0;
#else
DBG_ERR("unsupported NVT_LINUX_COMPRESS mode.\r\n");
return -1;
#endif
}
static int load_linux(LINUXTMP_PARTITION *p_linuxtmp, FDT_INFO *p_fdt_info)
{
SHMINFO *p_shm = (SHMINFO *)p_fdt_info->shmem_addr;
if ((p_shm->boot.LdCtrl2 & LDCF_BOOT_CARD) == 0) {
return load_linux_from_flash(p_linuxtmp, p_fdt_info);
} else {
return load_linux_from_nvtpack(p_linuxtmp, p_fdt_info);
}
}
static int check_mem_overlap(FDT_INFO *p_fdt_info)
{
//rule1: fdt, rtos, bridge must be in order and continuous
if (p_fdt_info->fdt_addr + p_fdt_info->fdt_size != p_fdt_info->rtos_addr) {
DBG_ERR("in nvt_memory_cfg, the mem of fdt, rtos, bridge must be in order.\r\n");
return -1;
}
//reule 2: (fdt, rtos, bridge cannot be overlapped with linux)
unsigned int mem_begin = p_fdt_info->fdt_addr;
unsigned int mem_end = mem_begin + p_fdt_info->fdt_size + p_fdt_info->rtos_size;
unsigned int linux_begin = p_fdt_info->linux_addr;
unsigned int linux_end = linux_begin + p_fdt_info->linux_size;
if (linux_end > mem_begin && linux_begin < mem_end) {
DBG_ERR("linux mem is overlapped with (fdt+rtos+bridge)\r\n");
return -1;
}
//reule 3: (fdt, rtos, bridge cannot be overlapped with hdal)
unsigned int hdal_begin = p_fdt_info->hdal_addr;
unsigned int hdal_end = hdal_begin + p_fdt_info->hdal_size;
if (hdal_end > mem_begin && hdal_begin < mem_end) {
DBG_ERR("hdal mem is overlapped with (fdt+rtos+bridge)\r\n");
return -1;
}
return 0;
}
#if (_PACKAGE_FILESYS_ && _PACKAGE_SDCARD_)
static int load_nvtpack(LINUXTMP_PARTITION *p_linuxtmp)
{
//polling filesys ready first
int n_retry = 5; // 5 sec
while (n_retry--) {
if (FileSys_WaitFinishEx('A') == FST_STA_OK) {
break;
}
vos_util_delay_ms(1000);
}
char bint_path[] = "A:\\" _BIN_NAME_T_ ".bin";
char bin_path[] = "A:\\" _BIN_NAME_ ".bin";
char *nvtpack_path = bint_path;
FST_FILE h_file = FileSys_OpenFile(bint_path, FST_OPEN_READ);
if (h_file == 0) {
h_file = FileSys_OpenFile(bin_path, FST_OPEN_READ);
nvtpack_path = bin_path;
}
if (h_file == 0) {
DBG_ERR("unable to open %s or %s\r\n", bint_path, bin_path);
return -1;
}
int nvtpack_len = FileSys_GetFileLen(nvtpack_path);
unsigned int alloc_size = ALIGN_CEIL_64(nvtpack_len);
if (p_linuxtmp->tmp_end-p_linuxtmp->tmp_curr < alloc_size) {
DBG_ERR("linuxtmp size too small to alloc nvtpack size %d bytes\r\n", alloc_size);
return -1;
}
p_linuxtmp->nvtpack_size = alloc_size;
p_linuxtmp->nvtpack_addr = p_linuxtmp->tmp_end - p_linuxtmp->nvtpack_size;
p_linuxtmp->tmp_end = p_linuxtmp->nvtpack_addr; // use the bottom of linuxtmp memory
UINT32 fw_size = (UINT32)nvtpack_len;
INT32 fst_er = FileSys_ReadFile(h_file, (UINT8 *)p_linuxtmp->nvtpack_addr, &fw_size, 0, NULL);
FileSys_CloseFile(h_file);
if (fst_er != FST_STA_OK) {
DBG_ERR("FW bin read fail\r\n");
return -1;
}
return 0;
}
#endif
int linuxboot_setup(LINUXBOOT_INFO *p_info)
{
int er;
unsigned int bootts_begin = hwclock_get_counter();
LINUXTMP_PARTITION *p_linuxtmp = &p_info->linuxtmp;
FDT_INFO *p_fdt_info = &p_info->fdt_info;
if ((er=fdt_get_info(p_fdt_info)) != 0) {
return er;
}
if ((er=check_mem_overlap(p_fdt_info)) != 0) {
return er;
}
p_linuxtmp->tmp_begin = p_fdt_info->linuxtmp_addr;
p_linuxtmp->tmp_curr = p_linuxtmp->tmp_begin;
p_linuxtmp->tmp_end = p_linuxtmp->tmp_begin + p_fdt_info->linuxtmp_size;
if (p_fdt_info->dram_size <= 0x04000000) {
DBG_WRN("small dram.\n");
p_linuxtmp->tmp2_begin = p_fdt_info->linux_addr + CFG_LINUX_MAX_CODE_SIZE;
p_linuxtmp->tmp2_curr = p_linuxtmp->tmp2_begin;
p_linuxtmp->tmp2_end = p_fdt_info->fdt_addr;
}
SHMINFO *p_shm = (SHMINFO *)p_fdt_info->shmem_addr;
if (p_shm->boot.LdCtrl2 & LDCF_BOOT_CARD) {
#if (_PACKAGE_FILESYS_ && _PACKAGE_SDCARD_)
// for boot linux from all-in-one in sd card
if ((er=load_nvtpack(p_linuxtmp)) !=0) {
return er;
}
#if (CFG_INDEP_RAMDISK)
// force load ramdisk by this method
ramdisk_methold = RAMDISK_METHOD_NVTPACK;
#endif
#else
DBG_ERR("for boot from sd, _PACKAGE_FILESYS_ and _PACKAGE_SDCARD_ must enable\r\n");
return -1;
#endif
}
// create new fdt for nodes of bootargs and ramdisk
if ((er=create_new_fdt(p_linuxtmp)) != 0) {
return er;
}
#if (CFG_INDEP_RAMDISK)
// load ramdisk into memory and reserved memory
if ((er=load_ramdisk(p_linuxtmp)) != 0) {
return er;
}
#endif
if ((er=load_linux(p_linuxtmp, p_fdt_info)) != 0) {
return er;
}
#if (CFG_INDEP_RAMDISK)
// wait ramdisk decompression thread finish (only for _NVT_LINUX_COMPRESS_NONE_)
if ((er=wait_ramdisk()) != 0) {
return er;
}
#endif
// make bootargs
if ((er=make_bootargs(p_linuxtmp, bootts_begin)) != 0) {
return er;
}
// insert bootargs and ramdisk into fdt
if ((er=fdt_chosen(p_linuxtmp)) != 0) {
return er;
}
return 0;
}
int linuxboot_set_flash_preload(LINUXBOOT_INFO *p_info)
{
int value = 1;
void *fdt = (void *)p_info->linuxtmp.fdt_addr;
int nodeoffset = fdt_path_offset(fdt, "/fastboot");
if (nodeoffset < 0) {
return nodeoffset;
}
/* find or create /fastboot/spi-nor node. */
nodeoffset = fdt_find_or_add_subnode(fdt, nodeoffset, "spi-nor");
if (nodeoffset < 0)
return nodeoffset;
int err = fdt_setprop(fdt, nodeoffset, "preload", &value, sizeof(value));
if (err < 0) {
DBG_DUMP("WARNING: could not set spi-nor/preload %s.\n",
fdt_strerror(err));
return err;
}
return 0;
}
void linuxboot_go(LINUXBOOT_INFO *p_info)
{
LINUXTMP_PARTITION *p_linuxtmp = &p_info->linuxtmp;
FDT_INFO *p_fdt_info = &p_info->fdt_info;
unsigned int r2 = p_linuxtmp->fdt_addr;
unsigned int kernel_addr = p_fdt_info->linux_addr + CFG_LINUX_START_OFFSET;
cpu_disable_interrupt();
cpu_disable_cache();
cpu_disable_mmu();
//alway enter #Mode_SVC before start linux
__asm__("cps #0x13");
{
void (*kernel_entry)(int zero, int arch, unsigned int params);
kernel_entry = (void (*)(int, int, unsigned int))((kernel_addr));
kernel_entry(0, 0, r2); // never returned
}
}