linux/arch/powerpc/boot/oflib.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) Paul Mackerras 1997.
   3 *
   4 * This program is free software; you can redistribute it and/or
   5 * modify it under the terms of the GNU General Public License
   6 * as published by the Free Software Foundation; either version
   7 * 2 of the License, or (at your option) any later version.
   8 */
   9#include <stddef.h>
  10#include "types.h"
  11#include "elf.h"
  12#include "string.h"
  13#include "stdio.h"
  14#include "page.h"
  15#include "ops.h"
  16
  17#include "of.h"
  18
  19static int (*prom) (void *);
  20
  21void of_init(void *promptr)
  22{
  23        prom = (int (*)(void *))promptr;
  24}
  25
  26int of_call_prom(const char *service, int nargs, int nret, ...)
  27{
  28        int i;
  29        struct prom_args {
  30                const char *service;
  31                int nargs;
  32                int nret;
  33                unsigned int args[12];
  34        } args;
  35        va_list list;
  36
  37        args.service = service;
  38        args.nargs = nargs;
  39        args.nret = nret;
  40
  41        va_start(list, nret);
  42        for (i = 0; i < nargs; i++)
  43                args.args[i] = va_arg(list, unsigned int);
  44        va_end(list);
  45
  46        for (i = 0; i < nret; i++)
  47                args.args[nargs+i] = 0;
  48
  49        if (prom(&args) < 0)
  50                return -1;
  51
  52        return (nret > 0)? args.args[nargs]: 0;
  53}
  54
  55static int of_call_prom_ret(const char *service, int nargs, int nret,
  56                            unsigned int *rets, ...)
  57{
  58        int i;
  59        struct prom_args {
  60                const char *service;
  61                int nargs;
  62                int nret;
  63                unsigned int args[12];
  64        } args;
  65        va_list list;
  66
  67        args.service = service;
  68        args.nargs = nargs;
  69        args.nret = nret;
  70
  71        va_start(list, rets);
  72        for (i = 0; i < nargs; i++)
  73                args.args[i] = va_arg(list, unsigned int);
  74        va_end(list);
  75
  76        for (i = 0; i < nret; i++)
  77                args.args[nargs+i] = 0;
  78
  79        if (prom(&args) < 0)
  80                return -1;
  81
  82        if (rets != (void *) 0)
  83                for (i = 1; i < nret; ++i)
  84                        rets[i-1] = args.args[nargs+i];
  85
  86        return (nret > 0)? args.args[nargs]: 0;
  87}
  88
  89/* returns true if s2 is a prefix of s1 */
  90static int string_match(const char *s1, const char *s2)
  91{
  92        for (; *s2; ++s2)
  93                if (*s1++ != *s2)
  94                        return 0;
  95        return 1;
  96}
  97
  98/*
  99 * Older OF's require that when claiming a specific range of addresses,
 100 * we claim the physical space in the /memory node and the virtual
 101 * space in the chosen mmu node, and then do a map operation to
 102 * map virtual to physical.
 103 */
 104static int need_map = -1;
 105static ihandle chosen_mmu;
 106static phandle memory;
 107
 108static int check_of_version(void)
 109{
 110        phandle oprom, chosen;
 111        char version[64];
 112
 113        oprom = of_finddevice("/openprom");
 114        if (oprom == (phandle) -1)
 115                return 0;
 116        if (of_getprop(oprom, "model", version, sizeof(version)) <= 0)
 117                return 0;
 118        version[sizeof(version)-1] = 0;
 119        printf("OF version = '%s'\r\n", version);
 120        if (!string_match(version, "Open Firmware, 1.")
 121            && !string_match(version, "FirmWorks,3."))
 122                return 0;
 123        chosen = of_finddevice("/chosen");
 124        if (chosen == (phandle) -1) {
 125                chosen = of_finddevice("/chosen@0");
 126                if (chosen == (phandle) -1) {
 127                        printf("no chosen\n");
 128                        return 0;
 129                }
 130        }
 131        if (of_getprop(chosen, "mmu", &chosen_mmu, sizeof(chosen_mmu)) <= 0) {
 132                printf("no mmu\n");
 133                return 0;
 134        }
 135        memory = (ihandle) of_call_prom("open", 1, 1, "/memory");
 136        if (memory == (ihandle) -1) {
 137                memory = (ihandle) of_call_prom("open", 1, 1, "/memory@0");
 138                if (memory == (ihandle) -1) {
 139                        printf("no memory node\n");
 140                        return 0;
 141                }
 142        }
 143        printf("old OF detected\r\n");
 144        return 1;
 145}
 146
 147void *of_claim(unsigned long virt, unsigned long size, unsigned long align)
 148{
 149        int ret;
 150        unsigned int result;
 151
 152        if (need_map < 0)
 153                need_map = check_of_version();
 154        if (align || !need_map)
 155                return (void *) of_call_prom("claim", 3, 1, virt, size, align);
 156
 157        ret = of_call_prom_ret("call-method", 5, 2, &result, "claim", memory,
 158                               align, size, virt);
 159        if (ret != 0 || result == -1)
 160                return (void *) -1;
 161        ret = of_call_prom_ret("call-method", 5, 2, &result, "claim", chosen_mmu,
 162                               align, size, virt);
 163        /* 0x12 == coherent + read/write */
 164        ret = of_call_prom("call-method", 6, 1, "map", chosen_mmu,
 165                           0x12, size, virt, virt);
 166        return (void *) virt;
 167}
 168
 169void *of_vmlinux_alloc(unsigned long size)
 170{
 171        unsigned long start = (unsigned long)_start, end = (unsigned long)_end;
 172        void *addr;
 173        void *p;
 174
 175        /* With some older POWER4 firmware we need to claim the area the kernel
 176         * will reside in.  Newer firmwares don't need this so we just ignore
 177         * the return value.
 178         */
 179        addr = of_claim(start, end - start, 0);
 180        printf("Trying to claim from 0x%lx to 0x%lx (0x%lx) got %p\r\n",
 181               start, end, end - start, addr);
 182
 183        p = malloc(size);
 184        if (!p)
 185                fatal("Can't allocate memory for kernel image!\n\r");
 186
 187        return p;
 188}
 189
 190void of_exit(void)
 191{
 192        of_call_prom("exit", 0, 0);
 193}
 194
 195/*
 196 * OF device tree routines
 197 */
 198void *of_finddevice(const char *name)
 199{
 200        return (phandle) of_call_prom("finddevice", 1, 1, name);
 201}
 202
 203int of_getprop(const void *phandle, const char *name, void *buf,
 204               const int buflen)
 205{
 206        return of_call_prom("getprop", 4, 1, phandle, name, buf, buflen);
 207}
 208
 209int of_setprop(const void *phandle, const char *name, const void *buf,
 210               const int buflen)
 211{
 212        return of_call_prom("setprop", 4, 1, phandle, name, buf, buflen);
 213}
 214