踩坑日记9 microblaze运行在DDR上固化优化-快速启动

        在上一次踩坑日记中,我使用了官方例程固化elf文件,官方的bootloader程序是把elf文件转换成SREC格式然后存进flash中,如图。

        在启动过程中需要把SREC文件再解码,耗费时间。

下面介绍直接把elf存进flash中然后搬运到ddr上运行的方法,在sdk新建fsbl_elf工程,空工程作为模板即可。

加入以下文件

eb-config.h

/* Copyright (c) 2015-2017 Henrik Brix Andersen <henrik@brixandersen.dk>
 * All rights reserved.
 *
 * 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 AUTHOR 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 AUTHOR 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.
 */

#include <xparameters.h>

/*
 * Device ID of the SPI controller to use
 */
#define SPI_DEVICE_ID			XPAR_SPI_0_DEVICE_ID

/*
 * Slave select pin for the SPI flash
 */
#define SPI_FLASH_SLAVE_SELECT	1

/*
 * Number of dummy bytes (derived from number of dummy cycles)
 * required for the SPI flash at the given frequency
 */
#define SPI_FLASH_NDUMMY_BYTES	4

/*
 * 修改成待会elf文件烧录的位置
 */
#define ELF_IMAGE_BASEADDR		0x00c00000

/*
 * Maximum number of bytes to read from flash in one go.
 * Must be large enough to accommodate the ELF32 header (52 bytes).
 */
#define EFFECTIVE_READ_BUFFER_SIZE		256

/*
 * SPI read operation to use
 */
#define SPI_READ_OPERATION				0x6B

/*
 * Byte offset for the valid bytes in ReadBuffer
 */
#define SPI_VALID_DATA_OFFSET			(4 + SPI_FLASH_NDUMMY_BYTES)

/*
 * Enable debug for the ELF loader
 */
//#define DEBUG_ELF_LOADER

elf-bootloader.c

/* Copyright (c) 2015-2017 Henrik Brix Andersen <henrik@brixandersen.dk>
 * All rights reserved.
 *
 * 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 AUTHOR 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 AUTHOR 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.
 */

#include <stdio.h>
#include <string.h>

#include <mb_interface.h>
#include <xil_cache.h>
#include <xil_printf.h>
#include <xspi.h>
#include <xparameters.h>

#include "elf32.h"
#include "eb-config.h"

static XSpi Spi;
static u8 ReadBuffer[EFFECTIVE_READ_BUFFER_SIZE + SPI_VALID_DATA_OFFSET];

/*
 * Reduce code size on Microblaze (no interrupts used)
 */
#ifdef __MICROBLAZE__
void _interrupt_handler() {}
void _exception_handler() {}
void _hw_exception_handler() {}
#endif

/**
 * Simple wrapper function for reading a number of bytes from SPI flash.
 */
int spi_flash_read(XSpi *InstancePtr, u32 FlashAddress, u8 *RecvBuffer, unsigned int ByteCount)
{
	RecvBuffer[0] = SPI_READ_OPERATION;
	RecvBuffer[1] = (FlashAddress >> 16) & 0xFF;
	RecvBuffer[2] = (FlashAddress >> 8) & 0xFF;
	RecvBuffer[3] = FlashAddress & 0xFF;

	return XSpi_Transfer(InstancePtr, RecvBuffer, RecvBuffer, ByteCount + SPI_VALID_DATA_OFFSET);
}

