Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/powerpc/ofw/ofw_real.c
39507 views
1
/* $NetBSD: Locore.c,v 1.7 2000/08/20 07:04:59 tsubai Exp $ */
2
3
/*-
4
* SPDX-License-Identifier:BSD-4-Clause AND BSD-2-Clause
5
*
6
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
7
* Copyright (C) 1995, 1996 TooLs GmbH.
8
* All rights reserved.
9
*
10
* Redistribution and use in source and binary forms, with or without
11
* modification, are permitted provided that the following conditions
12
* are met:
13
* 1. Redistributions of source code must retain the above copyright
14
* notice, this list of conditions and the following disclaimer.
15
* 2. Redistributions in binary form must reproduce the above copyright
16
* notice, this list of conditions and the following disclaimer in the
17
* documentation and/or other materials provided with the distribution.
18
* 3. All advertising materials mentioning features or use of this software
19
* must display the following acknowledgement:
20
* This product includes software developed by TooLs GmbH.
21
* 4. The name of TooLs GmbH may not be used to endorse or promote products
22
* derived from this software without specific prior written permission.
23
*
24
* THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
25
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
30
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
33
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
*/
35
/*-
36
* Copyright (C) 2000 Benno Rice.
37
* All rights reserved.
38
*
39
* Redistribution and use in source and binary forms, with or without
40
* modification, are permitted provided that the following conditions
41
* are met:
42
* 1. Redistributions of source code must retain the above copyright
43
* notice, this list of conditions and the following disclaimer.
44
* 2. Redistributions in binary form must reproduce the above copyright
45
* notice, this list of conditions and the following disclaimer in the
46
* documentation and/or other materials provided with the distribution.
47
*
48
* THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
49
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
50
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
51
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
52
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
53
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
54
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
55
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
56
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
57
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58
*/
59
60
#include <sys/cdefs.h>
61
#include <sys/endian.h>
62
#include <sys/param.h>
63
#include <sys/kernel.h>
64
#include <sys/lock.h>
65
#include <sys/mutex.h>
66
#include <sys/stdarg.h>
67
#include <sys/systm.h>
68
69
#include <vm/vm.h>
70
#include <vm/vm_page.h>
71
#include <vm/pmap.h>
72
73
#include <machine/bus.h>
74
#include <machine/md_var.h>
75
#include <machine/ofw_machdep.h>
76
77
#include <dev/ofw/openfirm.h>
78
#include <dev/ofw/ofwvar.h>
79
#include "ofw_if.h"
80
81
static int ofw_real_init(ofw_t, void *openfirm);
82
static int ofw_real_test(ofw_t, const char *name);
83
static phandle_t ofw_real_peer(ofw_t, phandle_t node);
84
static phandle_t ofw_real_child(ofw_t, phandle_t node);
85
static phandle_t ofw_real_parent(ofw_t, phandle_t node);
86
static phandle_t ofw_real_instance_to_package(ofw_t, ihandle_t instance);
87
static ssize_t ofw_real_getproplen(ofw_t, phandle_t package,
88
const char *propname);
89
static ssize_t ofw_real_getprop(ofw_t, phandle_t package, const char *propname,
90
void *buf, size_t buflen);
91
static int ofw_real_nextprop(ofw_t, phandle_t package, const char *previous,
92
char *buf, size_t);
93
static int ofw_real_setprop(ofw_t, phandle_t package, const char *propname,
94
const void *buf, size_t len);
95
static ssize_t ofw_real_canon(ofw_t, const char *device, char *buf, size_t len);
96
static phandle_t ofw_real_finddevice(ofw_t, const char *device);
97
static ssize_t ofw_real_instance_to_path(ofw_t, ihandle_t instance, char *buf,
98
size_t len);
99
static ssize_t ofw_real_package_to_path(ofw_t, phandle_t package, char *buf,
100
size_t len);
101
static int ofw_real_call_method(ofw_t, ihandle_t instance, const char *method,
102
int nargs, int nreturns, cell_t *args_and_returns);
103
static int ofw_real_interpret(ofw_t ofw, const char *cmd, int nreturns,
104
cell_t *returns);
105
static ihandle_t ofw_real_open(ofw_t, const char *device);
106
static void ofw_real_close(ofw_t, ihandle_t instance);
107
static ssize_t ofw_real_read(ofw_t, ihandle_t instance, void *addr, size_t len);
108
static ssize_t ofw_real_write(ofw_t, ihandle_t instance, const void *addr,
109
size_t len);
110
static int ofw_real_seek(ofw_t, ihandle_t instance, u_int64_t pos);
111
static caddr_t ofw_real_claim(ofw_t, void *virt, size_t size, u_int align);
112
static void ofw_real_release(ofw_t, void *virt, size_t size);
113
static void ofw_real_enter(ofw_t);
114
static void ofw_real_exit(ofw_t);
115
116
static ofw_method_t ofw_real_methods[] = {
117
OFWMETHOD(ofw_init, ofw_real_init),
118
OFWMETHOD(ofw_peer, ofw_real_peer),
119
OFWMETHOD(ofw_child, ofw_real_child),
120
OFWMETHOD(ofw_parent, ofw_real_parent),
121
OFWMETHOD(ofw_instance_to_package, ofw_real_instance_to_package),
122
OFWMETHOD(ofw_getproplen, ofw_real_getproplen),
123
OFWMETHOD(ofw_getprop, ofw_real_getprop),
124
OFWMETHOD(ofw_nextprop, ofw_real_nextprop),
125
OFWMETHOD(ofw_setprop, ofw_real_setprop),
126
OFWMETHOD(ofw_canon, ofw_real_canon),
127
OFWMETHOD(ofw_finddevice, ofw_real_finddevice),
128
OFWMETHOD(ofw_instance_to_path, ofw_real_instance_to_path),
129
OFWMETHOD(ofw_package_to_path, ofw_real_package_to_path),
130
131
OFWMETHOD(ofw_test, ofw_real_test),
132
OFWMETHOD(ofw_call_method, ofw_real_call_method),
133
OFWMETHOD(ofw_interpret, ofw_real_interpret),
134
OFWMETHOD(ofw_open, ofw_real_open),
135
OFWMETHOD(ofw_close, ofw_real_close),
136
OFWMETHOD(ofw_read, ofw_real_read),
137
OFWMETHOD(ofw_write, ofw_real_write),
138
OFWMETHOD(ofw_seek, ofw_real_seek),
139
OFWMETHOD(ofw_claim, ofw_real_claim),
140
OFWMETHOD(ofw_release, ofw_real_release),
141
OFWMETHOD(ofw_enter, ofw_real_enter),
142
OFWMETHOD(ofw_exit, ofw_real_exit),
143
{ 0, 0 }
144
};
145
146
static ofw_def_t ofw_real = {
147
OFW_STD_REAL,
148
ofw_real_methods,
149
0
150
};
151
OFW_DEF(ofw_real);
152
153
static ofw_def_t ofw_32bit = {
154
OFW_STD_32BIT,
155
ofw_real_methods,
156
0
157
};
158
OFW_DEF(ofw_32bit);
159
160
static MALLOC_DEFINE(M_OFWREAL, "ofwreal",
161
"Open Firmware Real Mode Bounce Page");
162
163
static int (*openfirmware)(void *);
164
165
static vm_offset_t of_bounce_phys;
166
static caddr_t of_bounce_virt;
167
static off_t of_bounce_offset;
168
static size_t of_bounce_size;
169
170
#define IN(x) htobe32(x)
171
#define OUT(x) be32toh(x)
172
173
/*
174
* To be able to use OFW console on PPC, that requires real mode OFW,
175
* the mutex that guards the mapping/unmapping of virtual to physical
176
* buffers (of_real_mtx) must be of SPIN type. This is needed because
177
* kernel console first locks a SPIN mutex before calling OFW real.
178
* By default, of_real_mtx is a sleepable mutex. To make it of SPIN
179
* type, use the following tunnable:
180
* machdep.ofw.mtx_spin=1
181
*
182
* Besides that, a few more tunables are needed to select and use the
183
* OFW console with real mode OFW.
184
*
185
* In order to disable the use of OFW FrameBuffer and fallback to the
186
* OFW console, use:
187
* hw.ofwfb.disable=1
188
*
189
* To disable the use of FDT (that doesn't support OFW read/write methods)
190
* and use real OFW instead, unset the following loader variable:
191
* unset usefdt
192
*
193
* OFW is put in quiesce state in early kernel boot, which usually disables
194
* OFW read/write capabilities (in QEMU write continue to work, but
195
* read doesn't). To avoid OFW quiesce, use:
196
* debug.quiesce_ofw=0
197
*
198
* Note that disabling OFW quiesce can cause conflicts between kernel and
199
* OFW trying to control the same hardware. Thus, it must be used with care.
200
* Some conflicts can be avoided by disabling kernel drivers with hints.
201
* For instance, to disable a xhci controller and an USB keyboard connected
202
* to it, that may be already being used for input by OFW, use:
203
* hint.xhci.0.disabled=1
204
*/
205
206
static struct mtx of_bounce_mtx;
207
static struct mtx of_spin_mtx;
208
static struct mtx *of_real_mtx;
209
static void (*of_mtx_lock)(void);
210
static void (*of_mtx_unlock)(void);
211
212
extern int ofw_real_mode;
213
214
/*
215
* After the VM is up, allocate a wired, low memory bounce page.
216
*/
217
218
static void ofw_real_bounce_alloc(void *);
219
220
SYSINIT(ofw_real_bounce_alloc, SI_SUB_KMEM, SI_ORDER_ANY,
221
ofw_real_bounce_alloc, NULL);
222
223
static void
224
ofw_real_mtx_lock_spin(void)
225
{
226
mtx_lock_spin(of_real_mtx);
227
}
228
229
static void
230
ofw_real_mtx_lock(void)
231
{
232
mtx_lock(of_real_mtx);
233
}
234
235
static void
236
ofw_real_mtx_unlock_spin(void)
237
{
238
mtx_unlock_spin(of_real_mtx);
239
}
240
241
static void
242
ofw_real_mtx_unlock(void)
243
{
244
mtx_unlock(of_real_mtx);
245
}
246
247
static void
248
ofw_real_start(void)
249
{
250
(*of_mtx_lock)();
251
of_bounce_offset = 0;
252
}
253
254
static void
255
ofw_real_stop(void)
256
{
257
(*of_mtx_unlock)();
258
}
259
260
static void
261
ofw_real_bounce_alloc(void *junk)
262
{
263
caddr_t temp;
264
265
/*
266
* Check that ofw_real is actually in use before allocating wads
267
* of memory. Do this by checking if our mutex has been set up.
268
*/
269
if (!mtx_initialized(&of_bounce_mtx))
270
return;
271
272
/*
273
* Allocate a page of contiguous, wired physical memory that can
274
* fit into a 32-bit address space and accessed from real mode.
275
*/
276
temp = contigmalloc(4 * PAGE_SIZE, M_OFWREAL, 0, 0,
277
ulmin(platform_real_maxaddr(), BUS_SPACE_MAXADDR_32BIT), PAGE_SIZE,
278
4 * PAGE_SIZE);
279
if (temp == NULL)
280
panic("%s: Not able to allocated contiguous memory\n", __func__);
281
282
mtx_lock(&of_bounce_mtx);
283
284
of_bounce_virt = temp;
285
286
of_bounce_phys = vtophys(of_bounce_virt);
287
of_bounce_size = 4 * PAGE_SIZE;
288
289
/*
290
* For virtual-mode OF, direct map this physical address so that
291
* we have a 32-bit virtual address to give OF.
292
*/
293
294
if (!ofw_real_mode && (!hw_direct_map || DMAP_BASE_ADDRESS != 0))
295
pmap_kenter(of_bounce_phys, of_bounce_phys);
296
297
mtx_unlock(&of_bounce_mtx);
298
}
299
300
static cell_t
301
ofw_real_map(const void *buf, size_t len)
302
{
303
static char emergency_buffer[255];
304
cell_t phys;
305
306
mtx_assert(of_real_mtx, MA_OWNED);
307
308
if (of_bounce_virt == NULL) {
309
/*
310
* If we haven't set up the MMU, then buf is guaranteed
311
* to be accessible to OF, because the only memory we
312
* can use right now is memory mapped by firmware.
313
*/
314
if (!pmap_bootstrapped)
315
return (cell_t)((uintptr_t)buf & ~DMAP_BASE_ADDRESS);
316
317
/*
318
* XXX: It is possible for us to get called before the VM has
319
* come online, but after the MMU is up. We don't have the
320
* bounce buffer yet, but can no longer presume a 1:1 mapping.
321
* Copy into the emergency buffer, and reset at the end.
322
*/
323
of_bounce_virt = emergency_buffer;
324
of_bounce_phys = (vm_offset_t)of_bounce_virt &
325
~DMAP_BASE_ADDRESS;
326
of_bounce_size = sizeof(emergency_buffer);
327
}
328
329
/*
330
* Make sure the bounce page offset satisfies any reasonable
331
* alignment constraint.
332
*/
333
of_bounce_offset += sizeof(register_t) -
334
(of_bounce_offset % sizeof(register_t));
335
336
if (of_bounce_offset + len > of_bounce_size) {
337
panic("Oversize Open Firmware call!");
338
return 0;
339
}
340
341
if (buf != NULL)
342
memcpy(of_bounce_virt + of_bounce_offset, buf, len);
343
else
344
return (0);
345
346
phys = of_bounce_phys + of_bounce_offset;
347
348
of_bounce_offset += len;
349
350
return (phys);
351
}
352
353
static void
354
ofw_real_unmap(cell_t physaddr, void *buf, size_t len)
355
{
356
mtx_assert(of_real_mtx, MA_OWNED);
357
358
if (of_bounce_virt == NULL)
359
return;
360
361
if (physaddr == 0)
362
return;
363
364
memcpy(buf,of_bounce_virt + (physaddr - of_bounce_phys),len);
365
}
366
367
/* Initialiser */
368
369
static int
370
ofw_real_init(ofw_t ofw, void *openfirm)
371
{
372
int mtx_spin;
373
374
openfirmware = (int (*)(void *))openfirm;
375
mtx_init(&of_bounce_mtx, "OF Bounce Page", NULL, MTX_DEF);
376
377
mtx_spin = 0;
378
TUNABLE_INT_FETCH("machdep.ofw.mtx_spin", &mtx_spin);
379
if (mtx_spin) {
380
mtx_init(&of_spin_mtx, "OF Real", NULL, MTX_SPIN);
381
of_real_mtx = &of_spin_mtx;
382
of_mtx_lock = ofw_real_mtx_lock_spin;
383
of_mtx_unlock = ofw_real_mtx_unlock_spin;
384
} else {
385
of_real_mtx = &of_bounce_mtx;
386
of_mtx_lock = ofw_real_mtx_lock;
387
of_mtx_unlock = ofw_real_mtx_unlock;
388
}
389
390
of_bounce_virt = NULL;
391
return (0);
392
}
393
394
/*
395
* Generic functions
396
*/
397
398
/* Test to see if a service exists. */
399
static int
400
ofw_real_test(ofw_t ofw, const char *name)
401
{
402
vm_offset_t argsptr;
403
struct {
404
cell_t name;
405
cell_t nargs;
406
cell_t nreturns;
407
cell_t service;
408
cell_t missing;
409
} args;
410
411
args.name = IN((cell_t)(uintptr_t)"test");
412
args.nargs = IN(1);
413
args.nreturns = IN(1);
414
415
ofw_real_start();
416
417
args.service = IN(ofw_real_map(name, strlen(name) + 1));
418
argsptr = ofw_real_map(&args, sizeof(args));
419
if (args.service == 0 || openfirmware((void *)argsptr) == -1) {
420
ofw_real_stop();
421
return (-1);
422
}
423
ofw_real_unmap(argsptr, &args, sizeof(args));
424
ofw_real_stop();
425
return (OUT(args.missing));
426
}
427
428
/*
429
* Device tree functions
430
*/
431
432
/* Return the next sibling of this node or 0. */
433
static phandle_t
434
ofw_real_peer(ofw_t ofw, phandle_t node)
435
{
436
vm_offset_t argsptr;
437
struct {
438
cell_t name;
439
cell_t nargs;
440
cell_t nreturns;
441
cell_t node;
442
cell_t next;
443
} args;
444
445
args.name = IN((cell_t)(uintptr_t)"peer");
446
args.nargs = IN(1);
447
args.nreturns = IN(1);
448
449
args.node = IN(node);
450
ofw_real_start();
451
argsptr = ofw_real_map(&args, sizeof(args));
452
if (openfirmware((void *)argsptr) == -1) {
453
ofw_real_stop();
454
return (0);
455
}
456
ofw_real_unmap(argsptr, &args, sizeof(args));
457
ofw_real_stop();
458
return (OUT(args.next));
459
}
460
461
/* Return the first child of this node or 0. */
462
static phandle_t
463
ofw_real_child(ofw_t ofw, phandle_t node)
464
{
465
vm_offset_t argsptr;
466
struct {
467
cell_t name;
468
cell_t nargs;
469
cell_t nreturns;
470
cell_t node;
471
cell_t child;
472
} args;
473
474
args.name = IN((cell_t)(uintptr_t)"child");
475
args.nargs = IN(1);
476
args.nreturns = IN(1);
477
478
args.node = IN(node);
479
ofw_real_start();
480
argsptr = ofw_real_map(&args, sizeof(args));
481
if (openfirmware((void *)argsptr) == -1) {
482
ofw_real_stop();
483
return (0);
484
}
485
ofw_real_unmap(argsptr, &args, sizeof(args));
486
ofw_real_stop();
487
return (OUT(args.child));
488
}
489
490
/* Return the parent of this node or 0. */
491
static phandle_t
492
ofw_real_parent(ofw_t ofw, phandle_t node)
493
{
494
vm_offset_t argsptr;
495
struct {
496
cell_t name;
497
cell_t nargs;
498
cell_t nreturns;
499
cell_t node;
500
cell_t parent;
501
} args;
502
503
args.name = IN((cell_t)(uintptr_t)"parent");
504
args.nargs = IN(1);
505
args.nreturns = IN(1);
506
507
args.node = IN(node);
508
ofw_real_start();
509
argsptr = ofw_real_map(&args, sizeof(args));
510
if (openfirmware((void *)argsptr) == -1) {
511
ofw_real_stop();
512
return (0);
513
}
514
ofw_real_unmap(argsptr, &args, sizeof(args));
515
ofw_real_stop();
516
return (OUT(args.parent));
517
}
518
519
/* Return the package handle that corresponds to an instance handle. */
520
static phandle_t
521
ofw_real_instance_to_package(ofw_t ofw, ihandle_t instance)
522
{
523
vm_offset_t argsptr;
524
struct {
525
cell_t name;
526
cell_t nargs;
527
cell_t nreturns;
528
cell_t instance;
529
cell_t package;
530
} args;
531
532
args.name = IN((cell_t)(uintptr_t)"instance-to-package");
533
args.nargs = IN(1);
534
args.nreturns = IN(1);
535
536
args.instance = IN(instance);
537
ofw_real_start();
538
argsptr = ofw_real_map(&args, sizeof(args));
539
if (openfirmware((void *)argsptr) == -1) {
540
ofw_real_stop();
541
return (-1);
542
}
543
ofw_real_unmap(argsptr, &args, sizeof(args));
544
ofw_real_stop();
545
return (OUT(args.package));
546
}
547
548
/* Get the length of a property of a package. */
549
static ssize_t
550
ofw_real_getproplen(ofw_t ofw, phandle_t package, const char *propname)
551
{
552
vm_offset_t argsptr;
553
struct {
554
cell_t name;
555
cell_t nargs;
556
cell_t nreturns;
557
cell_t package;
558
cell_t propname;
559
int32_t proplen;
560
} args;
561
562
args.name = IN((cell_t)(uintptr_t)"getproplen");
563
args.nargs = IN(2);
564
args.nreturns = IN(1);
565
566
ofw_real_start();
567
568
args.package = IN(package);
569
args.propname = IN(ofw_real_map(propname, strlen(propname) + 1));
570
argsptr = ofw_real_map(&args, sizeof(args));
571
if (args.propname == 0 || openfirmware((void *)argsptr) == -1) {
572
ofw_real_stop();
573
return (-1);
574
}
575
ofw_real_unmap(argsptr, &args, sizeof(args));
576
ofw_real_stop();
577
return ((ssize_t)(int32_t)OUT(args.proplen));
578
}
579
580
/* Get the value of a property of a package. */
581
static ssize_t
582
ofw_real_getprop(ofw_t ofw, phandle_t package, const char *propname, void *buf,
583
size_t buflen)
584
{
585
vm_offset_t argsptr;
586
struct {
587
cell_t name;
588
cell_t nargs;
589
cell_t nreturns;
590
cell_t package;
591
cell_t propname;
592
cell_t buf;
593
cell_t buflen;
594
int32_t size;
595
} args;
596
597
args.name = IN((cell_t)(uintptr_t)"getprop");
598
args.nargs = IN(4);
599
args.nreturns = IN(1);
600
601
ofw_real_start();
602
603
args.package = IN(package);
604
args.propname = IN(ofw_real_map(propname, strlen(propname) + 1));
605
args.buf = IN(ofw_real_map(buf, buflen));
606
args.buflen = IN(buflen);
607
argsptr = ofw_real_map(&args, sizeof(args));
608
if (args.propname == 0 || args.buf == 0 ||
609
openfirmware((void *)argsptr) == -1) {
610
ofw_real_stop();
611
return (-1);
612
}
613
ofw_real_unmap(argsptr, &args, sizeof(args));
614
ofw_real_unmap(OUT(args.buf), buf, buflen);
615
616
ofw_real_stop();
617
return ((ssize_t)(int32_t)OUT(args.size));
618
}
619
620
/* Get the next property of a package. */
621
static int
622
ofw_real_nextprop(ofw_t ofw, phandle_t package, const char *previous,
623
char *buf, size_t size)
624
{
625
vm_offset_t argsptr;
626
struct {
627
cell_t name;
628
cell_t nargs;
629
cell_t nreturns;
630
cell_t package;
631
cell_t previous;
632
cell_t buf;
633
cell_t flag;
634
} args;
635
636
args.name = IN((cell_t)(uintptr_t)"nextprop");
637
args.nargs = IN(3);
638
args.nreturns = IN(1);
639
640
ofw_real_start();
641
642
args.package = IN(package);
643
args.previous = IN(ofw_real_map(previous, (previous != NULL) ? (strlen(previous) + 1) : 0));
644
args.buf = IN(ofw_real_map(buf, size));
645
argsptr = ofw_real_map(&args, sizeof(args));
646
if (args.buf == 0 || openfirmware((void *)argsptr) == -1) {
647
ofw_real_stop();
648
return (-1);
649
}
650
ofw_real_unmap(argsptr, &args, sizeof(args));
651
ofw_real_unmap(OUT(args.buf), buf, size);
652
653
ofw_real_stop();
654
return (OUT(args.flag));
655
}
656
657
/* Set the value of a property of a package. */
658
/* XXX Has a bug on FirePower */
659
static int
660
ofw_real_setprop(ofw_t ofw, phandle_t package, const char *propname,
661
const void *buf, size_t len)
662
{
663
vm_offset_t argsptr;
664
struct {
665
cell_t name;
666
cell_t nargs;
667
cell_t nreturns;
668
cell_t package;
669
cell_t propname;
670
cell_t buf;
671
cell_t len;
672
cell_t size;
673
} args;
674
675
args.name = IN((cell_t)(uintptr_t)"setprop");
676
args.nargs = IN(4);
677
args.nreturns = IN(1);
678
679
ofw_real_start();
680
681
args.package = IN(package);
682
args.propname = IN(ofw_real_map(propname, strlen(propname) + 1));
683
args.buf = IN(ofw_real_map(buf, len));
684
args.len = IN(len);
685
argsptr = ofw_real_map(&args, sizeof(args));
686
if (args.propname == 0 || args.buf == 0 ||
687
openfirmware((void *)argsptr) == -1) {
688
ofw_real_stop();
689
return (-1);
690
}
691
ofw_real_unmap(argsptr, &args, sizeof(args));
692
ofw_real_stop();
693
return (OUT(args.size));
694
}
695
696
/* Convert a device specifier to a fully qualified pathname. */
697
static ssize_t
698
ofw_real_canon(ofw_t ofw, const char *device, char *buf, size_t len)
699
{
700
vm_offset_t argsptr;
701
struct {
702
cell_t name;
703
cell_t nargs;
704
cell_t nreturns;
705
cell_t device;
706
cell_t buf;
707
cell_t len;
708
int32_t size;
709
} args;
710
711
args.name = IN((cell_t)(uintptr_t)"canon");
712
args.nargs = IN(3);
713
args.nreturns = IN(1);
714
715
ofw_real_start();
716
717
args.device = IN(ofw_real_map(device, strlen(device) + 1));
718
args.buf = IN(ofw_real_map(buf, len));
719
args.len = IN(len);
720
argsptr = ofw_real_map(&args, sizeof(args));
721
if (args.device == 0 || args.buf == 0 ||
722
openfirmware((void *)argsptr) == -1) {
723
ofw_real_stop();
724
return (-1);
725
}
726
ofw_real_unmap(argsptr, &args, sizeof(args));
727
ofw_real_unmap(OUT(args.buf), buf, len);
728
729
ofw_real_stop();
730
return ((ssize_t)(int32_t)OUT(args.size));
731
}
732
733
/* Return a package handle for the specified device. */
734
static phandle_t
735
ofw_real_finddevice(ofw_t ofw, const char *device)
736
{
737
vm_offset_t argsptr;
738
struct {
739
cell_t name;
740
cell_t nargs;
741
cell_t nreturns;
742
cell_t device;
743
cell_t package;
744
} args;
745
746
args.name = IN((cell_t)(uintptr_t)"finddevice");
747
args.nargs = IN(1);
748
args.nreturns = IN(1);
749
750
ofw_real_start();
751
752
args.device = IN(ofw_real_map(device, strlen(device) + 1));
753
argsptr = ofw_real_map(&args, sizeof(args));
754
if (args.device == 0 ||
755
openfirmware((void *)argsptr) == -1) {
756
ofw_real_stop();
757
return (-1);
758
}
759
ofw_real_unmap(argsptr, &args, sizeof(args));
760
ofw_real_stop();
761
return (OUT(args.package));
762
}
763
764
/* Return the fully qualified pathname corresponding to an instance. */
765
static ssize_t
766
ofw_real_instance_to_path(ofw_t ofw, ihandle_t instance, char *buf, size_t len)
767
{
768
vm_offset_t argsptr;
769
struct {
770
cell_t name;
771
cell_t nargs;
772
cell_t nreturns;
773
cell_t instance;
774
cell_t buf;
775
cell_t len;
776
int32_t size;
777
} args;
778
779
args.name = IN((cell_t)(uintptr_t)"instance-to-path");
780
args.nargs = IN(3);
781
args.nreturns = IN(1);
782
783
ofw_real_start();
784
785
args.instance = IN(instance);
786
args.buf = IN(ofw_real_map(buf, len));
787
args.len = IN(len);
788
argsptr = ofw_real_map(&args, sizeof(args));
789
if (args.buf == 0 ||
790
openfirmware((void *)argsptr) == -1) {
791
ofw_real_stop();
792
return (-1);
793
}
794
ofw_real_unmap(argsptr, &args, sizeof(args));
795
ofw_real_unmap(OUT(args.buf), buf, len);
796
797
ofw_real_stop();
798
return ((ssize_t)(int32_t)OUT(args.size));
799
}
800
801
/* Return the fully qualified pathname corresponding to a package. */
802
static ssize_t
803
ofw_real_package_to_path(ofw_t ofw, phandle_t package, char *buf, size_t len)
804
{
805
vm_offset_t argsptr;
806
struct {
807
cell_t name;
808
cell_t nargs;
809
cell_t nreturns;
810
cell_t package;
811
cell_t buf;
812
cell_t len;
813
int32_t size;
814
} args;
815
816
args.name = IN((cell_t)(uintptr_t)"package-to-path");
817
args.nargs = IN(3);
818
args.nreturns = IN(1);
819
820
ofw_real_start();
821
822
args.package = IN(package);
823
args.buf = IN(ofw_real_map(buf, len));
824
args.len = IN(len);
825
argsptr = ofw_real_map(&args, sizeof(args));
826
if (args.buf == 0 ||
827
openfirmware((void *)argsptr) == -1) {
828
ofw_real_stop();
829
return (-1);
830
}
831
ofw_real_unmap(argsptr, &args, sizeof(args));
832
ofw_real_unmap(OUT(args.buf), buf, len);
833
834
ofw_real_stop();
835
return ((ssize_t)(int32_t)OUT(args.size));
836
}
837
838
/* Call the method in the scope of a given instance. */
839
static int
840
ofw_real_call_method(ofw_t ofw, ihandle_t instance, const char *method,
841
int nargs, int nreturns, cell_t *args_and_returns)
842
{
843
vm_offset_t argsptr;
844
struct {
845
cell_t name;
846
cell_t nargs;
847
cell_t nreturns;
848
cell_t method;
849
cell_t instance;
850
cell_t args_n_results[12];
851
} args;
852
cell_t *ap, *cp;
853
int n;
854
855
args.name = IN((cell_t)(uintptr_t)"call-method");
856
args.nargs = IN(2);
857
args.nreturns = IN(1);
858
859
if (nargs > 6)
860
return (-1);
861
862
ofw_real_start();
863
args.nargs = IN(nargs + 2);
864
args.nreturns = IN(nreturns + 1);
865
args.method = IN(ofw_real_map(method, strlen(method) + 1));
866
args.instance = IN(instance);
867
868
ap = args_and_returns;
869
for (cp = args.args_n_results + (n = nargs); --n >= 0;)
870
*--cp = IN(*(ap++));
871
argsptr = ofw_real_map(&args, sizeof(args));
872
if (args.method == 0 ||
873
openfirmware((void *)argsptr) == -1) {
874
ofw_real_stop();
875
return (-1);
876
}
877
ofw_real_unmap(argsptr, &args, sizeof(args));
878
ofw_real_stop();
879
if (OUT(args.args_n_results[nargs]))
880
return (OUT(args.args_n_results[nargs]));
881
for (cp = args.args_n_results + nargs + (n = OUT(args.nreturns)); --n > 0;)
882
*(ap++) = OUT(*--cp);
883
return (0);
884
}
885
886
static int
887
ofw_real_interpret(ofw_t ofw, const char *cmd, int nreturns, cell_t *returns)
888
{
889
vm_offset_t argsptr;
890
struct {
891
cell_t name;
892
cell_t nargs;
893
cell_t nreturns;
894
cell_t slot[16];
895
} args;
896
cell_t status;
897
int i = 0, j = 0;
898
899
args.name = IN((cell_t)(uintptr_t)"interpret");
900
args.nargs = IN(1);
901
902
ofw_real_start();
903
args.nreturns = IN(++nreturns);
904
args.slot[i++] = IN(ofw_real_map(cmd, strlen(cmd) + 1));
905
argsptr = ofw_real_map(&args, sizeof(args));
906
if (openfirmware((void *)argsptr) == -1) {
907
ofw_real_stop();
908
return (-1);
909
}
910
ofw_real_unmap(argsptr, &args, sizeof(args));
911
ofw_real_stop();
912
status = OUT(args.slot[i++]);
913
while (i < 1 + nreturns)
914
returns[j++] = OUT(args.slot[i++]);
915
return (status);
916
}
917
918
/*
919
* Device I/O functions
920
*/
921
922
/* Open an instance for a device. */
923
static ihandle_t
924
ofw_real_open(ofw_t ofw, const char *device)
925
{
926
vm_offset_t argsptr;
927
struct {
928
cell_t name;
929
cell_t nargs;
930
cell_t nreturns;
931
cell_t device;
932
cell_t instance;
933
} args;
934
935
args.name = IN((cell_t)(uintptr_t)"open");
936
args.nargs = IN(1);
937
args.nreturns = IN(1);
938
939
ofw_real_start();
940
941
args.device = IN(ofw_real_map(device, strlen(device) + 1));
942
argsptr = ofw_real_map(&args, sizeof(args));
943
if (args.device == 0 || openfirmware((void *)argsptr) == -1
944
|| args.instance == 0) {
945
ofw_real_stop();
946
return (-1);
947
}
948
ofw_real_unmap(argsptr, &args, sizeof(args));
949
ofw_real_stop();
950
return (OUT(args.instance));
951
}
952
953
/* Close an instance. */
954
static void
955
ofw_real_close(ofw_t ofw, ihandle_t instance)
956
{
957
vm_offset_t argsptr;
958
struct {
959
cell_t name;
960
cell_t nargs;
961
cell_t nreturns;
962
cell_t instance;
963
} args;
964
965
args.name = IN((cell_t)(uintptr_t)"close");
966
args.nargs = IN(1);
967
args.nreturns = IN(0);
968
args.instance = IN(instance);
969
ofw_real_start();
970
argsptr = ofw_real_map(&args, sizeof(args));
971
openfirmware((void *)argsptr);
972
ofw_real_stop();
973
}
974
975
/* Read from an instance. */
976
static ssize_t
977
ofw_real_read(ofw_t ofw, ihandle_t instance, void *addr, size_t len)
978
{
979
vm_offset_t argsptr;
980
struct {
981
cell_t name;
982
cell_t nargs;
983
cell_t nreturns;
984
cell_t instance;
985
cell_t addr;
986
cell_t len;
987
int32_t actual;
988
} args;
989
990
args.name = IN((cell_t)(uintptr_t)"read");
991
args.nargs = IN(3);
992
args.nreturns = IN(1);
993
994
ofw_real_start();
995
996
args.instance = IN(instance);
997
args.addr = IN(ofw_real_map(addr, len));
998
args.len = IN(len);
999
argsptr = ofw_real_map(&args, sizeof(args));
1000
if (args.addr == 0 || openfirmware((void *)argsptr) == -1) {
1001
ofw_real_stop();
1002
return (-1);
1003
}
1004
ofw_real_unmap(argsptr, &args, sizeof(args));
1005
ofw_real_unmap(OUT(args.addr), addr, len);
1006
1007
ofw_real_stop();
1008
return ((ssize_t)(int32_t)OUT(args.actual));
1009
}
1010
1011
/* Write to an instance. */
1012
static ssize_t
1013
ofw_real_write(ofw_t ofw, ihandle_t instance, const void *addr, size_t len)
1014
{
1015
vm_offset_t argsptr;
1016
struct {
1017
cell_t name;
1018
cell_t nargs;
1019
cell_t nreturns;
1020
cell_t instance;
1021
cell_t addr;
1022
cell_t len;
1023
int32_t actual;
1024
} args;
1025
1026
args.name = IN((cell_t)(uintptr_t)"write");
1027
args.nargs = IN(3);
1028
args.nreturns = IN(1);
1029
1030
ofw_real_start();
1031
1032
args.instance = IN(instance);
1033
args.addr = IN(ofw_real_map(addr, len));
1034
args.len = IN(len);
1035
argsptr = ofw_real_map(&args, sizeof(args));
1036
if (args.addr == 0 || openfirmware((void *)argsptr) == -1) {
1037
ofw_real_stop();
1038
return (-1);
1039
}
1040
ofw_real_unmap(argsptr, &args, sizeof(args));
1041
ofw_real_stop();
1042
return ((ssize_t)(int32_t)OUT(args.actual));
1043
}
1044
1045
/* Seek to a position. */
1046
static int
1047
ofw_real_seek(ofw_t ofw, ihandle_t instance, u_int64_t pos)
1048
{
1049
vm_offset_t argsptr;
1050
struct {
1051
cell_t name;
1052
cell_t nargs;
1053
cell_t nreturns;
1054
cell_t instance;
1055
cell_t poshi;
1056
cell_t poslo;
1057
cell_t status;
1058
} args;
1059
1060
args.name = IN((cell_t)(uintptr_t)"seek");
1061
args.nargs = IN(3);
1062
args.nreturns = IN(1);
1063
1064
args.instance = IN(instance);
1065
args.poshi = IN(pos >> 32);
1066
args.poslo = IN(pos);
1067
ofw_real_start();
1068
argsptr = ofw_real_map(&args, sizeof(args));
1069
if (openfirmware((void *)argsptr) == -1) {
1070
ofw_real_stop();
1071
return (-1);
1072
}
1073
ofw_real_unmap(argsptr, &args, sizeof(args));
1074
ofw_real_stop();
1075
return (OUT(args.status));
1076
}
1077
1078
/*
1079
* Memory functions
1080
*/
1081
1082
/* Claim an area of memory. */
1083
static caddr_t
1084
ofw_real_claim(ofw_t ofw, void *virt, size_t size, u_int align)
1085
{
1086
vm_offset_t argsptr;
1087
struct {
1088
cell_t name;
1089
cell_t nargs;
1090
cell_t nreturns;
1091
cell_t virt;
1092
cell_t size;
1093
cell_t align;
1094
cell_t baseaddr;
1095
} args;
1096
1097
args.name = IN((cell_t)(uintptr_t)"claim");
1098
args.nargs = IN(3);
1099
args.nreturns = IN(1);
1100
1101
args.virt = IN((cell_t)(uintptr_t)virt);
1102
args.size = IN(size);
1103
args.align = IN(align);
1104
ofw_real_start();
1105
argsptr = ofw_real_map(&args, sizeof(args));
1106
if (openfirmware((void *)argsptr) == -1) {
1107
ofw_real_stop();
1108
return ((void *)-1);
1109
}
1110
ofw_real_unmap(argsptr, &args, sizeof(args));
1111
ofw_real_stop();
1112
return ((void *)(uintptr_t)(OUT(args.baseaddr)));
1113
}
1114
1115
/* Release an area of memory. */
1116
static void
1117
ofw_real_release(ofw_t ofw, void *virt, size_t size)
1118
{
1119
vm_offset_t argsptr;
1120
struct {
1121
cell_t name;
1122
cell_t nargs;
1123
cell_t nreturns;
1124
cell_t virt;
1125
cell_t size;
1126
} args;
1127
1128
args.name = IN((cell_t)(uintptr_t)"release");
1129
args.nargs = IN(2);
1130
args.nreturns = IN(0);
1131
1132
args.virt = IN((cell_t)(uintptr_t)virt);
1133
args.size = IN(size);
1134
ofw_real_start();
1135
argsptr = ofw_real_map(&args, sizeof(args));
1136
openfirmware((void *)argsptr);
1137
ofw_real_stop();
1138
}
1139
1140
/*
1141
* Control transfer functions
1142
*/
1143
1144
/* Suspend and drop back to the Open Firmware interface. */
1145
static void
1146
ofw_real_enter(ofw_t ofw)
1147
{
1148
vm_offset_t argsptr;
1149
struct {
1150
cell_t name;
1151
cell_t nargs;
1152
cell_t nreturns;
1153
} args;
1154
1155
args.name = IN((cell_t)(uintptr_t)"enter");
1156
args.nargs = IN(0);
1157
args.nreturns = IN(0);
1158
1159
ofw_real_start();
1160
argsptr = ofw_real_map(&args, sizeof(args));
1161
openfirmware((void *)argsptr);
1162
/* We may come back. */
1163
ofw_real_stop();
1164
}
1165
1166
/* Shut down and drop back to the Open Firmware interface. */
1167
static void
1168
ofw_real_exit(ofw_t ofw)
1169
{
1170
vm_offset_t argsptr;
1171
struct {
1172
cell_t name;
1173
cell_t nargs;
1174
cell_t nreturns;
1175
} args;
1176
1177
args.name = IN((cell_t)(uintptr_t)"exit");
1178
args.nargs = IN(0);
1179
args.nreturns = IN(0);
1180
1181
ofw_real_start();
1182
argsptr = ofw_real_map(&args, sizeof(args));
1183
openfirmware((void *)argsptr);
1184
for (;;) /* just in case */
1185
;
1186
ofw_real_stop();
1187
}
1188
1189