source: mainline/boot/genarch/ofw.c@ 4bc73fa

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 4bc73fa was 4bc73fa, checked in by Martin Decky <martin@…>, 17 years ago

call mmu_translate with corrent number of arguments

  • Property mode set to 100644
File size: 10.6 KB
Line 
1/*
2 * Copyright (c) 2005 Martin Decky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <ofw.h>
30#include <ofwarch.h>
31#include <printf.h>
32#include <asm.h>
33#include <types.h>
34
35uintptr_t ofw_cif;
36
37phandle ofw_chosen;
38ihandle ofw_stdout;
39phandle ofw_root;
40ihandle ofw_mmu;
41ihandle ofw_memory_prop;
42phandle ofw_memory;
43phandle ofw_aliases;
44
45void ofw_init(void)
46{
47 ofw_chosen = ofw_find_device("/chosen");
48 if (ofw_chosen == -1)
49 halt();
50
51 if (ofw_get_property(ofw_chosen, "stdout", &ofw_stdout,
52 sizeof(ofw_stdout)) <= 0)
53 ofw_stdout = 0;
54
55 ofw_root = ofw_find_device("/");
56 if (ofw_root == -1) {
57 puts("\r\nError: Unable to find / device, halted.\r\n");
58 halt();
59 }
60
61 if (ofw_get_property(ofw_chosen, "mmu", &ofw_mmu,
62 sizeof(ofw_mmu)) <= 0) {
63 puts("\r\nError: Unable to get mmu property, halted.\r\n");
64 halt();
65 }
66 if (ofw_get_property(ofw_chosen, "memory", &ofw_memory_prop,
67 sizeof(ofw_memory_prop)) <= 0) {
68 puts("\r\nError: Unable to get memory property, halted.\r\n");
69 halt();
70 }
71
72 ofw_memory = ofw_find_device("/memory");
73 if (ofw_memory == -1) {
74 puts("\r\nError: Unable to find /memory device, halted.\r\n");
75 halt();
76 }
77
78 ofw_aliases = ofw_find_device("/aliases");
79 if (ofw_aliases == -1) {
80 puts("\r\nError: Unable to find /aliases device, halted.\r\n");
81 halt();
82 }
83}
84
85/** Perform a call to OpenFirmware client interface.
86 *
87 * @param service String identifying the service requested.
88 * @param nargs Number of input arguments.
89 * @param nret Number of output arguments. This includes the return
90 * value.
91 * @param rets Buffer for output arguments or NULL. The buffer must
92 * accommodate nret - 1 items.
93 *
94 * @return Return value returned by the client interface.
95 */
96unsigned long
97ofw_call(const char *service, const int nargs, const int nret, ofw_arg_t *rets,
98 ...)
99{
100 va_list list;
101 ofw_args_t args;
102 int i;
103
104 args.service = (ofw_arg_t) service;
105 args.nargs = nargs;
106 args.nret = nret;
107
108 va_start(list, rets);
109 for (i = 0; i < nargs; i++)
110 args.args[i] = va_arg(list, ofw_arg_t);
111 va_end(list);
112
113 for (i = 0; i < nret; i++)
114 args.args[i + nargs] = 0;
115
116 (void) ofw(&args);
117
118 for (i = 1; i < nret; i++)
119 rets[i - 1] = args.args[i + nargs];
120
121 return args.args[nargs];
122}
123
124phandle ofw_find_device(const char *name)
125{
126 return ofw_call("finddevice", 1, 1, NULL, name);
127}
128
129int
130ofw_get_property(const phandle device, const char *name, void *buf,
131 const int buflen)
132{
133 return ofw_call("getprop", 4, 1, NULL, device, name, buf, buflen);
134}
135
136int ofw_get_proplen(const phandle device, const char *name)
137{
138 return ofw_call("getproplen", 2, 1, NULL, device, name);
139}
140
141int ofw_next_property(const phandle device, char *previous, char *buf)
142{
143 return ofw_call("nextprop", 3, 1, NULL, device, previous, buf);
144}
145
146int ofw_package_to_path(const phandle device, char *buf, const int buflen)
147{
148 return ofw_call("package-to-path", 3, 1, NULL, device, buf, buflen);
149}
150
151unsigned int ofw_get_address_cells(const phandle device)
152{
153 unsigned int ret = 1;
154
155 if (ofw_get_property(device, "#address-cells", &ret, sizeof(ret)) <= 0)
156 if (ofw_get_property(ofw_root, "#address-cells", &ret,
157 sizeof(ret)) <= 0)
158 ret = OFW_ADDRESS_CELLS;
159
160 return ret;
161}
162
163
164unsigned int ofw_get_size_cells(const phandle device)
165{
166 unsigned int ret;
167
168 if (ofw_get_property(device, "#size-cells", &ret, sizeof(ret)) <= 0)
169 if (ofw_get_property(ofw_root, "#size-cells", &ret,
170 sizeof(ret)) <= 0)
171 ret = OFW_SIZE_CELLS;
172
173 return ret;
174}
175
176phandle ofw_get_child_node(const phandle node)
177{
178 return ofw_call("child", 1, 1, NULL, node);
179}
180
181phandle ofw_get_peer_node(const phandle node)
182{
183 return ofw_call("peer", 1, 1, NULL, node);
184}
185
186static ihandle ofw_open(const char *name)
187{
188 return ofw_call("open", 1, 1, NULL, name);
189}
190
191
192void ofw_write(const char *str, const int len)
193{
194 if (ofw_stdout == 0)
195 return;
196
197 ofw_call("write", 3, 1, NULL, ofw_stdout, str, len);
198}
199
200
201void *ofw_translate(const void *virt)
202{
203 ofw_arg_t result[4];
204 int shift;
205
206 if (ofw_call("call-method", 4, 5, result, "translate", ofw_mmu,
207 virt, 0) != 0) {
208 puts("Error: MMU method translate() failed, halting.\n");
209 halt();
210 }
211
212 if (ofw_translate_failed(result[0]))
213 return NULL;
214
215 if (sizeof(unative_t) == 8)
216 shift = 32;
217 else
218 shift = 0;
219
220 return (void *) ((result[2] << shift) | result[3]);
221}
222
223void *ofw_claim_virt(const void *virt, const int len)
224{
225 ofw_arg_t retaddr;
226
227 if (ofw_call("call-method", 5, 2, &retaddr, "claim", ofw_mmu, 0, len,
228 virt) != 0) {
229 puts("Error: MMU method claim() failed, halting.\n");
230 halt();
231 }
232
233 return (void *) retaddr;
234}
235
236void *ofw_claim_phys(const void *phys, const int len)
237{
238 ofw_arg_t retaddr[2];
239 int shift;
240
241 if (sizeof(unative_t) == 8) {
242 shift = 32;
243 if (ofw_call("call-method", 6, 3, retaddr, "claim",
244 ofw_memory_prop, 0, len, ((uintptr_t) phys) >> shift,
245 ((uintptr_t) phys) & ((uint32_t) -1)) != 0) {
246 /*
247 * Note that this will help us to discover
248 * conflicts between OpenFirmware allocations
249 * and our use of physical memory.
250 * It is better to detect collisions here
251 * than to cope with weird errors later.
252 *
253 * So this is really not to make the loader
254 * more generic; it is here for debugging
255 * purposes.
256 */
257 puts("Error: memory method claim() failed, halting.\n");
258 halt();
259 }
260 } else {
261 shift = 0;
262 /*
263 * FIXME: the number of arguments is probably different...
264 */
265 puts("Error: 32-bit ofw_claim_phys not implemented.\n");
266 halt();
267 }
268
269 return (void *) ((retaddr[0] << shift) | retaddr[1]);
270}
271
272int ofw_map(const void *phys, const void *virt, const int size, const int mode)
273{
274 uintptr_t phys_hi, phys_lo;
275
276 if (sizeof(unative_t) == 8) {
277 int shift = 32;
278 phys_hi = (uintptr_t) phys >> shift;
279 phys_lo = (uintptr_t) phys & 0xffffffff;
280 } else {
281 phys_hi = 0;
282 phys_lo = (uintptr_t) phys;
283 }
284
285 return ofw_call("call-method", 7, 1, NULL, "map", ofw_mmu, mode, size,
286 virt, phys_hi, phys_lo);
287}
288
289/** Save OpenFirmware physical memory map.
290 *
291 * @param map Memory map structure where the map will be saved.
292 *
293 * @return Zero on failure, non-zero on success.
294 */
295int ofw_memmap(memmap_t *map)
296{
297 unsigned int ac = ofw_get_address_cells(ofw_memory) /
298 (sizeof(uintptr_t) / sizeof(uint32_t));
299 unsigned int sc = ofw_get_size_cells(ofw_memory) /
300 (sizeof(uintptr_t) / sizeof(uint32_t));
301
302 uintptr_t buf[((ac + sc) * MEMMAP_MAX_RECORDS)];
303 int ret = ofw_get_property(ofw_memory, "reg", buf, sizeof(buf));
304 if (ret <= 0) /* ret is the number of written bytes */
305 return false;
306
307 int pos;
308 map->total = 0;
309 map->count = 0;
310 for (pos = 0; (pos < ret / sizeof(uintptr_t)) &&
311 (map->count < MEMMAP_MAX_RECORDS); pos += ac + sc) {
312 void *start = (void *) (buf[pos + ac - 1]);
313 unsigned int size = buf[pos + ac + sc - 1];
314
315 /*
316 * This is a hot fix of the issue which occurs on machines
317 * where there are holes in the physical memory (such as
318 * SunBlade 1500). Should we detect a hole in the physical
319 * memory, we will ignore any memory detected behind
320 * the hole and pretend the hole does not exist.
321 */
322 if ((map->count > 0) && (map->zones[map->count - 1].start +
323 map->zones[map->count - 1].size < start))
324 break;
325
326 if (size > 0) {
327 map->zones[map->count].start = start;
328 map->zones[map->count].size = size;
329 map->count++;
330 map->total += size;
331 }
332 }
333
334 return true;
335}
336
337int ofw_screen(screen_t *screen)
338{
339 char device_name[BUF_SIZE];
340 uint32_t virtaddr;
341
342 if (ofw_get_property(ofw_aliases, "screen", device_name,
343 sizeof(device_name)) <= 0)
344 return false;
345
346 phandle device = ofw_find_device(device_name);
347 if (device == -1)
348 return false;
349
350 if (ofw_get_property(device, "address", &virtaddr,
351 sizeof(virtaddr)) <= 0)
352 return false;
353
354 screen->addr = (void *) ((uintptr_t) virtaddr);
355
356 if (ofw_get_property(device, "width", &screen->width,
357 sizeof(screen->width)) <= 0)
358 return false;
359
360 if (ofw_get_property(device, "height", &screen->height,
361 sizeof(screen->height)) <= 0)
362 return false;
363
364 if (ofw_get_property(device, "depth", &screen->bpp,
365 sizeof(screen->bpp)) <= 0)
366 return false;
367
368 if (ofw_get_property(device, "linebytes", &screen->scanline,
369 sizeof(screen->scanline)) <= 0)
370 return false;
371
372 return true;
373}
374
375/**
376 * Sets up the palette for the 8-bit color depth configuration so that the
377 * 3:2:3 color scheme can be used. Checks that setting the palette makes sense
378 * (appropriate nodes exist in the OBP tree and the color depth is not greater
379 * than 8).
380 *
381 * @return true if the palette has been set, false otherwise
382 */
383int setup_palette(void)
384{
385 char device_name[BUF_SIZE];
386
387 /* resolve alias */
388 if (ofw_get_property(ofw_aliases, "screen", device_name,
389 sizeof(device_name)) <= 0)
390 return false;
391
392 /* for depth greater than 8 it makes no sense to set up the palette */
393 uint32_t depth;
394 phandle device = ofw_find_device(device_name);
395 if (device == -1)
396 return false;
397 if (ofw_get_property(device, "depth", &depth, sizeof(uint32_t)) <= 0)
398 return false;
399 if (depth != 8)
400 return false;
401
402 /* required in order to be able to make a method call */
403 ihandle screen = ofw_open(device_name);
404 if (screen == -1)
405 return false;
406
407 /* setup the palette so that the (inverted) 3:2:3 scheme is usable */
408 unsigned int i;
409 for (i = 0; i < 256; i++)
410 if (ofw_call("call-method", 6, 1, NULL, "color!", screen,
411 255 - i,
412 i << 5,
413 (i >> 3) << 6,
414 (i >> 5) << 5) != 0);
415 return true;
416}
417
418void ofw_quiesce(void)
419{
420 ofw_call("quiesce", 0, 0, NULL);
421}
Note: See TracBrowser for help on using the repository browser.