int main()
{
	elf32_hdr hdr;
	elf32_phdr phdr;
	u32 addr;
	int ret, i, j;

	/*
	 * Disable caches
	 */
#if (XPAR_MICROBLAZE_USE_DCACHE == 1)
	Xil_DCacheInvalidate()
	Xil_DCacheDisable();
#endif
#if (XPAR_MICROBLAZE_USE_ICACHE == 1)
	Xil_ICacheInvalidate();
	Xil_ICacheDisable();
#endif

	print("\r\nSPI ELF Bootloader\r\n");

	/*
	 * Initialize the SPI controller in polled mode
	 * and enable the flash slave select
	 */
	ret = XSpi_Initialize(&Spi, SPI_DEVICE_ID);
	if (ret != XST_SUCCESS) {
		if (ret == XST_DEVICE_IS_STARTED) {
			if (XSpi_Stop(&Spi) == XST_DEVICE_BUSY) {
				print("SPI device is busy\r\n");
				return -1;
			}
		} else if (ret == XST_DEVICE_NOT_FOUND) {
			print("SPI device not found\r\n");
			return -1;
		} else {
			print("Unknown error\r\n");
			return -1;
		}
	}

	ret = XSpi_SetOptions(&Spi, XSP_MASTER_OPTION | XSP_MANUAL_SSELECT_OPTION);
	if (ret != XST_SUCCESS) {
		if (ret == XST_DEVICE_BUSY) {
			print("SPI device is busy\r\n");
			return -1;
		} else if (ret == XST_SPI_SLAVE_ONLY) {
			print("SPI device is slave-only\r\n");
			return -1;
		} else {
			print("Unknown error\r\n");
			return -1;
		}
	}

	ret = XSpi_SetSlaveSelect(&Spi, SPI_FLASH_SLAVE_SELECT);
	if (ret != XST_SUCCESS) {
		if (ret == XST_DEVICE_BUSY) {
			print("SPI device is busy\r\n");
			return ret;
		} else if (ret == XST_SPI_TOO_MANY_SLAVES) {
			print("Too many SPI slave devices\r\n");
			return ret;
		} else {
			print("Unknown error\r\n");
			return ret;
		}
	}

	XSpi_Start(&Spi);
	XSpi_IntrGlobalDisable(&Spi);

	print("Copying ELF image from SPI flash @ 0x");
	putnum(ELF_IMAGE_BASEADDR);
	print(" to RAM\r\n");

	/*
	 * Read ELF header
	 */
	ret = spi_flash_read(&Spi, ELF_IMAGE_BASEADDR, ReadBuffer, sizeof(hdr));
	if (ret == XST_SUCCESS) {
		memcpy(&hdr, ReadBuffer + SPI_VALID_DATA_OFFSET, sizeof(hdr));

#ifdef DEBUG_ELF_LOADER
		print("hdr.ident:\r\n");
		for (i = 0; i < HDR_IDENT_NBYTES; i++) {
			putnum(hdr.ident[i]);
			print("\r\n");
		}
#endif

	} else {
		print("Failed to read ELF header");
		return -1;
	}

	/*
	 * Validate ELF header
	 */
	if (hdr.ident[0] != HDR_IDENT_MAGIC_0 ||
			hdr.ident[1] != HDR_IDENT_MAGIC_1 ||
			hdr.ident[2] != HDR_IDENT_MAGIC_2 ||
			hdr.ident[3] != HDR_IDENT_MAGIC_3) {
		print("Invalid ELF header");
		return -1;
	}

	/**
	 * Read ELF program headers
	 */
	for (i = 0; i < hdr.phnum; i++) {
		ret = spi_flash_read(&Spi, ELF_IMAGE_BASEADDR + hdr.phoff + i * sizeof(phdr), ReadBuffer, sizeof(phdr));
		if (ret == XST_SUCCESS) {
			memcpy(&phdr, ReadBuffer + SPI_VALID_DATA_OFFSET, sizeof(phdr));

			if (phdr.type == PHDR_TYPE_LOAD) {
				/*
				 * Copy program segment from flash to RAM
				 */
				for (addr = 0; addr < phdr.filesz; addr += EFFECTIVE_READ_BUFFER_SIZE) {
					if (addr + EFFECTIVE_READ_BUFFER_SIZE > phdr.filesz) {
						ret = spi_flash_read(&Spi, ELF_IMAGE_BASEADDR + phdr.offset + addr,
								ReadBuffer, phdr.filesz - addr);
#ifdef DEBUG_ELF_LOADER
						print("End of section: ");
						putnum(i);
						print("\r\n");

						print("filesz: ");
						putnum(phdr.filesz);
						print("\r\n");

						print("addr: ");
						putnum(addr);
						print("\r\n");

						print("segment end:\r\n");
						for (j = 15; j >= 0; j--) {
							putnum(ReadBuffer[SPI_VALID_DATA_OFFSET + phdr.filesz - addr - j]);
							print(" ");
						}
						print("\r\n");
#endif

					} else {
						ret = spi_flash_read(&Spi, ELF_IMAGE_BASEADDR + phdr.offset + addr,
								ReadBuffer, EFFECTIVE_READ_BUFFER_SIZE);
#ifdef DEBUG_ELF_LOADER
						if (addr == 0) {
							print("segment start:\r\n");
							for (j = 0; j < EFFECTIVE_READ_BUFFER_SIZE; j++) {
								putnum(ReadBuffer[SPI_VALID_DATA_OFFSET + j]);
								print(" ");
							}
							print("\r\n");
						}
#endif
					}

					if (ret == XST_SUCCESS) {
						if (addr + EFFECTIVE_READ_BUFFER_SIZE > phdr.filesz) {
							memcpy((void*)phdr.paddr + addr, ReadBuffer + SPI_VALID_DATA_OFFSET, phdr.filesz - addr);
						} else {
							memcpy((void*)phdr.paddr + addr, ReadBuffer + SPI_VALID_DATA_OFFSET, EFFECTIVE_READ_BUFFER_SIZE);
						}

						if (addr % 1024 == 0) {
							print(".");
						}
					} else {
						print("Failed to read ELF program segment");
						return -1;
					}
				}

				/*
				 * Fill remaining segment in RAM with zeros
				 */
				if (phdr.memsz > phdr.filesz) {
					memset((void*)(phdr.paddr + phdr.filesz), 0, phdr.memsz - phdr.filesz);
				}
			}
		} else {
			print("Failed to read ELF program header");
			return -1;
		}
	}

	/**
	 * Jump to ELF entry address
	 */
	print("\r\nTransferring execution to program @ 0x");
	putnum(hdr.entry);
	print("\r\n");
	((void (*)())hdr.entry)();

	// Never reached
	return 0;
}

