The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/powerpc/ofw/ofw_real.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 34aa34baaddd6b6abd15fe7a88369679


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.