1222613Snwhitehorn/*- 2222613Snwhitehorn * Copyright (c) 2011 Nathan Whitehorn 3222613Snwhitehorn * All rights reserved. 4222613Snwhitehorn * 5222613Snwhitehorn * Redistribution and use in source and binary forms, with or without 6222613Snwhitehorn * modification, are permitted provided that the following conditions 7222613Snwhitehorn * are met: 8222613Snwhitehorn * 1. Redistributions of source code must retain the above copyright 9222613Snwhitehorn * notice, this list of conditions and the following disclaimer. 10222613Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright 11222613Snwhitehorn * notice, this list of conditions and the following disclaimer in the 12222613Snwhitehorn * documentation and/or other materials provided with the distribution. 13222613Snwhitehorn * 14222613Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15222613Snwhitehorn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16222613Snwhitehorn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17222613Snwhitehorn * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18222613Snwhitehorn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19222613Snwhitehorn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20222613Snwhitehorn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21222613Snwhitehorn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22222613Snwhitehorn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23222613Snwhitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24222613Snwhitehorn * SUCH DAMAGE. 25222613Snwhitehorn */ 26222613Snwhitehorn 27222613Snwhitehorn#include <sys/cdefs.h> 28222613Snwhitehorn__FBSDID("$FreeBSD: releng/10.3/sys/powerpc/ofw/rtas.c 259258 2013-12-12 13:00:07Z andreast $"); 29222613Snwhitehorn 30222613Snwhitehorn#include <sys/param.h> 31222613Snwhitehorn#include <sys/kernel.h> 32222613Snwhitehorn#include <sys/lock.h> 33222613Snwhitehorn#include <sys/mutex.h> 34222613Snwhitehorn#include <sys/systm.h> 35223571Snwhitehorn#include <sys/proc.h> 36222613Snwhitehorn 37222613Snwhitehorn#include <vm/vm.h> 38222613Snwhitehorn#include <vm/vm_page.h> 39222613Snwhitehorn#include <vm/pmap.h> 40222613Snwhitehorn 41222613Snwhitehorn#include <machine/bus.h> 42222613Snwhitehorn#include <machine/md_var.h> 43223571Snwhitehorn#include <machine/pcb.h> 44222613Snwhitehorn#include <machine/pmap.h> 45222613Snwhitehorn#include <machine/rtas.h> 46222613Snwhitehorn#include <machine/stdarg.h> 47222613Snwhitehorn 48222613Snwhitehorn#include <dev/ofw/openfirm.h> 49222613Snwhitehorn 50227293Sedstatic MALLOC_DEFINE(M_RTAS, "rtas", "Run Time Abstraction Service"); 51222613Snwhitehorn 52222613Snwhitehornstatic vm_offset_t rtas_bounce_phys; 53222613Snwhitehornstatic caddr_t rtas_bounce_virt; 54222613Snwhitehornstatic off_t rtas_bounce_offset; 55222613Snwhitehornstatic size_t rtas_bounce_size; 56222613Snwhitehornstatic uintptr_t rtas_private_data; 57222613Snwhitehornstatic struct mtx rtas_mtx; 58222613Snwhitehornstatic phandle_t rtas; 59222613Snwhitehorn 60222613Snwhitehorn/* From ofwcall.S */ 61222613Snwhitehornint rtascall(vm_offset_t callbuffer, uintptr_t rtas_privdat); 62222613Snwhitehornextern uintptr_t rtas_entry; 63222613Snwhitehornextern register_t rtasmsr; 64222613Snwhitehorn 65223571Snwhitehornint setfault(faultbuf); /* defined in locore.S */ 66223571Snwhitehorn 67222613Snwhitehorn/* 68222613Snwhitehorn * After the VM is up, allocate RTAS memory and instantiate it 69222613Snwhitehorn */ 70222613Snwhitehorn 71222613Snwhitehornstatic void rtas_setup(void *); 72222613Snwhitehorn 73222613SnwhitehornSYSINIT(rtas_setup, SI_SUB_KMEM, SI_ORDER_ANY, rtas_setup, NULL); 74222613Snwhitehorn 75222613Snwhitehornstatic void 76222613Snwhitehornrtas_setup(void *junk) 77222613Snwhitehorn{ 78222613Snwhitehorn ihandle_t rtasi; 79222613Snwhitehorn cell_t rtas_size = 0, rtas_ptr; 80222613Snwhitehorn char path[31]; 81222613Snwhitehorn int result; 82222613Snwhitehorn 83222613Snwhitehorn rtas = OF_finddevice("/rtas"); 84222613Snwhitehorn if (rtas == -1) { 85222613Snwhitehorn rtas = 0; 86222613Snwhitehorn return; 87222613Snwhitehorn } 88222613Snwhitehorn OF_package_to_path(rtas, path, sizeof(path)); 89222613Snwhitehorn rtasi = OF_open(path); 90222613Snwhitehorn if (rtasi == 0) { 91222613Snwhitehorn rtas = 0; 92222613Snwhitehorn printf("Error initializing RTAS: could not open node\n"); 93222613Snwhitehorn return; 94222613Snwhitehorn } 95222613Snwhitehorn 96255416Snwhitehorn mtx_init(&rtas_mtx, "RTAS", NULL, MTX_SPIN); 97222613Snwhitehorn 98222613Snwhitehorn /* RTAS must be called with everything turned off in MSR */ 99222613Snwhitehorn rtasmsr = mfmsr(); 100222613Snwhitehorn rtasmsr &= ~(PSL_IR | PSL_DR | PSL_EE | PSL_SE); 101222613Snwhitehorn #ifdef __powerpc64__ 102222613Snwhitehorn rtasmsr &= ~PSL_SF; 103222613Snwhitehorn #endif 104222613Snwhitehorn 105222613Snwhitehorn /* 106222613Snwhitehorn * Allocate rtas_size + one page of contiguous, wired physical memory 107222613Snwhitehorn * that can fit into a 32-bit address space and accessed from real mode. 108222613Snwhitehorn * This is used both to bounce arguments and for RTAS private data. 109222613Snwhitehorn * 110222613Snwhitehorn * It must be 4KB-aligned and not cross a 256 MB boundary. 111222613Snwhitehorn */ 112222613Snwhitehorn 113222613Snwhitehorn OF_getprop(rtas, "rtas-size", &rtas_size, sizeof(rtas_size)); 114222613Snwhitehorn rtas_size = round_page(rtas_size); 115222613Snwhitehorn rtas_bounce_virt = contigmalloc(rtas_size + PAGE_SIZE, M_RTAS, 0, 0, 116222613Snwhitehorn ulmin(platform_real_maxaddr(), BUS_SPACE_MAXADDR_32BIT), 117222613Snwhitehorn 4096, 256*1024*1024); 118222613Snwhitehorn 119222613Snwhitehorn rtas_private_data = vtophys(rtas_bounce_virt); 120222613Snwhitehorn rtas_bounce_virt += rtas_size; /* Actual bounce area */ 121222613Snwhitehorn rtas_bounce_phys = vtophys(rtas_bounce_virt); 122222613Snwhitehorn rtas_bounce_size = PAGE_SIZE; 123222613Snwhitehorn 124222613Snwhitehorn /* 125222613Snwhitehorn * Instantiate RTAS. We always use the 32-bit version. 126222613Snwhitehorn */ 127222613Snwhitehorn 128222613Snwhitehorn result = OF_call_method("instantiate-rtas", rtasi, 1, 1, 129222613Snwhitehorn (cell_t)rtas_private_data, &rtas_ptr); 130222613Snwhitehorn OF_close(rtasi); 131222613Snwhitehorn 132222613Snwhitehorn if (result != 0) { 133222613Snwhitehorn rtas = 0; 134222613Snwhitehorn rtas_ptr = 0; 135222613Snwhitehorn printf("Error initializing RTAS (%d)\n", result); 136222613Snwhitehorn return; 137222613Snwhitehorn } 138222613Snwhitehorn 139222613Snwhitehorn rtas_entry = (uintptr_t)(rtas_ptr); 140222613Snwhitehorn} 141222613Snwhitehorn 142222613Snwhitehornstatic cell_t 143222613Snwhitehornrtas_real_map(const void *buf, size_t len) 144222613Snwhitehorn{ 145222613Snwhitehorn cell_t phys; 146222613Snwhitehorn 147222613Snwhitehorn mtx_assert(&rtas_mtx, MA_OWNED); 148222613Snwhitehorn 149222613Snwhitehorn /* 150222613Snwhitehorn * Make sure the bounce page offset satisfies any reasonable 151222613Snwhitehorn * alignment constraint. 152222613Snwhitehorn */ 153222613Snwhitehorn rtas_bounce_offset += sizeof(register_t) - 154222613Snwhitehorn (rtas_bounce_offset % sizeof(register_t)); 155222613Snwhitehorn 156222613Snwhitehorn if (rtas_bounce_offset + len > rtas_bounce_size) { 157222613Snwhitehorn panic("Oversize RTAS call!"); 158222613Snwhitehorn return 0; 159222613Snwhitehorn } 160222613Snwhitehorn 161222613Snwhitehorn if (buf != NULL) 162222613Snwhitehorn memcpy(rtas_bounce_virt + rtas_bounce_offset, buf, len); 163222613Snwhitehorn else 164222613Snwhitehorn return (0); 165222613Snwhitehorn 166222613Snwhitehorn phys = rtas_bounce_phys + rtas_bounce_offset; 167222613Snwhitehorn rtas_bounce_offset += len; 168222613Snwhitehorn 169222613Snwhitehorn return (phys); 170222613Snwhitehorn} 171222613Snwhitehorn 172222613Snwhitehornstatic void 173222613Snwhitehornrtas_real_unmap(cell_t physaddr, void *buf, size_t len) 174222613Snwhitehorn{ 175222613Snwhitehorn mtx_assert(&rtas_mtx, MA_OWNED); 176222613Snwhitehorn 177222613Snwhitehorn if (physaddr == 0) 178222613Snwhitehorn return; 179222613Snwhitehorn 180222613Snwhitehorn memcpy(buf, rtas_bounce_virt + (physaddr - rtas_bounce_phys), len); 181222613Snwhitehorn} 182222613Snwhitehorn 183222613Snwhitehorn/* Check if we have RTAS */ 184222613Snwhitehornint 185222613Snwhitehornrtas_exists(void) 186222613Snwhitehorn{ 187222613Snwhitehorn return (rtas != 0); 188222613Snwhitehorn} 189222613Snwhitehorn 190222613Snwhitehorn/* Call an RTAS method by token */ 191222613Snwhitehornint 192222613Snwhitehornrtas_call_method(cell_t token, int nargs, int nreturns, ...) 193222613Snwhitehorn{ 194222613Snwhitehorn vm_offset_t argsptr; 195259258Sandreast faultbuf env, *oldfaultbuf; 196222613Snwhitehorn va_list ap; 197222613Snwhitehorn struct { 198222613Snwhitehorn cell_t token; 199222613Snwhitehorn cell_t nargs; 200222613Snwhitehorn cell_t nreturns; 201222613Snwhitehorn cell_t args_n_results[12]; 202222613Snwhitehorn } args; 203222613Snwhitehorn int n, result; 204222613Snwhitehorn 205222613Snwhitehorn if (!rtas_exists() || nargs + nreturns > 12) 206222613Snwhitehorn return (-1); 207222613Snwhitehorn 208222613Snwhitehorn args.token = token; 209222613Snwhitehorn va_start(ap, nreturns); 210222613Snwhitehorn 211255416Snwhitehorn mtx_lock_spin(&rtas_mtx); 212222613Snwhitehorn rtas_bounce_offset = 0; 213222613Snwhitehorn 214222613Snwhitehorn args.nargs = nargs; 215222613Snwhitehorn args.nreturns = nreturns; 216222613Snwhitehorn 217222613Snwhitehorn for (n = 0; n < nargs; n++) 218222613Snwhitehorn args.args_n_results[n] = va_arg(ap, cell_t); 219222613Snwhitehorn 220222613Snwhitehorn argsptr = rtas_real_map(&args, sizeof(args)); 221223571Snwhitehorn 222223571Snwhitehorn /* Get rid of any stale machine checks that have been waiting. */ 223223571Snwhitehorn __asm __volatile ("sync; isync"); 224259258Sandreast oldfaultbuf = curthread->td_pcb->pcb_onfault; 225223571Snwhitehorn if (!setfault(env)) { 226223571Snwhitehorn __asm __volatile ("sync"); 227223571Snwhitehorn result = rtascall(argsptr, rtas_private_data); 228223571Snwhitehorn __asm __volatile ("sync; isync"); 229223571Snwhitehorn } else { 230223571Snwhitehorn result = RTAS_HW_ERROR; 231223571Snwhitehorn } 232259258Sandreast curthread->td_pcb->pcb_onfault = oldfaultbuf; 233223571Snwhitehorn __asm __volatile ("sync"); 234223571Snwhitehorn 235222613Snwhitehorn rtas_real_unmap(argsptr, &args, sizeof(args)); 236255416Snwhitehorn mtx_unlock_spin(&rtas_mtx); 237222613Snwhitehorn 238222613Snwhitehorn if (result < 0) 239222613Snwhitehorn return (result); 240222613Snwhitehorn 241222613Snwhitehorn for (n = nargs; n < nargs + nreturns; n++) 242222613Snwhitehorn *va_arg(ap, cell_t *) = args.args_n_results[n]; 243222613Snwhitehorn return (result); 244222613Snwhitehorn} 245222613Snwhitehorn 246222613Snwhitehorn/* Look up an RTAS token */ 247222613Snwhitehorncell_t 248222613Snwhitehornrtas_token_lookup(const char *method) 249222613Snwhitehorn{ 250222613Snwhitehorn cell_t token; 251222613Snwhitehorn 252222613Snwhitehorn if (!rtas_exists()) 253222613Snwhitehorn return (-1); 254222613Snwhitehorn 255222613Snwhitehorn if (OF_getprop(rtas, method, &token, sizeof(token)) == -1) 256222613Snwhitehorn return (-1); 257222613Snwhitehorn 258222613Snwhitehorn return (token); 259222613Snwhitehorn} 260222613Snwhitehorn 261222613Snwhitehorn 262