[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[microblaze-uclinux] Simple bootloader for custom board



Hello,

I'm still working on my custom board with a Virtex-II on it with some SDRAM.

So now my system is pretty ok in the hardware and FPGA part. I'm at the
moment working on the bootloader. I have chosen as a base the bootloader
that comes with the current uClinux-auto project. But since I have no
Flash memory on my board, I have to reload the kernel everytime, and I
want to use the serial port to do that.

So there is code in that bootloader, but it handles srec files. What is
the way to produce a srec file containing the kernel image AND the
filesystem so that I could use the current bootloader ?

I have also started working on a more simple bootlader that takes the
image file from the serial port, taking the raw data ... I can write the
file very well in the memory (I can check and the value are the same in
memory and my hard disk), but when starting the kernel, I just get
nothing ! The problem is that I have never been able to boot uClinux
with that card, so I've got no Idea where it could come from ! And has
someone already made that kind of work, and maybe with some protocol
implemented (Y or Z modem for example), because with my version, I have
to hard code the image size ? If you want to check my version, it is
attached to this message.

Thanks for your support

Valentin
/**********************************************************************
*
*  bootloader.c
*
*  Simple menu-driven bootloader for microblaze/uclinux on ROPES board
*
*  uClinux kernel command line parameter handling 
*     by Brett Boren <borenb@eng.uah.edu>
*
*************************************************************************
*  Copyright (C) 2003 John Williams <jwilliams@itee.uq.edu.au>
*  Copyright (C) 2004 Brett Boren <borenb@eng.uah.edu>
*  Copyright (C) 2005 Valentin Longchamp <valentin.longchamp@epfl.ch>
*
*  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*****************************************************************************/


/* Get general hardware memory map */
#include "xparameters.h"
#include "xbasic_types.h"
#include "xstatus.h"
#include "xuartlite_l.h"
#include "xuartlite.h"
#include "xgpio.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

#include "flash.h"

/* Software flow control characters */
#define XON 17
#define XOFF 19

#define FLASH_BASEADDR 0xff000000

/* Length of the Memory test */
#define TAB_SIZE 0x10

/* For now, hard code image length at 2MB */
unsigned int gImageLen=0;

/* Start and end of SDRAM ram */
unsigned int *sdram_start = (unsigned int *)XPAR_SDRAM_CONTROLLER_BASEADDR;
unsigned int *sdram_end = (unsigned int *)XPAR_SDRAM_CONTROLLER_HIGHADDR; 

/* Start and end of SRAM */
unsigned int *ram_start = (unsigned int *)0xffe00000;
unsigned int *ram_end = (unsigned int *)0xfff00000;

/* Static buffer to store kernel command line */
char cmdline[512];

/* hard coded size of the Linux image */
unsigned int imageSize = 644793;

/* the UART IP */
XUartLite uart;

/* Prototypes for menu functions */
typedef int (*menu_function)(void);
int menu_download_kernel(void);
int menu_test_memory(void);
int menu_launch_kernel(void);

typedef struct {
	menu_function fn;
	char *menu_string;
} menu_item;

menu_item main_menu[]={
	{menu_test_memory,"Test the SDRAM"},
	{menu_download_kernel,"Download Kernel from serial port"},
	{menu_launch_kernel,"Launch the Kernel from memory"},
	{0,0}};

// take an argument for the cmdline buffer
typedef void (*void_fn)(void *);
void_fn kernel_start;

extern int _start;

void set_intvecs(void)
{
	unsigned int *ptr=(unsigned int *)0x0;

	/* Only care about reset vector, make sure it points at 
		 the startup code */

	*ptr=(unsigned)&_start;
}


void memory_test(unsigned int *start, unsigned int *end)
{
	unsigned int *dst;

	print("\n\r\n\rTesting memory...");

	for(dst=start; dst<end; dst++)
		*dst=(unsigned int)dst;

	for(dst=start; dst<end; dst++)
		if(*dst!=(unsigned int)dst)
		{
			print("failed at 0x");
			putnum((int)dst);
			print("\n\rContents:0x");
			putnum((int)*dst);
			print(" expected 0x");
			putnum((unsigned int)dst);
			print("\n\rHalting...");
			for(;;)
				;
		}
}

void clear_memory(unsigned int *start, unsigned int *end)
{
	unsigned int *dst;

	for(dst=start; dst< end; dst++)
		*dst=0;
}

void copy_image(unsigned int *src, unsigned int *dst, unsigned int len)
{

	flash_read_reset();

	print("\n\rCopying kernel image...");
	while(len--)
	{
		*dst++=*src++;
	}
	print("done\n\r");
}

int menu_test_memory(void) {

	int *SDRAM_pointer = (int *) (XPAR_SDRAM_CONTROLLER_BASEADDR);
	int i = 0;
	int write_value = 0x12345600;
	
	xil_printf("Memory Test Program\r\n");

	//we erase memory to be sure of its state
	xil_printf("Erasing SDRAM\r\n");
	for (i=0; i<TAB_SIZE;i++) {
		*SDRAM_pointer = 0;
		SDRAM_pointer++;
	}
	xil_printf("Erasing done\r\n checking erase\r\n");

	SDRAM_pointer = (int *) (XPAR_SDRAM_CONTROLLER_BASEADDR);

	for (i = 0; i<TAB_SIZE; i++) {
		int value = *SDRAM_pointer;
		xil_printf("address : 0x%x value : 0x%x \r\n", SDRAM_pointer , value);
		SDRAM_pointer++;
	}

	SDRAM_pointer = (int *) (XPAR_SDRAM_CONTROLLER_BASEADDR);
	// we write into the memory
	xil_printf("Writing to the SDRAM\r\n");
	for (i=0; i<TAB_SIZE;i++) {
		*SDRAM_pointer = write_value;
		xil_printf("address : 0x%x value to be written : 0x%x \r\n", SDRAM_pointer, write_value);
		SDRAM_pointer++;
		write_value++;
	}
	xil_printf("write operations finished\r\n");

	SDRAM_pointer = (int *) (XPAR_SDRAM_CONTROLLER_BASEADDR);

	xil_printf("Reading back from the SDRAM\r\n");
	for (i=0; i<TAB_SIZE;i++) {
		int value = *SDRAM_pointer;
		xil_printf("address : 0x%x read value : 0x%x \r\n", SDRAM_pointer , value);
		SDRAM_pointer++;
	}

	xil_printf("end of Memory Test program\r\n");
	
	return 0;
	
}

int menu_download_kernel(void)
{

	unsigned int received = 0;
	Xuint8 *write_address = (Xuint8 *) sdram_start;
	Xuint32 *read_address = (Xuint32 *) sdram_start;
	
	XUartLite_Initialize(&uart, XPAR_CONSOLE_UART_DEVICE_ID);
	XUartLite_ResetFifos(&uart);
	
	xil_printf("\r\nImage will be loaded to %08x\n\r",write_address);

	xil_printf("Initiate file transfer now\n\r");

	gImageLen=0;

	while(received<imageSize)
	{
		int recv = XUartLite_Recv(&uart,write_address,16);
		if (recv > 0) {
			received += recv;
			gImageLen += recv;
			write_address += recv;
		}
	}

	xil_printf("%d bytes received\n\r",gImageLen);
	
	for(received = 0; received<12; received++){
		Xuint32 value = *read_address;
		xil_printf("address : 0x%x read value : 0x%x \r\n", read_address++ , value);
	}

	return 0;
}

int menu_launch_kernel(void)
{
	if(!gImageLen)
	{
		print("Error - no image downloaded yet!\n\r");
		return -1;
	}

	kernel_start = (void_fn)sdram_start;
	kernel_start(cmdline);		/* Never returns */

	return 0;

}

/* simple routine to get a number typed on stdin */
int get_number(void)
{
	char ch, buffer[100];
	int num_chars;

	num_chars=0;

	/* Read chars until buffer full or enter pressed */
	while((ch=inbyte()) != '\r' && num_chars < 99)
		if(isdigit(ch))
			outbyte(buffer[num_chars++]=ch);

	print("\n\r");

	buffer[num_chars]='\0';

	return atoi(buffer);
}

int do_menu(menu_item *menu)
{
	int menu_choice, num_items=0;

	num_items=0;

	print("\n\n\r");
	print("ROPES bootloader Menu\n\r");
	print("---------------------\n\r");
	print("\n\r");

	while(menu[num_items].fn)
	{
		xil_printf("%d.    %s\n\r",num_items+1,
					menu[num_items].menu_string);
		num_items++;
	}

	print("\n\r");
	print("\n\r");

	do
	{
		print("Make your choice>");
		menu_choice = get_number();
	} while (menu_choice<1 || menu_choice > num_items);

	return menu[menu_choice-1].fn();
}

int menu_set_cmdline(void)
{
	/* overwrite the first part of the address space since we're 
		 pretty well guaranteed not to have to use it again */
	int i = 0;
	char ch = '\0';

	outbyte(XON); 

	print("Enter cmdline: ");

	ch = inbyte();

	// 0x0d is the carriage return (Enter) ascii value
	// cmdline buffer is only 512 bytes
	while (ch != 0x0d && i < 512-1)
	{
		cmdline[i++] = ch;
		outbyte(XON); 
		outbyte(ch);
		ch = inbyte();
	}

	cmdline[i] = '\0';

	outbyte(XON); 

	return 1;
}

void reset_uarts(void)
{
	unsigned int *uartp;

	uartp=(unsigned int *)XPAR_CONSOLE_UART_BASEADDR;
	uartp[XUL_CONTROL_REG_OFFSET/4]=0x0;

#ifdef XPAR_DEBUG_UART_BASEADDR
	uartp=(unsigned int *)XPAR_DEBUG_UART_BASEADDR;
	uartp[XUL_CONTROL_REG_OFFSET/4]=0x0;
#endif
}



int main(void)
{
	//set_intvecs();	
	reset_uarts();
	flash_set_base((unsigned int *)FLASH_BASEADDR);
	flash_read_reset();

	/* Ensure cmdline defaults to null (zero-length) string */
	cmdline[0]='\0';

	while(1)
		do_menu(main_menu);
}