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/rtas.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 /*-
    2  * Copyright (c) 2011 Nathan Whitehorn
    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  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD: releng/11.1/sys/powerpc/ofw/rtas.c 295880 2016-02-22 09:02:20Z skra $");
   29 
   30 #include <sys/param.h>
   31 #include <sys/kernel.h>
   32 #include <sys/lock.h>
   33 #include <sys/mutex.h>
   34 #include <sys/systm.h>
   35 #include <sys/proc.h>
   36 
   37 #include <vm/vm.h>
   38 #include <vm/vm_page.h>
   39 #include <vm/pmap.h>
   40 
   41 #include <machine/bus.h>
   42 #include <machine/md_var.h>
   43 #include <machine/pcb.h>
   44 #include <machine/rtas.h>
   45 #include <machine/stdarg.h>
   46 
   47 #include <dev/ofw/openfirm.h>
   48 
   49 static MALLOC_DEFINE(M_RTAS, "rtas", "Run Time Abstraction Service");
   50 
   51 static vm_offset_t      rtas_bounce_phys;
   52 static caddr_t          rtas_bounce_virt;
   53 static off_t            rtas_bounce_offset;
   54 static size_t           rtas_bounce_size;
   55 static uintptr_t        rtas_private_data;
   56 static struct mtx       rtas_mtx;
   57 static phandle_t        rtas;
   58 
   59 /* From ofwcall.S */
   60 int rtascall(vm_offset_t callbuffer, uintptr_t rtas_privdat);
   61 extern uintptr_t        rtas_entry;
   62 extern register_t       rtasmsr;
   63 
   64 /*
   65  * After the VM is up, allocate RTAS memory and instantiate it
   66  */
   67 
   68 static void rtas_setup(void *);
   69 
   70 SYSINIT(rtas_setup, SI_SUB_KMEM, SI_ORDER_ANY, rtas_setup, NULL);
   71 
   72 static void
   73 rtas_setup(void *junk)
   74 {
   75         ihandle_t rtasi;
   76         cell_t rtas_size = 0, rtas_ptr;
   77         char path[31];
   78         int result;
   79 
   80         rtas = OF_finddevice("/rtas");
   81         if (rtas == -1) {
   82                 rtas = 0;
   83                 return;
   84         }
   85         OF_package_to_path(rtas, path, sizeof(path));
   86 
   87         mtx_init(&rtas_mtx, "RTAS", NULL, MTX_SPIN);
   88 
   89         /* RTAS must be called with everything turned off in MSR */
   90         rtasmsr = mfmsr();
   91         rtasmsr &= ~(PSL_IR | PSL_DR | PSL_EE | PSL_SE);
   92         #ifdef __powerpc64__
   93         rtasmsr &= ~PSL_SF;
   94         #endif
   95 
   96         /*
   97          * Allocate rtas_size + one page of contiguous, wired physical memory
   98          * that can fit into a 32-bit address space and accessed from real mode.
   99          * This is used both to bounce arguments and for RTAS private data.
  100          *
  101          * It must be 4KB-aligned and not cross a 256 MB boundary.
  102          */
  103 
  104         OF_getencprop(rtas, "rtas-size", &rtas_size, sizeof(rtas_size));
  105         rtas_size = round_page(rtas_size);
  106         rtas_bounce_virt = contigmalloc(rtas_size + PAGE_SIZE, M_RTAS, 0, 0,
  107             ulmin(platform_real_maxaddr(), BUS_SPACE_MAXADDR_32BIT),
  108             4096, 256*1024*1024);
  109 
  110         rtas_private_data = vtophys(rtas_bounce_virt);
  111         rtas_bounce_virt += rtas_size;  /* Actual bounce area */
  112         rtas_bounce_phys = vtophys(rtas_bounce_virt);
  113         rtas_bounce_size = PAGE_SIZE;
  114 
  115         /*
  116          * Instantiate RTAS. We always use the 32-bit version.
  117          */
  118 
  119         if (OF_hasprop(rtas, "linux,rtas-entry") &&
  120             OF_hasprop(rtas, "linux,rtas-base")) {
  121                 OF_getencprop(rtas, "linux,rtas-base", &rtas_ptr,
  122                     sizeof(rtas_ptr));
  123                 rtas_private_data = rtas_ptr;
  124                 OF_getencprop(rtas, "linux,rtas-entry", &rtas_ptr,
  125                     sizeof(rtas_ptr));
  126         } else {
  127                 rtasi = OF_open(path);
  128                 if (rtasi == 0) {
  129                         rtas = 0;
  130                         printf("Error initializing RTAS: could not open "
  131                             "node\n");
  132                         return;
  133                 }
  134 
  135                 result = OF_call_method("instantiate-rtas", rtasi, 1, 1,
  136                     (cell_t)rtas_private_data, &rtas_ptr);
  137                 OF_close(rtasi);
  138 
  139                 if (result != 0) {
  140                         rtas = 0;
  141                         rtas_ptr = 0;
  142                         printf("Error initializing RTAS (%d)\n", result);
  143                         return;
  144                 }
  145         }
  146 
  147         rtas_entry = (uintptr_t)(rtas_ptr);
  148 }
  149 
  150 static cell_t
  151 rtas_real_map(const void *buf, size_t len)
  152 {
  153         cell_t phys;
  154 
  155         mtx_assert(&rtas_mtx, MA_OWNED);
  156 
  157         /*
  158          * Make sure the bounce page offset satisfies any reasonable
  159          * alignment constraint.
  160          */
  161         rtas_bounce_offset += sizeof(register_t) -
  162             (rtas_bounce_offset % sizeof(register_t));
  163 
  164         if (rtas_bounce_offset + len > rtas_bounce_size) {
  165                 panic("Oversize RTAS call!");
  166                 return 0;
  167         }
  168 
  169         if (buf != NULL)
  170                 memcpy(rtas_bounce_virt + rtas_bounce_offset, buf, len);
  171         else
  172                 return (0);
  173 
  174         phys = rtas_bounce_phys + rtas_bounce_offset;
  175         rtas_bounce_offset += len;
  176 
  177         return (phys);
  178 }
  179 
  180 static void
  181 rtas_real_unmap(cell_t physaddr, void *buf, size_t len)
  182 {
  183         mtx_assert(&rtas_mtx, MA_OWNED);
  184 
  185         if (physaddr == 0)
  186                 return;
  187 
  188         memcpy(buf, rtas_bounce_virt + (physaddr - rtas_bounce_phys), len);
  189 }
  190 
  191 /* Check if we have RTAS */
  192 int
  193 rtas_exists(void)
  194 {
  195         return (rtas != 0);
  196 }
  197 
  198 /* Call an RTAS method by token */
  199 int
  200 rtas_call_method(cell_t token, int nargs, int nreturns, ...)
  201 {
  202         vm_offset_t argsptr;
  203         jmp_buf env, *oldfaultbuf;
  204         va_list ap;
  205         struct {
  206                 cell_t token;
  207                 cell_t nargs;
  208                 cell_t nreturns;
  209                 cell_t args_n_results[12];
  210         } args;
  211         int n, result;
  212 
  213         if (!rtas_exists() || nargs + nreturns > 12)
  214                 return (-1);
  215 
  216         args.token = token;
  217         va_start(ap, nreturns);
  218 
  219         mtx_lock_spin(&rtas_mtx);
  220         rtas_bounce_offset = 0;
  221 
  222         args.nargs = nargs;
  223         args.nreturns = nreturns;
  224 
  225         for (n = 0; n < nargs; n++)
  226                 args.args_n_results[n] = va_arg(ap, cell_t);
  227 
  228         argsptr = rtas_real_map(&args, sizeof(args));
  229 
  230         /* Get rid of any stale machine checks that have been waiting.  */
  231         __asm __volatile ("sync; isync");
  232         oldfaultbuf = curthread->td_pcb->pcb_onfault;
  233         curthread->td_pcb->pcb_onfault = &env;
  234         if (!setjmp(env)) {
  235                 __asm __volatile ("sync");
  236                 result = rtascall(argsptr, rtas_private_data);
  237                 __asm __volatile ("sync; isync");
  238         } else {
  239                 result = RTAS_HW_ERROR;
  240         }
  241         curthread->td_pcb->pcb_onfault = oldfaultbuf;
  242         __asm __volatile ("sync");
  243 
  244         rtas_real_unmap(argsptr, &args, sizeof(args));
  245         mtx_unlock_spin(&rtas_mtx);
  246 
  247         if (result < 0)
  248                 return (result);
  249 
  250         for (n = nargs; n < nargs + nreturns; n++)
  251                 *va_arg(ap, cell_t *) = args.args_n_results[n];
  252         return (result);
  253 }
  254 
  255 /* Look up an RTAS token */
  256 cell_t
  257 rtas_token_lookup(const char *method)
  258 {
  259         cell_t token;
  260         
  261         if (!rtas_exists())
  262                 return (-1);
  263 
  264         if (OF_getencprop(rtas, method, &token, sizeof(token)) == -1)
  265                 return (-1);
  266 
  267         return (token);
  268 }
  269 
  270 

Cache object: 1f54ae9619c8c81ecb1289627b5b364c


[ 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.