source: mainline/boot/genarch/src/ofw.c@ 84239b1

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 84239b1 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 8 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 13.2 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 <arch/arch.h>
30#include <arch/ofw.h>
31#include <genarch/ofw.h>
32#include <printf.h>
33#include <stddef.h>
34#include <str.h>
35#include <align.h>
36#include <halt.h>
37
38#define RED(i) (((i) >> 5) & ((1 << 3) - 1))
39#define GREEN(i) (((i) >> 3) & ((1 << 2) - 1))
40#define BLUE(i) ((i) & ((1 << 3) - 1))
41#define CLIP(i) ((i) <= 255 ? (i) : 255)
42
43uintptr_t ofw_cif;
44
45phandle ofw_chosen;
46ihandle ofw_stdout;
47phandle ofw_root;
48ihandle ofw_mmu;
49ihandle ofw_memory_prop;
50phandle ofw_memory;
51
52static char path[OFW_TREE_PATH_MAX_LEN + 1];
53
54static ihandle ofw_open(const char *name)
55{
56 return (ihandle) ofw_call("open", 1, 1, NULL, name);
57}
58
59void ofw_init(void)
60{
61 ofw_chosen = ofw_find_device("/chosen");
62 if (ofw_chosen == (phandle) -1)
63 halt();
64
65 if ((ofw_ret_t) ofw_get_property(ofw_chosen, "stdout", &ofw_stdout,
66 sizeof(ofw_stdout)) <= 0)
67 ofw_stdout = 0;
68
69 ofw_root = ofw_find_device("/");
70 if (ofw_root == (phandle) -1) {
71 printf("Error: Unable to find / device, halting.\n");
72 halt();
73 }
74
75 if ((ofw_ret_t) ofw_get_property(ofw_chosen, "mmu", &ofw_mmu,
76 sizeof(ofw_mmu)) <= 0) {
77 printf("Error: Unable to get mmu property, halting.\n");
78 halt();
79 }
80 if ((ofw_ret_t) ofw_get_property(ofw_chosen, "memory", &ofw_memory_prop,
81 sizeof(ofw_memory_prop)) <= 0) {
82 printf("Error: Unable to get memory property, halting.\n");
83 halt();
84 }
85
86 ofw_memory = ofw_find_device("/memory");
87 if (ofw_memory == (phandle) -1) {
88 printf("Error: Unable to find /memory device, halting.\n");
89 halt();
90 }
91}
92
93/** Perform a call to OpenFirmware client interface.
94 *
95 * @param service String identifying the service requested.
96 * @param nargs Number of input arguments.
97 * @param nret Number of output arguments. This includes the return
98 * value.
99 * @param rets Buffer for output arguments or NULL. The buffer must
100 * accommodate nret - 1 items.
101 *
102 * @return Return value returned by the client interface.
103 *
104 */
105ofw_arg_t ofw_call(const char *service, const size_t nargs,
106 const size_t nret, ofw_arg_t *rets, ...)
107{
108 ofw_args_t args;
109 args.service = (ofw_arg_t) service;
110 args.nargs = nargs;
111 args.nret = nret;
112
113 va_list list;
114 va_start(list, rets);
115
116 size_t i;
117 for (i = 0; i < nargs; i++)
118 args.args[i] = va_arg(list, ofw_arg_t);
119
120 va_end(list);
121
122 for (i = 0; i < nret; i++)
123 args.args[i + nargs] = 0;
124
125 (void) ofw(&args);
126
127 for (i = 1; i < nret; i++)
128 rets[i - 1] = args.args[i + nargs];
129
130 return args.args[nargs];
131}
132
133phandle ofw_find_device(const char *name)
134{
135 return (phandle) ofw_call("finddevice", 1, 1, NULL, name);
136}
137
138ofw_arg_t ofw_get_property(const phandle device, const char *name, void *buf,
139 const size_t buflen)
140{
141 return ofw_call("getprop", 4, 1, NULL, device, name, buf, buflen);
142}
143
144ofw_arg_t ofw_get_proplen(const phandle device, const char *name)
145{
146 return ofw_call("getproplen", 2, 1, NULL, device, name);
147}
148
149ofw_arg_t ofw_next_property(const phandle device, char *previous, char *buf)
150{
151 return ofw_call("nextprop", 3, 1, NULL, device, previous, buf);
152}
153
154ofw_arg_t ofw_package_to_path(const phandle device, char *buf,
155 const size_t buflen)
156{
157 return ofw_call("package-to-path", 3, 1, NULL, device, buf, buflen);
158}
159
160size_t ofw_get_address_cells(const phandle device)
161{
162 ofw_prop_t ret = 1;
163
164 if ((ofw_ret_t) ofw_get_property(device, "#address-cells", &ret,
165 sizeof(ret)) <= 0)
166 if ((ofw_ret_t) ofw_get_property(ofw_root, "#address-cells", &ret,
167 sizeof(ret)) <= 0)
168 ret = OFW_ADDRESS_CELLS;
169
170 return (size_t) ret;
171}
172
173size_t ofw_get_size_cells(const phandle device)
174{
175 ofw_prop_t ret = 1;
176
177 if ((ofw_ret_t) ofw_get_property(device, "#size-cells", &ret,
178 sizeof(ret)) <= 0)
179 if ((ofw_ret_t) ofw_get_property(ofw_root, "#size-cells", &ret,
180 sizeof(ret)) <= 0)
181 ret = OFW_SIZE_CELLS;
182
183 return (size_t) ret;
184}
185
186phandle ofw_get_child_node(const phandle node)
187{
188 return (phandle) ofw_call("child", 1, 1, NULL, node);
189}
190
191phandle ofw_get_peer_node(const phandle node)
192{
193 return (phandle) ofw_call("peer", 1, 1, NULL, node);
194}
195
196void ofw_putchar(const char ch)
197{
198 if (ofw_stdout == 0)
199 return;
200
201 ofw_call("write", 3, 1, NULL, ofw_stdout, &ch, 1);
202}
203
204void *ofw_translate(const void *virt)
205{
206 ofw_arg_t result[4];
207 if (ofw_call("call-method", 4, 5, result, "translate", ofw_mmu,
208 virt, 0) != 0) {
209 printf("Error: mmu method translate failed, halting.\n");
210 halt();
211 }
212
213 if (result[0] == false) {
214 printf("Error: Unable to translate virtual address %p, halting.\n",
215 virt);
216 halt();
217 }
218
219#ifdef __32_BITS__
220 return (void *) result[2];
221#endif
222
223#ifdef __64_BITS__
224 return (void *) ((result[2] << 32) | result[3]);
225#endif
226}
227
228static void *ofw_claim_virt_internal(const void *virt, const size_t len,
229 const size_t alignment)
230{
231 ofw_arg_t addr;
232 if ((ofw_ret_t) ofw_call("call-method", 5, 2, &addr, "claim", ofw_mmu,
233 alignment, len, (ofw_arg_t) virt) != 0) {
234 printf("Error: mmu method claim failed, halting.\n");
235 halt();
236 }
237
238 return (void *) addr;
239}
240
241void ofw_claim_virt(const void *virt, const size_t len)
242{
243 void *addr = ofw_claim_virt_internal(virt, len, 0);
244 if (addr != virt) {
245 printf("Error: Unable to claim virtual memory %p (size %zu), halting.\n",
246 virt, len);
247 halt();
248 }
249}
250
251void *ofw_claim_virt_any(const size_t len, const size_t alignment)
252{
253 void *addr = ofw_claim_virt_internal(NULL, len, alignment);
254
255 if (addr == NULL) {
256 printf("Error: Unable to claim %zu bytes in virtual memory, halting.\n",
257 len);
258 halt();
259 }
260
261 return addr;
262}
263
264static void *ofw_claim_phys_internal(const void *phys, const size_t len,
265 const size_t alignment)
266{
267 /*
268 * Note that the return value check will help
269 * us to discover conflicts between OpenFirmware
270 * allocations and our use of physical memory.
271 * It is better to detect collisions here
272 * than to cope with weird errors later.
273 *
274 * So this is really not to make the loader
275 * more generic; it is here for debugging
276 * purposes.
277 */
278
279#ifdef __32_BITS__
280 ofw_arg_t retaddr[1];
281 if (ofw_call("call-method", 5, 2, retaddr, "claim",
282 ofw_memory_prop, alignment, len, (ofw_arg_t) phys) != 0) {
283 printf("Error: memory method claim failed, halting.\n");
284 halt();
285 }
286
287 return (void *) retaddr[0];
288#endif
289
290#ifdef __64_BITS__
291 ofw_arg_t retaddr[2];
292 if (ofw_call("call-method", 6, 3, retaddr, "claim",
293 ofw_memory_prop, alignment, len, ((ofw_arg_t) phys) >> 32,
294 ((ofw_arg_t) phys) & 0xffffffff) != 0) {
295 printf("Error: memory method claim failed, halting.\n");
296 halt();
297 }
298
299 return (void *) ((retaddr[0] << 32) | retaddr[1]);
300#endif
301}
302
303void ofw_claim_phys(const void *phys, const size_t len)
304{
305 void *addr = ofw_claim_phys_internal(phys, len, 0);
306 if (addr != phys) {
307 printf("Error: Unable to claim physical memory %p (size %zu), halting.\n",
308 phys, len);
309 halt();
310 }
311}
312
313void *ofw_claim_phys_any(const size_t len, const size_t alignment)
314{
315 void *addr = ofw_claim_phys_internal(NULL, len, alignment);
316 if (addr == NULL) {
317 printf("Error: Unable to claim %zu bytes in physical memory, halting.\n",
318 len);
319 halt();
320 }
321
322 return addr;
323}
324
325void ofw_map(const void *phys, const void *virt, const size_t size,
326 const ofw_arg_t mode)
327{
328 ofw_arg_t phys_hi;
329 ofw_arg_t phys_lo;
330
331#ifdef __32_BITS__
332 phys_hi = (ofw_arg_t) phys;
333 phys_lo = 0;
334#endif
335
336#ifdef __64_BITS__
337 phys_hi = (ofw_arg_t) phys >> 32;
338 phys_lo = (ofw_arg_t) phys & 0xffffffff;
339#endif
340
341 ofw_arg_t ret = ofw_call("call-method", 7, 1, NULL, "map", ofw_mmu, mode,
342 ALIGN_UP(size, PAGE_SIZE), virt, phys_hi, phys_lo);
343
344 if (ret != 0) {
345 printf("Error: Unable to map %p to %p (size %zu), halting.\n",
346 virt, phys, size);
347 halt();
348 }
349}
350
351/** Save OpenFirmware physical memory map.
352 *
353 * @param map Memory map structure where the map will be saved.
354 *
355 */
356void ofw_memmap(memmap_t *map)
357{
358 size_t ac = ofw_get_address_cells(ofw_memory) /
359 (sizeof(uintptr_t) / sizeof(uint32_t));
360 size_t sc = ofw_get_size_cells(ofw_memory) /
361 (sizeof(uintptr_t) / sizeof(uint32_t));
362
363 uintptr_t buf[((ac + sc) * MEMMAP_MAX_RECORDS)];
364
365 /* The number of bytes read */
366 ofw_ret_t ret = (ofw_ret_t) ofw_get_property(ofw_memory, "reg", buf,
367 sizeof(buf));
368 if (ret <= 0) {
369 printf("Error: Unable to get physical memory information, halting.\n");
370 halt();
371 }
372
373 size_t pos;
374 map->total = 0;
375 map->cnt = 0;
376 for (pos = 0; (pos < ret / sizeof(uintptr_t)) &&
377 (map->cnt < MEMMAP_MAX_RECORDS); pos += ac + sc) {
378 void *start = (void *) (buf[pos + ac - 1]);
379 uintptr_t size = buf[pos + ac + sc - 1];
380
381 /*
382 * This is a hot fix of the issue which occurs on machines
383 * where there are holes in the physical memory (such as
384 * SunBlade 1500). Should we detect a hole in the physical
385 * memory, we will ignore any memory detected behind
386 * the hole and pretend the hole does not exist.
387 */
388 if ((map->cnt > 0) && (map->zones[map->cnt - 1].start +
389 map->zones[map->cnt - 1].size < start))
390 break;
391
392 if (size > 0) {
393 map->zones[map->cnt].start = start;
394 map->zones[map->cnt].size = size;
395 map->cnt++;
396 map->total += size;
397 }
398 }
399
400 if (map->total == 0) {
401 printf("Error: No physical memory detected, halting.\n");
402 halt();
403 }
404}
405
406/** Allocate physical and virtual memory area and map it
407 *
408 * The allocated memory is always page-aligned.
409 *
410 * @param name Description of the memory area.
411 * @param base Virtual memory area address.
412 * @param base_pa Physical memory area address.
413 * @param size Requested size in bytes.
414 * @param min_pa Minimal allowed physical address.
415 *
416 */
417void ofw_alloc(const char *name, void **base, void **base_pa, const size_t size,
418 void *min_pa)
419{
420 do {
421 *base_pa = ofw_claim_phys_any(size, PAGE_SIZE);
422 } while (*base_pa <= min_pa);
423
424 *base = ofw_claim_virt_any(size, PAGE_SIZE);
425 ofw_map(*base_pa, *base, ALIGN_UP(size, PAGE_SIZE), (ofw_arg_t) -1);
426}
427
428static void ofw_setup_screen(phandle handle)
429{
430 /* Check for device type */
431 char device_type[OFW_TREE_PROPERTY_MAX_VALUELEN];
432 if ((ofw_ret_t) ofw_get_property(handle, "device_type", device_type,
433 OFW_TREE_PROPERTY_MAX_VALUELEN) <= 0)
434 return;
435
436 device_type[OFW_TREE_PROPERTY_MAX_VALUELEN - 1] = '\0';
437 if (str_cmp(device_type, "display") != 0)
438 return;
439
440 /* Check for 8 bit depth */
441 ofw_prop_t depth;
442 if ((ofw_ret_t) ofw_get_property(handle, "depth", &depth,
443 sizeof(depth)) <= 0)
444 depth = 0;
445
446 /* Get device path */
447 ofw_arg_t len = ofw_package_to_path(handle, path, OFW_TREE_PATH_MAX_LEN);
448 if (len == (ofw_arg_t) -1)
449 return;
450
451 path[len] = '\0';
452
453 /* Open the display to initialize it */
454 ihandle screen = ofw_open(path);
455 if (screen == (ihandle) -1)
456 return;
457
458 if (depth == 8) {
459 /* Setup the palette so that the (inverted) 3:2:3 scheme is usable */
460 size_t i;
461 for (i = 0; i < 256; i++) {
462 ofw_call("call-method", 6, 1, NULL, "color!", screen,
463 255 - i, CLIP(BLUE(i) * 37), GREEN(i) * 85, CLIP(RED(i) * 37));
464 }
465 }
466}
467
468static void ofw_setup_screens_internal(phandle current)
469{
470 while ((current != 0) && (current != (phandle) -1)) {
471 ofw_setup_screen(current);
472
473 /*
474 * Recursively process the potential child node.
475 */
476 phandle child = ofw_get_child_node(current);
477 if ((child != 0) && (child != (phandle) -1))
478 ofw_setup_screens_internal(child);
479
480 /*
481 * Iteratively process the next peer node.
482 * Note that recursion is a bad idea here.
483 * Due to the topology of the OpenFirmware device tree,
484 * the nesting of peer nodes could be to wide and the
485 * risk of overflowing the stack is too real.
486 */
487 phandle peer = ofw_get_peer_node(current);
488 if ((peer != 0) && (peer != (phandle) -1)) {
489 current = peer;
490 /*
491 * Process the peer in next iteration.
492 */
493 continue;
494 }
495
496 /*
497 * No more peers on this level.
498 */
499 break;
500 }
501}
502
503/** Setup all screens which can be detected.
504 *
505 * Open all screens which can be detected and set up the palette for the 8-bit
506 * color depth configuration so that the 3:2:3 color scheme can be used.
507 * Check that setting the palette makes sense (the color depth is not greater
508 * than 8).
509 *
510 */
511void ofw_setup_screens(void)
512{
513 ofw_setup_screens_internal(ofw_root);
514}
515
516void ofw_quiesce(void)
517{
518 ofw_call("quiesce", 0, 0, NULL);
519}
Note: See TracBrowser for help on using the repository browser.