/* * Creation Date: <2002/10/02 22:24:24 samuel> * Time-stamp: <2004/03/27 01:57:55 samuel> * * * * * * 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 "config.h" #include "libopenbios/bindings.h" #include "libopenbios/elf_load.h" #include "arch/common/nvram.h" #include "packages/nvram.h" #include "libc/diskio.h" #include "libc/vsprintf.h" #include "kernel.h" #include "libopenbios/ofmem.h" #define NO_QEMU_PROTOS #include "arch/common/fw_cfg.h" //#define DEBUG_QEMU #ifdef DEBUG_QEMU #define SUBSYS_DPRINTF(subsys, fmt, args...) \ do { printk("%s - %s: " fmt, subsys, __func__ , ##args); } while (0) #else #define SUBSYS_DPRINTF(subsys, fmt, args...) \ do { } while (0) #endif #define CHRP_DPRINTF(fmt, args...) SUBSYS_DPRINTF("CHRP", fmt, ##args) #define ELF_DPRINTF(fmt, args...) SUBSYS_DPRINTF("ELF", fmt, ##args) #define NEWWORLD_DPRINTF(fmt, args...) SUBSYS_DPRINTF("NEWWORLD", fmt, ##args) 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) return -1; path++; if (!strchr(path, ',')) /* check if there is a ',' */ return -1; return atol(path); } static char * get_filename( const char * path , char **dirname) { static char buf[1024]; char *filename; while ( *path && *path != ':' ) path++; if (!*path) { *dirname = NULL; return NULL; } path++; while ( *path && isdigit(*path) ) path++; if (*path == ',') path++; strncpy(buf, path, sizeof(buf)); buf[sizeof(buf) - 1] = 0; filename = strrchr(buf, '\\'); if (filename) { *dirname = buf; (*filename++) = 0; } else { *dirname = NULL; filename = buf; } return filename; } static void encode_bootpath( const char *spec, const char *args ) { char path[1024]; phandle_t chosen_ph = find_dev("/chosen"); char *filename, *directory; int partition; if (spec) return; filename = get_filename(spec, &directory); 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); ELF_DPRINTF("bootpath %s bootargs %s\n", path, args); set_property( chosen_ph, "bootpath", path, strlen(path)+1 ); if (args) set_property( chosen_ph, "bootargs", args, strlen(args)+1 ); } #define OLDWORLD_BOOTCODE_BASEADDR (0x3f4000) static void oldworld_boot( void ) { int fd; int len, total; const char *path = "hd:,%BOOT"; char *bootcode; if ((fd = open_io(path)) == -1) { ELF_DPRINTF("Can't open %s\n", path); return; } 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; } close_io( fd ); if (total == 0) { ELF_DPRINTF("Can't read %s\n", path); return; } encode_bootpath(path, "Linux"); if( ofmem_claim( OLDWORLD_BOOTCODE_BASEADDR, total, 0 ) == -1 ) fatal_error("Claim failed!\n"); call_elf(0, 0, OLDWORLD_BOOTCODE_BASEADDR); return; } static void check_preloaded_kernel(void) { unsigned long kernel_image, kernel_size; unsigned long initrd_image, initrd_size; const char * kernel_cmdline; kernel_size = fw_cfg_read_i32(FW_CFG_KERNEL_SIZE); if (kernel_size) { 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); 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); 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); } call_elf(initrd_image, initrd_size, kernel_image); } } /************************************************************************/ /* entry */ /************************************************************************/ void boot( void ) { uint16_t boot_device = fw_cfg_read_i16(FW_CFG_BOOT_DEVICE); fword("update-chosen"); if (boot_device == 'm') { check_preloaded_kernel(); } if (boot_device == 'c') { oldworld_boot(); } update_nvram(); }