2008-11-24 12:16:22 +00:00
|
|
|
/*
|
2008-12-21 08:30:42 +00:00
|
|
|
* Creation Date: <2002/10/02 22:24:24 samuel>
|
|
|
|
|
* Time-stamp: <2004/03/27 01:57:55 samuel>
|
2008-11-24 12:16:22 +00:00
|
|
|
*
|
|
|
|
|
* <main.c>
|
|
|
|
|
*
|
|
|
|
|
*
|
2008-12-21 08:30:42 +00:00
|
|
|
*
|
2008-11-24 12:16:22 +00:00
|
|
|
* Copyright (C) 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se)
|
|
|
|
|
*
|
|
|
|
|
* 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
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "openbios/config.h"
|
2010-03-14 15:05:53 +00:00
|
|
|
#include "libopenbios/bindings.h"
|
|
|
|
|
#include "libopenbios/elfload.h"
|
2008-11-24 12:16:22 +00:00
|
|
|
#include "openbios/nvram.h"
|
|
|
|
|
#include "libc/diskio.h"
|
|
|
|
|
#include "libc/vsprintf.h"
|
2008-12-21 09:15:57 +00:00
|
|
|
#include "kernel.h"
|
2010-03-14 15:05:53 +00:00
|
|
|
#include "libopenbios/ofmem.h"
|
2009-03-08 09:45:25 +00:00
|
|
|
#define NO_QEMU_PROTOS
|
2010-03-14 16:09:44 +00:00
|
|
|
#include "arch/common/fw_cfg.h"
|
2008-11-24 12:16:22 +00:00
|
|
|
|
2009-08-10 19:57:43 +00:00
|
|
|
//#define DEBUG_QEMU
|
2008-12-21 08:30:42 +00:00
|
|
|
|
2009-08-10 19:57:43 +00:00
|
|
|
#ifdef DEBUG_QEMU
|
|
|
|
|
#define SUBSYS_DPRINTF(subsys, fmt, args...) \
|
|
|
|
|
do { printk("%s - %s: " fmt, subsys, __func__ , ##args); } while (0)
|
2008-12-21 08:30:42 +00:00
|
|
|
#else
|
2009-08-10 19:57:43 +00:00
|
|
|
#define SUBSYS_DPRINTF(subsys, fmt, args...) \
|
|
|
|
|
do { } while (0)
|
2008-12-21 08:30:42 +00:00
|
|
|
#endif
|
2009-08-10 19:57:43 +00:00
|
|
|
#define CHRP_DPRINTF(fmt, args...) SUBSYS_DPRINTF("CHRP", fmt, ##args)
|
|
|
|
|
#define ELF_DPRINTF(fmt, args...) SUBSYS_DPRINTF("ELF", fmt, ##args)
|
2009-08-29 15:43:00 +00:00
|
|
|
#define NEWWORLD_DPRINTF(fmt, args...) SUBSYS_DPRINTF("NEWWORLD", fmt, ##args)
|
2008-12-21 08:30:42 +00:00
|
|
|
|
2009-09-01 23:44:24 +00:00
|
|
|
static void
|
2009-09-21 23:12:02 +00:00
|
|
|
load(const char *path, const char *param)
|
2009-09-01 23:44:24 +00:00
|
|
|
{
|
|
|
|
|
char buffer[1024];
|
2009-09-21 23:12:02 +00:00
|
|
|
if (param)
|
|
|
|
|
sprintf(buffer, "load %s %s", path, param);
|
|
|
|
|
else
|
|
|
|
|
sprintf(buffer, "load %s", path);
|
2009-09-01 23:44:24 +00:00
|
|
|
feval(buffer);
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-05 00:05:58 +00:00
|
|
|
static char *
|
|
|
|
|
get_device( const char *path )
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
static char buf[1024];
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < sizeof(buf) && path[i] && path[i] != ':'; i++)
|
|
|
|
|
buf[i] = path[i];
|
|
|
|
|
buf[i] = 0;
|
|
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
get_partition( const char *path )
|
|
|
|
|
{
|
|
|
|
|
while ( *path && *path != ':' )
|
|
|
|
|
path++;
|
|
|
|
|
|
|
|
|
|
if (!*path)
|
2009-08-29 15:24:49 +00:00
|
|
|
return -1;
|
2009-02-05 00:05:58 +00:00
|
|
|
path++;
|
|
|
|
|
|
|
|
|
|
if (!strchr(path, ',')) /* check if there is a ',' */
|
2009-08-29 15:24:49 +00:00
|
|
|
return -1;
|
2009-02-05 00:05:58 +00:00
|
|
|
|
|
|
|
|
return atol(path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
2009-02-15 20:20:55 +00:00
|
|
|
get_filename( const char * path , char **dirname)
|
2009-02-05 00:05:58 +00:00
|
|
|
{
|
|
|
|
|
static char buf[1024];
|
2009-02-15 20:20:55 +00:00
|
|
|
char *filename;
|
2009-02-05 00:05:58 +00:00
|
|
|
|
|
|
|
|
while ( *path && *path != ':' )
|
|
|
|
|
path++;
|
|
|
|
|
|
2009-02-15 20:20:55 +00:00
|
|
|
if (!*path) {
|
|
|
|
|
*dirname = NULL;
|
2009-02-05 00:05:58 +00:00
|
|
|
return NULL;
|
2009-02-15 20:20:55 +00:00
|
|
|
}
|
2009-02-05 00:05:58 +00:00
|
|
|
path++;
|
|
|
|
|
|
|
|
|
|
while ( *path && isdigit(*path) )
|
|
|
|
|
path++;
|
|
|
|
|
|
|
|
|
|
if (*path == ',')
|
|
|
|
|
path++;
|
|
|
|
|
|
|
|
|
|
strncpy(buf, path, sizeof(buf));
|
|
|
|
|
buf[sizeof(buf) - 1] = 0;
|
|
|
|
|
|
2009-02-15 20:20:55 +00:00
|
|
|
filename = strrchr(buf, '\\');
|
|
|
|
|
if (filename) {
|
|
|
|
|
*dirname = buf;
|
|
|
|
|
(*filename++) = 0;
|
|
|
|
|
} else {
|
|
|
|
|
*dirname = NULL;
|
|
|
|
|
filename = buf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return filename;
|
2009-02-05 00:05:58 +00:00
|
|
|
}
|
|
|
|
|
|
2008-11-24 12:16:22 +00:00
|
|
|
static void
|
|
|
|
|
encode_bootpath( const char *spec, const char *args )
|
|
|
|
|
{
|
2009-02-05 00:05:58 +00:00
|
|
|
char path[1024];
|
2008-11-24 12:16:22 +00:00
|
|
|
phandle_t chosen_ph = find_dev("/chosen");
|
2009-02-15 20:20:55 +00:00
|
|
|
char *filename, *directory;
|
2009-08-29 15:24:49 +00:00
|
|
|
int partition;
|
2009-02-05 00:05:58 +00:00
|
|
|
|
2009-02-15 20:20:55 +00:00
|
|
|
filename = get_filename(spec, &directory);
|
2009-08-29 15:24:49 +00:00
|
|
|
partition = get_partition(spec);
|
|
|
|
|
if (partition == -1)
|
|
|
|
|
snprintf(path, sizeof(path), "%s:,%s\\%s", get_device(spec),
|
|
|
|
|
directory, filename);
|
|
|
|
|
else
|
|
|
|
|
snprintf(path, sizeof(path), "%s:%d,%s\\%s", get_device(spec),
|
|
|
|
|
partition, directory, filename);
|
2009-02-05 00:05:58 +00:00
|
|
|
|
|
|
|
|
ELF_DPRINTF("bootpath %s bootargs %s\n", path, args);
|
2009-11-08 23:43:19 +00:00
|
|
|
set_property( chosen_ph, "bootpath", path, strlen(path)+1 );
|
2009-02-18 13:58:35 +00:00
|
|
|
if (args)
|
|
|
|
|
set_property( chosen_ph, "bootargs", args, strlen(args)+1 );
|
2008-11-24 12:16:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/************************************************************************/
|
|
|
|
|
/* qemu booting */
|
|
|
|
|
/************************************************************************/
|
2008-12-23 11:53:13 +00:00
|
|
|
static void
|
2009-09-21 23:12:02 +00:00
|
|
|
try_path(const char *device, const char* filename, const char *param)
|
2008-12-23 11:53:13 +00:00
|
|
|
{
|
2009-09-21 23:12:02 +00:00
|
|
|
char path[1024];
|
|
|
|
|
|
|
|
|
|
if (filename)
|
|
|
|
|
snprintf(path, sizeof(path), "%s%s", device, filename);
|
|
|
|
|
else
|
|
|
|
|
snprintf(path, sizeof(path), "%s", device);
|
2008-12-23 11:53:13 +00:00
|
|
|
|
|
|
|
|
ELF_DPRINTF("Trying %s %s\n", path, param);
|
|
|
|
|
|
2009-09-21 23:12:02 +00:00
|
|
|
load(path, param);
|
2008-12-23 11:53:13 +00:00
|
|
|
update_nvram();
|
|
|
|
|
ELF_DPRINTF("Transfering control to %s %s\n",
|
|
|
|
|
path, param);
|
2009-09-20 20:15:46 +00:00
|
|
|
feval("go");
|
2008-12-23 11:54:25 +00:00
|
|
|
}
|
|
|
|
|
|
2009-08-12 19:55:31 +00:00
|
|
|
#define OLDWORLD_BOOTCODE_BASEADDR (0x3f4000)
|
2009-01-11 00:19:02 +00:00
|
|
|
|
|
|
|
|
static void
|
2009-08-12 19:55:31 +00:00
|
|
|
oldworld_boot( void )
|
2009-01-11 00:19:02 +00:00
|
|
|
{
|
|
|
|
|
int fd;
|
2009-08-12 19:55:31 +00:00
|
|
|
int len, total;
|
|
|
|
|
const char *path = "hd:,%BOOT";
|
|
|
|
|
char *bootcode;
|
2009-01-11 00:19:02 +00:00
|
|
|
|
|
|
|
|
if ((fd = open_io(path)) == -1) {
|
|
|
|
|
ELF_DPRINTF("Can't open %s\n", path);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-08-12 19:55:31 +00:00
|
|
|
total = 0;
|
|
|
|
|
bootcode = (char*)OLDWORLD_BOOTCODE_BASEADDR;
|
|
|
|
|
while(1) {
|
|
|
|
|
if (seek_io(fd, total) == -1)
|
|
|
|
|
break;
|
|
|
|
|
len = read_io(fd, bootcode, 512);
|
|
|
|
|
bootcode += len;
|
|
|
|
|
total += len;
|
2009-01-11 00:19:02 +00:00
|
|
|
}
|
|
|
|
|
|
2009-08-12 19:55:31 +00:00
|
|
|
close_io( fd );
|
2009-01-11 00:19:02 +00:00
|
|
|
|
2009-08-12 19:55:31 +00:00
|
|
|
if (total == 0) {
|
|
|
|
|
ELF_DPRINTF("Can't read %s\n", path);
|
2009-01-11 00:19:02 +00:00
|
|
|
return;
|
2009-08-12 19:55:31 +00:00
|
|
|
}
|
2009-01-11 00:19:02 +00:00
|
|
|
|
2009-08-08 21:56:26 +00:00
|
|
|
encode_bootpath(path, "Linux");
|
2009-01-11 00:19:02 +00:00
|
|
|
|
2009-08-12 19:55:31 +00:00
|
|
|
if( ofmem_claim( OLDWORLD_BOOTCODE_BASEADDR, total, 0 ) == -1 )
|
2009-01-11 00:19:02 +00:00
|
|
|
fatal_error("Claim failed!\n");
|
|
|
|
|
|
2009-08-12 19:55:31 +00:00
|
|
|
call_elf(0, 0, OLDWORLD_BOOTCODE_BASEADDR);
|
2009-01-11 00:19:02 +00:00
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-24 12:16:22 +00:00
|
|
|
static void
|
2009-08-29 15:43:00 +00:00
|
|
|
newworld_boot( void )
|
2008-11-24 12:16:22 +00:00
|
|
|
{
|
2009-10-19 23:02:10 +00:00
|
|
|
static const char * const chrp_path[] = { "\\\\:tbxi",
|
|
|
|
|
"ppc\\bootinfo.txt",
|
|
|
|
|
NULL
|
|
|
|
|
};
|
2008-12-23 11:53:13 +00:00
|
|
|
char *path = pop_fstr_copy(), *param;
|
2009-10-19 23:02:10 +00:00
|
|
|
int i;
|
2008-12-23 11:53:13 +00:00
|
|
|
|
2009-02-18 13:58:35 +00:00
|
|
|
param = strchr(path, ' ');
|
|
|
|
|
if (param) {
|
|
|
|
|
*param = 0;
|
|
|
|
|
param++;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-23 11:53:13 +00:00
|
|
|
if (!path) {
|
2009-08-29 15:43:00 +00:00
|
|
|
NEWWORLD_DPRINTF("Entering boot, no path\n");
|
2008-12-23 11:53:13 +00:00
|
|
|
push_str("boot-device");
|
|
|
|
|
push_str("/options");
|
|
|
|
|
fword("(find-dev)");
|
|
|
|
|
POP();
|
|
|
|
|
fword("get-package-property");
|
|
|
|
|
if (!POP()) {
|
|
|
|
|
path = pop_fstr_copy();
|
|
|
|
|
param = strchr(path, ' ');
|
|
|
|
|
if (param) {
|
|
|
|
|
*param = '\0';
|
|
|
|
|
param++;
|
|
|
|
|
} else {
|
|
|
|
|
push_str("boot-args");
|
|
|
|
|
push_str("/options");
|
|
|
|
|
fword("(find-dev)");
|
|
|
|
|
POP();
|
|
|
|
|
fword("get-package-property");
|
|
|
|
|
POP();
|
|
|
|
|
param = pop_fstr_copy();
|
|
|
|
|
}
|
2009-09-21 23:12:02 +00:00
|
|
|
try_path(path, NULL, param);
|
2009-10-19 23:02:10 +00:00
|
|
|
for (i = 0; chrp_path[i]; i++)
|
|
|
|
|
try_path(path, chrp_path[i], param);
|
2008-12-23 11:57:36 +00:00
|
|
|
} else {
|
2009-03-08 09:45:25 +00:00
|
|
|
uint16_t boot_device = fw_cfg_read_i16(FW_CFG_BOOT_DEVICE);
|
2008-12-23 11:57:36 +00:00
|
|
|
switch (boot_device) {
|
|
|
|
|
case 'c':
|
2009-08-29 15:24:49 +00:00
|
|
|
path = strdup("hd:");
|
2008-12-23 11:57:36 +00:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
case 'd':
|
2009-08-29 15:24:49 +00:00
|
|
|
path = strdup("cd:");
|
2008-12-23 11:57:36 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2009-10-19 23:02:10 +00:00
|
|
|
for (i = 0; chrp_path[i]; i++)
|
|
|
|
|
try_path(path, chrp_path[i], param);
|
2008-12-23 11:53:13 +00:00
|
|
|
}
|
2008-12-23 11:54:25 +00:00
|
|
|
} else {
|
2009-08-29 15:43:00 +00:00
|
|
|
NEWWORLD_DPRINTF("Entering boot, path %s\n", path);
|
2009-09-21 23:12:02 +00:00
|
|
|
try_path(path, NULL, param);
|
2009-10-19 23:02:10 +00:00
|
|
|
for (i = 0; chrp_path[i]; i++)
|
|
|
|
|
try_path(path, chrp_path[i], param);
|
2008-12-23 11:53:13 +00:00
|
|
|
}
|
2008-11-24 12:16:22 +00:00
|
|
|
printk("*** Boot failure! No secondary bootloader specified ***\n");
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-23 11:57:36 +00:00
|
|
|
static void check_preloaded_kernel(void)
|
|
|
|
|
{
|
2009-01-13 20:02:40 +00:00
|
|
|
unsigned long kernel_image, kernel_size;
|
2008-12-23 11:57:36 +00:00
|
|
|
unsigned long initrd_image, initrd_size;
|
2009-03-08 09:45:25 +00:00
|
|
|
const char * kernel_cmdline;
|
2008-12-23 11:57:36 +00:00
|
|
|
|
2009-03-08 09:45:25 +00:00
|
|
|
kernel_size = fw_cfg_read_i32(FW_CFG_KERNEL_SIZE);
|
2008-12-23 11:57:36 +00:00
|
|
|
if (kernel_size) {
|
2009-03-08 09:45:25 +00:00
|
|
|
kernel_image = fw_cfg_read_i32(FW_CFG_KERNEL_ADDR);
|
|
|
|
|
kernel_cmdline = (const char *) fw_cfg_read_i32(FW_CFG_KERNEL_CMDLINE);
|
|
|
|
|
initrd_image = fw_cfg_read_i32(FW_CFG_INITRD_ADDR);
|
|
|
|
|
initrd_size = fw_cfg_read_i32(FW_CFG_INITRD_SIZE);
|
2009-01-04 19:25:41 +00:00
|
|
|
printk("[ppc] Kernel already loaded (0x%8.8lx + 0x%8.8lx) "
|
|
|
|
|
"(initrd 0x%8.8lx + 0x%8.8lx)\n",
|
|
|
|
|
kernel_image, kernel_size, initrd_image, initrd_size);
|
2009-03-08 09:45:25 +00:00
|
|
|
if (kernel_cmdline) {
|
|
|
|
|
phandle_t ph;
|
|
|
|
|
printk("[ppc] Kernel command line: %s\n", kernel_cmdline);
|
|
|
|
|
ph = find_dev("/chosen");
|
|
|
|
|
set_property(ph, "bootargs", strdup(kernel_cmdline), strlen(kernel_cmdline) + 1);
|
2009-01-13 20:02:40 +00:00
|
|
|
}
|
2009-01-04 19:25:41 +00:00
|
|
|
call_elf(initrd_image, initrd_size, kernel_image);
|
2008-12-23 11:57:36 +00:00
|
|
|
}
|
|
|
|
|
}
|
2008-11-24 12:16:22 +00:00
|
|
|
|
|
|
|
|
/************************************************************************/
|
|
|
|
|
/* entry */
|
|
|
|
|
/************************************************************************/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
boot( void )
|
|
|
|
|
{
|
2009-03-08 09:45:25 +00:00
|
|
|
uint16_t boot_device = fw_cfg_read_i16(FW_CFG_BOOT_DEVICE);
|
|
|
|
|
|
2008-11-24 12:16:22 +00:00
|
|
|
fword("update-chosen");
|
2009-01-13 20:07:43 +00:00
|
|
|
if (boot_device == 'm') {
|
|
|
|
|
check_preloaded_kernel();
|
|
|
|
|
}
|
|
|
|
|
if (boot_device == 'c') {
|
2009-08-12 19:55:31 +00:00
|
|
|
oldworld_boot();
|
2009-01-13 20:07:43 +00:00
|
|
|
}
|
2009-08-29 15:43:00 +00:00
|
|
|
newworld_boot();
|
2008-11-24 12:16:22 +00:00
|
|
|
}
|