Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (C) Paul Mackerras 1997.
0004  */
0005 #include <stddef.h>
0006 #include "types.h"
0007 #include "elf.h"
0008 #include "string.h"
0009 #include "stdio.h"
0010 #include "page.h"
0011 #include "ops.h"
0012 
0013 #include "of.h"
0014 
0015 typedef u32 prom_arg_t;
0016 
0017 /* The following structure is used to communicate with open firmware.
0018  * All arguments in and out are in big endian format. */
0019 struct prom_args {
0020     __be32 service; /* Address of service name string. */
0021     __be32 nargs;   /* Number of input arguments. */
0022     __be32 nret;    /* Number of output arguments. */
0023     __be32 args[10];    /* Input/output arguments. */
0024 };
0025 
0026 #ifdef __powerpc64__
0027 extern int prom(void *);
0028 #else
0029 static int (*prom) (void *);
0030 #endif
0031 
0032 void of_init(void *promptr)
0033 {
0034 #ifndef __powerpc64__
0035     prom = (int (*)(void *))promptr;
0036 #endif
0037 }
0038 
0039 #define ADDR(x)     (u32)(unsigned long)(x)
0040 
0041 int of_call_prom(const char *service, int nargs, int nret, ...)
0042 {
0043     int i;
0044     struct prom_args args;
0045     va_list list;
0046 
0047     args.service = cpu_to_be32(ADDR(service));
0048     args.nargs = cpu_to_be32(nargs);
0049     args.nret = cpu_to_be32(nret);
0050 
0051     va_start(list, nret);
0052     for (i = 0; i < nargs; i++)
0053         args.args[i] = cpu_to_be32(va_arg(list, prom_arg_t));
0054     va_end(list);
0055 
0056     for (i = 0; i < nret; i++)
0057         args.args[nargs+i] = 0;
0058 
0059     if (prom(&args) < 0)
0060         return PROM_ERROR;
0061 
0062     return (nret > 0) ? be32_to_cpu(args.args[nargs]) : 0;
0063 }
0064 
0065 static int of_call_prom_ret(const char *service, int nargs, int nret,
0066                 prom_arg_t *rets, ...)
0067 {
0068     int i;
0069     struct prom_args args;
0070     va_list list;
0071 
0072     args.service = cpu_to_be32(ADDR(service));
0073     args.nargs = cpu_to_be32(nargs);
0074     args.nret = cpu_to_be32(nret);
0075 
0076     va_start(list, rets);
0077     for (i = 0; i < nargs; i++)
0078         args.args[i] = cpu_to_be32(va_arg(list, prom_arg_t));
0079     va_end(list);
0080 
0081     for (i = 0; i < nret; i++)
0082         args.args[nargs+i] = 0;
0083 
0084     if (prom(&args) < 0)
0085         return PROM_ERROR;
0086 
0087     if (rets != NULL)
0088         for (i = 1; i < nret; ++i)
0089             rets[i-1] = be32_to_cpu(args.args[nargs+i]);
0090 
0091     return (nret > 0) ? be32_to_cpu(args.args[nargs]) : 0;
0092 }
0093 
0094 /* returns true if s2 is a prefix of s1 */
0095 static int string_match(const char *s1, const char *s2)
0096 {
0097     for (; *s2; ++s2)
0098         if (*s1++ != *s2)
0099             return 0;
0100     return 1;
0101 }
0102 
0103 /*
0104  * Older OF's require that when claiming a specific range of addresses,
0105  * we claim the physical space in the /memory node and the virtual
0106  * space in the chosen mmu node, and then do a map operation to
0107  * map virtual to physical.
0108  */
0109 static int need_map = -1;
0110 static ihandle chosen_mmu;
0111 static ihandle memory;
0112 
0113 static int check_of_version(void)
0114 {
0115     phandle oprom, chosen;
0116     char version[64];
0117 
0118     oprom = of_finddevice("/openprom");
0119     if (oprom == (phandle) -1)
0120         return 0;
0121     if (of_getprop(oprom, "model", version, sizeof(version)) <= 0)
0122         return 0;
0123     version[sizeof(version)-1] = 0;
0124     printf("OF version = '%s'\r\n", version);
0125     if (!string_match(version, "Open Firmware, 1.")
0126         && !string_match(version, "FirmWorks,3."))
0127         return 0;
0128     chosen = of_finddevice("/chosen");
0129     if (chosen == (phandle) -1) {
0130         chosen = of_finddevice("/chosen@0");
0131         if (chosen == (phandle) -1) {
0132             printf("no chosen\n");
0133             return 0;
0134         }
0135     }
0136     if (of_getprop(chosen, "mmu", &chosen_mmu, sizeof(chosen_mmu)) <= 0) {
0137         printf("no mmu\n");
0138         return 0;
0139     }
0140     memory = of_call_prom("open", 1, 1, "/memory");
0141     if (memory == PROM_ERROR) {
0142         memory = of_call_prom("open", 1, 1, "/memory@0");
0143         if (memory == PROM_ERROR) {
0144             printf("no memory node\n");
0145             return 0;
0146         }
0147     }
0148     printf("old OF detected\r\n");
0149     return 1;
0150 }
0151 
0152 unsigned int of_claim(unsigned long virt, unsigned long size,
0153               unsigned long align)
0154 {
0155     int ret;
0156     prom_arg_t result;
0157 
0158     if (need_map < 0)
0159         need_map = check_of_version();
0160     if (align || !need_map)
0161         return of_call_prom("claim", 3, 1, virt, size, align);
0162 
0163     ret = of_call_prom_ret("call-method", 5, 2, &result, "claim", memory,
0164                    align, size, virt);
0165     if (ret != 0 || result == -1)
0166         return  -1;
0167     ret = of_call_prom_ret("call-method", 5, 2, &result, "claim", chosen_mmu,
0168                    align, size, virt);
0169     /* 0x12 == coherent + read/write */
0170     ret = of_call_prom("call-method", 6, 1, "map", chosen_mmu,
0171                0x12, size, virt, virt);
0172     return virt;
0173 }
0174 
0175 void *of_vmlinux_alloc(unsigned long size)
0176 {
0177     unsigned long start = (unsigned long)_start, end = (unsigned long)_end;
0178     unsigned long addr;
0179     void *p;
0180 
0181     /* With some older POWER4 firmware we need to claim the area the kernel
0182      * will reside in.  Newer firmwares don't need this so we just ignore
0183      * the return value.
0184      */
0185     addr = (unsigned long) of_claim(start, end - start, 0);
0186     printf("Trying to claim from 0x%lx to 0x%lx (0x%lx) got %lx\r\n",
0187            start, end, end - start, addr);
0188 
0189     p = malloc(size);
0190     if (!p)
0191         fatal("Can't allocate memory for kernel image!\n\r");
0192 
0193     return p;
0194 }
0195 
0196 void of_exit(void)
0197 {
0198     of_call_prom("exit", 0, 0);
0199 }
0200 
0201 /*
0202  * OF device tree routines
0203  */
0204 void *of_finddevice(const char *name)
0205 {
0206     return (void *) (unsigned long) of_call_prom("finddevice", 1, 1, name);
0207 }
0208 
0209 int of_getprop(const void *phandle, const char *name, void *buf,
0210            const int buflen)
0211 {
0212     return of_call_prom("getprop", 4, 1, phandle, name, buf, buflen);
0213 }
0214 
0215 int of_setprop(const void *phandle, const char *name, const void *buf,
0216            const int buflen)
0217 {
0218     return of_call_prom("setprop", 4, 1, phandle, name, buf, buflen);
0219 }