0001
0002
0003
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
0018
0019 struct prom_args {
0020 __be32 service;
0021 __be32 nargs;
0022 __be32 nret;
0023 __be32 args[10];
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
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
0105
0106
0107
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
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
0182
0183
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
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 }