9
0
Fork 0
barebox/arch/m68k/lib/m68k-linuxboot.c

178 lines
4.7 KiB
C

/*
* Copyright (c) 2008 Carsten Schlote <c.schlote@konzeptpark.de>
* See file CREDITS for list of people who contributed to this project.
*
* This file is part of barebox.
*
* barebox 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 3 of the License, or
* (at your option) any later version.
*
* barebox 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 barebox. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file
* @brief Linux boot preparation code.
*
* This file is responsible to start a linux kernel on
* Coldfire targets.
*
* @note Only Colilo mode supported yet.
*/
#include <common.h>
#include <command.h>
#include <driver.h>
#include <image.h>
#include <zlib.h>
#include <init.h>
#include <asm/byteorder.h>
#include <asm/setup.h>
#include <environment.h>
#include <boot.h>
#include <asm/barebox-m68k.h>
#include <asm/bootinfo.h>
static int m68k_architecture = MACH_TYPE_GENERIC;
/*
* Setup M68k/Coldfire bootrecord info
*/
#if defined (CONFIG_SETUP_MEMORY_TAGS) || \
defined (CONFIG_CMDLINE_TAG) || \
defined (CONFIG_INITRD_TAG)
static void setup_boot_record(char* start_boot_rec, const char* command_line)
{
struct bi_record* record;
*start_boot_rec++ = 'C';
*start_boot_rec++ = 'o';
*start_boot_rec++ = 'L';
*start_boot_rec++ = 'i';
*start_boot_rec++ = 'L';
*start_boot_rec++ = 'o';
record = (struct bi_record*) start_boot_rec;
/* specify memory layout */
#ifdef CONFIG_SETUP_MEMORY_TAGS
record->tag = BI_MEMCHUNK;
record->data[0] = 0;
record->data[1] = 64 * 1024 * 1024; // TODO: to be changed for different boards
record->size = sizeof (record->tag) + sizeof (record->size)
+ sizeof (record->data[0]) + sizeof (record->data[0]);
record = (struct bi_record *) ((void *) record + record->size);
#endif
/* add a kernel command line */
#ifdef CONFIG_CMDLINE_TAG
record->tag = BI_COMMAND_LINE;
strcpy ((char *) &record->data, command_line);
record->size = sizeof (record->tag) + sizeof (record->size)
+ max (sizeof (record->data[0]), strlen (command_line)+1);
record = (struct bi_record *) ((void *) record + record->size);
#endif
/* Add reference to initrd */
#ifdef CONFIG_INITRD_TAG
#endif
/* Mark end of tags */
record->tag = 0;
record->data[0] = 0;
record->data[1] = 0;
record->size = sizeof(record->tag) + sizeof (record->size)
+ sizeof (record->data[0]) + sizeof (record->data[0]);
}
#else
#define setup_boot_record(start_boot_rec,command_line) while (0) { }
#endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */
static int do_bootm_linux(struct image_data *data)
{
image_header_t *os_header = &data->os->header;
void (*theKernel)(int zero, int arch, uint params);
const char *commandline = getenv ("bootargs");
uint32_t loadaddr,loadsize;
if (os_header->ih_type == IH_TYPE_MULTI) {
printf("Multifile images not handled at the moment\n");
return -1;
}
printf("commandline: %s\n", commandline);
theKernel = (void (*)(int,int,uint))ntohl((os_header->ih_ep));
debug ("## Transferring control to Linux (at address %08lx) ...\n",
(ulong) theKernel);
loadaddr = (uint32_t)ntohl(os_header->ih_load);
loadsize = (uint32_t)ntohl(os_header->ih_size);
setup_boot_record( (char*)(loadaddr+loadsize),(char*)commandline);
if (relocate_image(data->os, (void *)loadaddr))
return -1;
/* we assume that the kernel is in place */
printf ("\nStarting kernel image at 0x%08x size 0x%08x eentry 0x%08x\n\n",
loadaddr, loadsize, (ulong) theKernel);
/* Bring board into inactive post-reset state again */
cleanup_before_linux ();
/* Jump to kernel entry point */
theKernel (0, m68k_architecture, 0xdeadbeaf);
enable_interrupts();
printf("Error: Loaded kernel returned. Probably it couldn't\n"
"find it's bootrecord.\n");
return -1;
}
/*
* Register handler for m68k Kernel Images
*/
static int image_handle_cmdline_parse(struct image_data *data, int opt, char *optarg)
{
switch (opt)
{
case 'a':
m68k_architecture = simple_strtoul(optarg, NULL, 0);
return 0;
default:
return 1;
}
}
static struct image_handler handler =
{
.cmdline_options = "a:",
.cmdline_parse = image_handle_cmdline_parse,
.help_string = " -a <arch> use architecture number <arch>",
.bootm = do_bootm_linux,
.image_type = IH_OS_LINUX,
};
static int m68klinux_register_image_handler(void)
{
return register_image_handler(&handler);
}
late_initcall(m68klinux_register_image_handler);