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/11.0/sys/powerpc/ofw/rtas.c 295880 2016-02-22 09:02:20Z skra $"); 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/rtas.h> 45222613Snwhitehorn#include <machine/stdarg.h> 46222613Snwhitehorn 47222613Snwhitehorn#include <dev/ofw/openfirm.h> 48222613Snwhitehorn 49227293Sedstatic MALLOC_DEFINE(M_RTAS, "rtas", "Run Time Abstraction Service"); 50222613Snwhitehorn 51222613Snwhitehornstatic vm_offset_t rtas_bounce_phys; 52222613Snwhitehornstatic caddr_t rtas_bounce_virt; 53222613Snwhitehornstatic off_t rtas_bounce_offset; 54222613Snwhitehornstatic size_t rtas_bounce_size; 55222613Snwhitehornstatic uintptr_t rtas_private_data; 56222613Snwhitehornstatic struct mtx rtas_mtx; 57222613Snwhitehornstatic phandle_t rtas; 58222613Snwhitehorn 59222613Snwhitehorn/* From ofwcall.S */ 60222613Snwhitehornint rtascall(vm_offset_t callbuffer, uintptr_t rtas_privdat); 61222613Snwhitehornextern uintptr_t rtas_entry; 62222613Snwhitehornextern register_t rtasmsr; 63222613Snwhitehorn 64222613Snwhitehorn/* 65222613Snwhitehorn * After the VM is up, allocate RTAS memory and instantiate it 66222613Snwhitehorn */ 67222613Snwhitehorn 68222613Snwhitehornstatic void rtas_setup(void *); 69222613Snwhitehorn 70222613SnwhitehornSYSINIT(rtas_setup, SI_SUB_KMEM, SI_ORDER_ANY, rtas_setup, NULL); 71222613Snwhitehorn 72222613Snwhitehornstatic void 73222613Snwhitehornrtas_setup(void *junk) 74222613Snwhitehorn{ 75222613Snwhitehorn ihandle_t rtasi; 76222613Snwhitehorn cell_t rtas_size = 0, rtas_ptr; 77222613Snwhitehorn char path[31]; 78222613Snwhitehorn int result; 79222613Snwhitehorn 80222613Snwhitehorn rtas = OF_finddevice("/rtas"); 81222613Snwhitehorn if (rtas == -1) { 82222613Snwhitehorn rtas = 0; 83222613Snwhitehorn return; 84222613Snwhitehorn } 85222613Snwhitehorn OF_package_to_path(rtas, path, sizeof(path)); 86222613Snwhitehorn 87255416Snwhitehorn mtx_init(&rtas_mtx, "RTAS", NULL, MTX_SPIN); 88222613Snwhitehorn 89222613Snwhitehorn /* RTAS must be called with everything turned off in MSR */ 90222613Snwhitehorn rtasmsr = mfmsr(); 91222613Snwhitehorn rtasmsr &= ~(PSL_IR | PSL_DR | PSL_EE | PSL_SE); 92222613Snwhitehorn #ifdef __powerpc64__ 93222613Snwhitehorn rtasmsr &= ~PSL_SF; 94222613Snwhitehorn #endif 95222613Snwhitehorn 96222613Snwhitehorn /* 97222613Snwhitehorn * Allocate rtas_size + one page of contiguous, wired physical memory 98222613Snwhitehorn * that can fit into a 32-bit address space and accessed from real mode. 99222613Snwhitehorn * This is used both to bounce arguments and for RTAS private data. 100222613Snwhitehorn * 101222613Snwhitehorn * It must be 4KB-aligned and not cross a 256 MB boundary. 102222613Snwhitehorn */ 103222613Snwhitehorn 104277539Snwhitehorn OF_getencprop(rtas, "rtas-size", &rtas_size, sizeof(rtas_size)); 105222613Snwhitehorn rtas_size = round_page(rtas_size); 106222613Snwhitehorn rtas_bounce_virt = contigmalloc(rtas_size + PAGE_SIZE, M_RTAS, 0, 0, 107222613Snwhitehorn ulmin(platform_real_maxaddr(), BUS_SPACE_MAXADDR_32BIT), 108222613Snwhitehorn 4096, 256*1024*1024); 109222613Snwhitehorn 110222613Snwhitehorn rtas_private_data = vtophys(rtas_bounce_virt); 111222613Snwhitehorn rtas_bounce_virt += rtas_size; /* Actual bounce area */ 112222613Snwhitehorn rtas_bounce_phys = vtophys(rtas_bounce_virt); 113222613Snwhitehorn rtas_bounce_size = PAGE_SIZE; 114222613Snwhitehorn 115222613Snwhitehorn /* 116222613Snwhitehorn * Instantiate RTAS. We always use the 32-bit version. 117222613Snwhitehorn */ 118222613Snwhitehorn 119277539Snwhitehorn if (OF_hasprop(rtas, "linux,rtas-entry") && 120277539Snwhitehorn OF_hasprop(rtas, "linux,rtas-base")) { 121277539Snwhitehorn OF_getencprop(rtas, "linux,rtas-base", &rtas_ptr, 122277539Snwhitehorn sizeof(rtas_ptr)); 123277539Snwhitehorn rtas_private_data = rtas_ptr; 124277539Snwhitehorn OF_getencprop(rtas, "linux,rtas-entry", &rtas_ptr, 125277539Snwhitehorn sizeof(rtas_ptr)); 126277539Snwhitehorn } else { 127277539Snwhitehorn rtasi = OF_open(path); 128277539Snwhitehorn if (rtasi == 0) { 129277539Snwhitehorn rtas = 0; 130277539Snwhitehorn printf("Error initializing RTAS: could not open " 131277539Snwhitehorn "node\n"); 132277539Snwhitehorn return; 133277539Snwhitehorn } 134222613Snwhitehorn 135277539Snwhitehorn result = OF_call_method("instantiate-rtas", rtasi, 1, 1, 136277539Snwhitehorn (cell_t)rtas_private_data, &rtas_ptr); 137277539Snwhitehorn OF_close(rtasi); 138277539Snwhitehorn 139277539Snwhitehorn if (result != 0) { 140277539Snwhitehorn rtas = 0; 141277539Snwhitehorn rtas_ptr = 0; 142277539Snwhitehorn printf("Error initializing RTAS (%d)\n", result); 143277539Snwhitehorn return; 144277539Snwhitehorn } 145222613Snwhitehorn } 146222613Snwhitehorn 147222613Snwhitehorn rtas_entry = (uintptr_t)(rtas_ptr); 148222613Snwhitehorn} 149222613Snwhitehorn 150222613Snwhitehornstatic cell_t 151222613Snwhitehornrtas_real_map(const void *buf, size_t len) 152222613Snwhitehorn{ 153222613Snwhitehorn cell_t phys; 154222613Snwhitehorn 155222613Snwhitehorn mtx_assert(&rtas_mtx, MA_OWNED); 156222613Snwhitehorn 157222613Snwhitehorn /* 158222613Snwhitehorn * Make sure the bounce page offset satisfies any reasonable 159222613Snwhitehorn * alignment constraint. 160222613Snwhitehorn */ 161222613Snwhitehorn rtas_bounce_offset += sizeof(register_t) - 162222613Snwhitehorn (rtas_bounce_offset % sizeof(register_t)); 163222613Snwhitehorn 164222613Snwhitehorn if (rtas_bounce_offset + len > rtas_bounce_size) { 165222613Snwhitehorn panic("Oversize RTAS call!"); 166222613Snwhitehorn return 0; 167222613Snwhitehorn } 168222613Snwhitehorn 169222613Snwhitehorn if (buf != NULL) 170222613Snwhitehorn memcpy(rtas_bounce_virt + rtas_bounce_offset, buf, len); 171222613Snwhitehorn else 172222613Snwhitehorn return (0); 173222613Snwhitehorn 174222613Snwhitehorn phys = rtas_bounce_phys + rtas_bounce_offset; 175222613Snwhitehorn rtas_bounce_offset += len; 176222613Snwhitehorn 177222613Snwhitehorn return (phys); 178222613Snwhitehorn} 179222613Snwhitehorn 180222613Snwhitehornstatic void 181222613Snwhitehornrtas_real_unmap(cell_t physaddr, void *buf, size_t len) 182222613Snwhitehorn{ 183222613Snwhitehorn mtx_assert(&rtas_mtx, MA_OWNED); 184222613Snwhitehorn 185222613Snwhitehorn if (physaddr == 0) 186222613Snwhitehorn return; 187222613Snwhitehorn 188222613Snwhitehorn memcpy(buf, rtas_bounce_virt + (physaddr - rtas_bounce_phys), len); 189222613Snwhitehorn} 190222613Snwhitehorn 191222613Snwhitehorn/* Check if we have RTAS */ 192222613Snwhitehornint 193222613Snwhitehornrtas_exists(void) 194222613Snwhitehorn{ 195222613Snwhitehorn return (rtas != 0); 196222613Snwhitehorn} 197222613Snwhitehorn 198222613Snwhitehorn/* Call an RTAS method by token */ 199222613Snwhitehornint 200222613Snwhitehornrtas_call_method(cell_t token, int nargs, int nreturns, ...) 201222613Snwhitehorn{ 202222613Snwhitehorn vm_offset_t argsptr; 203293636Snwhitehorn jmp_buf env, *oldfaultbuf; 204222613Snwhitehorn va_list ap; 205222613Snwhitehorn struct { 206222613Snwhitehorn cell_t token; 207222613Snwhitehorn cell_t nargs; 208222613Snwhitehorn cell_t nreturns; 209222613Snwhitehorn cell_t args_n_results[12]; 210222613Snwhitehorn } args; 211222613Snwhitehorn int n, result; 212222613Snwhitehorn 213222613Snwhitehorn if (!rtas_exists() || nargs + nreturns > 12) 214222613Snwhitehorn return (-1); 215222613Snwhitehorn 216222613Snwhitehorn args.token = token; 217222613Snwhitehorn va_start(ap, nreturns); 218222613Snwhitehorn 219255416Snwhitehorn mtx_lock_spin(&rtas_mtx); 220222613Snwhitehorn rtas_bounce_offset = 0; 221222613Snwhitehorn 222222613Snwhitehorn args.nargs = nargs; 223222613Snwhitehorn args.nreturns = nreturns; 224222613Snwhitehorn 225222613Snwhitehorn for (n = 0; n < nargs; n++) 226222613Snwhitehorn args.args_n_results[n] = va_arg(ap, cell_t); 227222613Snwhitehorn 228222613Snwhitehorn argsptr = rtas_real_map(&args, sizeof(args)); 229223571Snwhitehorn 230223571Snwhitehorn /* Get rid of any stale machine checks that have been waiting. */ 231223571Snwhitehorn __asm __volatile ("sync; isync"); 232258694Snwhitehorn oldfaultbuf = curthread->td_pcb->pcb_onfault; 233293636Snwhitehorn curthread->td_pcb->pcb_onfault = &env; 234293636Snwhitehorn if (!setjmp(env)) { 235223571Snwhitehorn __asm __volatile ("sync"); 236223571Snwhitehorn result = rtascall(argsptr, rtas_private_data); 237223571Snwhitehorn __asm __volatile ("sync; isync"); 238223571Snwhitehorn } else { 239223571Snwhitehorn result = RTAS_HW_ERROR; 240223571Snwhitehorn } 241258694Snwhitehorn curthread->td_pcb->pcb_onfault = oldfaultbuf; 242223571Snwhitehorn __asm __volatile ("sync"); 243223571Snwhitehorn 244222613Snwhitehorn rtas_real_unmap(argsptr, &args, sizeof(args)); 245255416Snwhitehorn mtx_unlock_spin(&rtas_mtx); 246222613Snwhitehorn 247222613Snwhitehorn if (result < 0) 248222613Snwhitehorn return (result); 249222613Snwhitehorn 250222613Snwhitehorn for (n = nargs; n < nargs + nreturns; n++) 251222613Snwhitehorn *va_arg(ap, cell_t *) = args.args_n_results[n]; 252222613Snwhitehorn return (result); 253222613Snwhitehorn} 254222613Snwhitehorn 255222613Snwhitehorn/* Look up an RTAS token */ 256222613Snwhitehorncell_t 257222613Snwhitehornrtas_token_lookup(const char *method) 258222613Snwhitehorn{ 259222613Snwhitehorn cell_t token; 260222613Snwhitehorn 261222613Snwhitehorn if (!rtas_exists()) 262222613Snwhitehorn return (-1); 263222613Snwhitehorn 264277539Snwhitehorn if (OF_getencprop(rtas, method, &token, sizeof(token)) == -1) 265222613Snwhitehorn return (-1); 266222613Snwhitehorn 267222613Snwhitehorn return (token); 268222613Snwhitehorn} 269222613Snwhitehorn 270222613Snwhitehorn 271