/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include /* * Returns 0 on error. Otherwise returns a handle. */ int prom_open(char *path) { cell_t ci[5]; promif_owrap_t *ow; #ifdef PROM_32BIT_ADDRS char *opath = NULL; size_t len; if ((uintptr_t)path > (uint32_t)-1) { opath = path; len = prom_strlen(opath) + 1; /* include terminating NUL */ path = promplat_alloc(len); if (path == NULL) return (0); (void) prom_strcpy(path, opath); } #endif ow = promif_preout(); promif_preprom(); ci[0] = p1275_ptr2cell("open"); /* Service name */ ci[1] = (cell_t)1; /* #argument cells */ ci[2] = (cell_t)1; /* #result cells */ ci[3] = p1275_ptr2cell(path); /* Arg1: Pathname */ ci[4] = (cell_t)0; /* Res1: Prime result */ (void) p1275_cif_handler(&ci); promif_postprom(); promif_postout(ow); #ifdef PROM_32BIT_ADDRS if (opath != NULL) promplat_free(path, len); #endif return (p1275_cell2int(ci[4])); /* Res1: ihandle */ } int prom_seek(int fd, unsigned long long offset) { cell_t ci[7]; ci[0] = p1275_ptr2cell("seek"); /* Service name */ ci[1] = (cell_t)3; /* #argument cells */ ci[2] = (cell_t)1; /* #result cells */ ci[3] = p1275_uint2cell((uint_t)fd); /* Arg1: ihandle */ ci[4] = p1275_ull2cell_high(offset); /* Arg2: pos.hi */ ci[5] = p1275_ull2cell_low(offset); /* Arg3: pos.lo */ ci[6] = (cell_t)-1; /* Res1: Prime result */ promif_preprom(); (void) p1275_cif_handler(&ci); promif_postprom(); return (p1275_cell2int(ci[6])); /* Res1: actual */ } /*ARGSUSED3*/ ssize_t prom_read(ihandle_t fd, caddr_t buf, size_t len, uint_t startblk, char devtype) { cell_t ci[7]; promif_owrap_t *ow; #ifdef PROM_32BIT_ADDRS caddr_t obuf = NULL; if ((uintptr_t)buf > (uint32_t)-1) { obuf = buf; buf = promplat_alloc(len); if (buf == NULL) return (-1); } #endif ow = promif_preout(); promif_preprom(); ci[0] = p1275_ptr2cell("read"); /* Service name */ ci[1] = (cell_t)3; /* #argument cells */ ci[2] = (cell_t)1; /* #result cells */ ci[3] = p1275_size2cell((uint_t)fd); /* Arg1: ihandle */ ci[4] = p1275_ptr2cell(buf); /* Arg2: buffer address */ ci[5] = p1275_uint2cell(len); /* Arg3: buffer length */ ci[6] = (cell_t)-1; /* Res1: Prime result */ (void) p1275_cif_handler(&ci); promif_postprom(); promif_postout(ow); #ifdef PROM_32BIT_ADDRS if (obuf != NULL) { promplat_bcopy(buf, obuf, len); promplat_free(buf, len); } #endif return (p1275_cell2size(ci[6])); /* Res1: actual length */ } /* * prom_write is the only prom_*() function we have to intercept * because all the other prom_*() io interfaces eventually call * into prom_write(). */ /*ARGSUSED3*/ ssize_t prom_write(ihandle_t fd, caddr_t buf, size_t len, uint_t startblk, char devtype) { cell_t ci[7]; promif_owrap_t *ow; ssize_t rlen; #ifdef PROM_32BIT_ADDRS caddr_t obuf = NULL; static char smallbuf[256]; ASSERT(buf); #endif /* * If the callback address is set, attempt to redirect * console output back into kernel terminal emulator. */ if (promif_redirect != NULL && fd == prom_stdout_ihandle()) { ow = promif_preout(); rlen = promif_redirect(promif_redirect_arg, (uchar_t *)buf, len); promif_postout(ow); return (rlen); } #ifdef PROM_32BIT_ADDRS if ((uintptr_t)buf > (uint32_t)-1) { /* * This is a hack for kernel message output. * By avoiding calls to promplat_alloc (and * using smallbuf instead) when memory is low * we can print shortish kernel messages without * deadlocking. smallbuf should be at least as * large as the automatic buffer in * prom_printf.c:_doprint()'s stack frame. * promplat_alloc() can block on a mutex and so * is called here before calling promif_preprom(). */ if (len > sizeof (smallbuf)) { obuf = buf; buf = promplat_alloc(len); if (buf == NULL) { return (-1); } promplat_bcopy(obuf, buf, len); } } #endif /* * Normally we'd call promif_preprom() just before * calling into the prom (to enforce single-threaded * access) but here we need to call it before accessing * smallbuf, since smallbuf is statically allocated and * hence can only be accessed by one thread at a time. */ ow = promif_preout(); promif_preprom(); #ifdef PROM_32BIT_ADDRS if ((uintptr_t)buf > (uint32_t)-1) { /* * If buf is small enough, use smallbuf * instead of promplat_alloc() (see above) * smallbuf is static, so single thread * access to it by using it only after * promif_preprom() */ if (len <= sizeof (smallbuf)) { promplat_bcopy(buf, smallbuf, len); buf = smallbuf; } } #endif ci[0] = p1275_ptr2cell("write"); /* Service name */ ci[1] = (cell_t)3; /* #argument cells */ ci[2] = (cell_t)1; /* #result cells */ ci[3] = p1275_uint2cell((uint_t)fd); /* Arg1: ihandle */ ci[4] = p1275_ptr2cell(buf); /* Arg2: buffer addr */ ci[5] = p1275_size2cell(len); /* Arg3: buffer len */ ci[6] = (cell_t)-1; /* Res1: Prime result */ (void) p1275_cif_handler(&ci); rlen = p1275_cell2size(ci[6]); /* Res1: actual len */ promif_postprom(); promif_postout(ow); #ifdef PROM_32BIT_ADDRS if (obuf != NULL) promplat_free(buf, len); #endif return (rlen); } int prom_close(int fd) { cell_t ci[4]; promif_owrap_t *ow; ci[0] = p1275_ptr2cell("close"); /* Service name */ ci[1] = (cell_t)1; /* #argument cells */ ci[2] = (cell_t)0; /* #result cells */ ci[3] = p1275_uint2cell((uint_t)fd); /* Arg1: ihandle */ ow = promif_preout(); promif_preprom(); (void) p1275_cif_handler(&ci); promif_postprom(); promif_postout(ow); return (0); }