linux-kernel-test/arch/powerpc/boot/of.c
David Gibson 2e60161337 [POWERPC] Split low-level OF-related bootloader code into separate files
Currently, all OF-related code in the bootloader is contained in of.c.
of.c also provides the platform specific things necessary to boot on
an OF platform.

However, there are platforms (such as PReP) which can include an OF
implementation, but are not bootable as pure OF systems.  For use by
such platforms, this patch splits out the low-level parts of the OF
code (call_prom() and various wrappers thereof) into a new oflib.c
file.  In addition, the code related to bootwrapper console output via
OF are moved to a new ofconsole.c file.  Both these files are included
in the wrapper.a library where they can be used by both full-OF and
partial OF platforms.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Paul Mackerras <paulus@samba.org>
2007-06-14 22:30:15 +10:00

116 lines
2.6 KiB
C

/*
* Copyright (C) Paul Mackerras 1997.
*
* 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.
*/
#include <stdarg.h>
#include <stddef.h>
#include "types.h"
#include "elf.h"
#include "string.h"
#include "stdio.h"
#include "page.h"
#include "ops.h"
#include "of.h"
extern char _end[];
/* Value picked to match that used by yaboot */
#define PROG_START 0x01400000 /* only used on 64-bit systems */
#define RAM_END (512<<20) /* Fixme: use OF */
#define ONE_MB 0x100000
static unsigned long claim_base;
static void *of_try_claim(unsigned long size)
{
unsigned long addr = 0;
if (claim_base == 0)
claim_base = _ALIGN_UP((unsigned long)_end, ONE_MB);
for(; claim_base < RAM_END; claim_base += ONE_MB) {
#ifdef DEBUG
printf(" trying: 0x%08lx\n\r", claim_base);
#endif
addr = (unsigned long)of_claim(claim_base, size, 0);
if ((void *)addr != (void *)-1)
break;
}
if (addr == 0)
return NULL;
claim_base = PAGE_ALIGN(claim_base + size);
return (void *)addr;
}
static void of_image_hdr(const void *hdr)
{
const Elf64_Ehdr *elf64 = hdr;
if (elf64->e_ident[EI_CLASS] == ELFCLASS64) {
/*
* Maintain a "magic" minimum address. This keeps some older
* firmware platforms running.
*/
if (claim_base < PROG_START)
claim_base = PROG_START;
}
}
static void *of_vmlinux_alloc(unsigned long size)
{
void *p = malloc(size);
if (!p)
fatal("Can't allocate memory for kernel image!\n\r");
return p;
}
/*
* OF device tree routines
*/
static void *of_finddevice(const char *name)
{
return (phandle) of_call_prom("finddevice", 1, 1, name);
}
static int of_getprop(const void *phandle, const char *name, void *buf,
const int buflen)
{
return of_call_prom("getprop", 4, 1, phandle, name, buf, buflen);
}
static int of_setprop(const void *phandle, const char *name, const void *buf,
const int buflen)
{
return of_call_prom("setprop", 4, 1, phandle, name, buf, buflen);
}
void platform_init(unsigned long a1, unsigned long a2, void *promptr)
{
platform_ops.image_hdr = of_image_hdr;
platform_ops.malloc = of_try_claim;
platform_ops.exit = of_exit;
platform_ops.vmlinux_alloc = of_vmlinux_alloc;
dt_ops.finddevice = of_finddevice;
dt_ops.getprop = of_getprop;
dt_ops.setprop = of_setprop;
of_console_init();
of_init(promptr);
loader_info.promptr = promptr;
if (a1 && a2 && a2 != 0xdeadbeef) {
loader_info.initrd_addr = a1;
loader_info.initrd_size = a2;
}
}