elf32.h

/* Copyright (c) 2015-2017 Henrik Brix Andersen <henrik@brixandersen.dk>
 * All rights reserved.
 *
 * 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 AUTHOR 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 AUTHOR 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.
 */

#ifndef __ELF32_H__
#define __ELF32_H__

#define HDR_IDENT_NBYTES	(16)

#define HDR_IDENT_MAGIC_0	0x7f
#define HDR_IDENT_MAGIC_1	'E'
#define HDR_IDENT_MAGIC_2	'L'
#define HDR_IDENT_MAGIC_3	'F'

typedef struct {
	u8  ident[HDR_IDENT_NBYTES];
	u16 type;
	u16 machine;
	u32 version;
	u32 entry;
	u32 phoff;
	u32 shoff;
	u32 flags;
	u16 ehsize;
	u16 phentsize;
	u16 phnum;
	u16 shentsize;
	u16 shnum;
	u16 shstrndx;
} elf32_hdr;

#define PHDR_TYPE_LOAD 1

typedef struct {
	u32 type;
	u32 offset;
	u32 vaddr;
	u32 paddr;
	u32 filesz;
	u32 memsz;
	u32 flags;
	u32 align;
} elf32_phdr;

#endif /* __ELF32_H__ */

将本工程作为之前官方FSBL工程的替代,设置运行在bram上,随bit一起烧录进flash。

烧录elf文件时,选择如下,记得更改Offset为eb-config.h一样的。另外,flash地址加上elf文件的大小最后不要超出0x01000000,因为spi flash的读取地址在常规下只有24位。

两个烧录完成后启动,只需要3秒左右,而用官方的FSBL需要2分钟。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值