1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22/* 23 * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26#include <sys/promif.h> 27#include <sys/promimpl.h> 28 29/* 30 * Returns 0 on error. Otherwise returns a handle. 31 */ 32int 33prom_open(char *path) 34{ 35 cell_t ci[5]; 36 promif_owrap_t *ow; 37#ifdef PROM_32BIT_ADDRS 38 char *opath = NULL; 39 size_t len; 40 41 if ((uintptr_t)path > (uint32_t)-1) { 42 opath = path; 43 len = prom_strlen(opath) + 1; /* include terminating NUL */ 44 path = promplat_alloc(len); 45 if (path == NULL) 46 return (0); 47 (void) prom_strcpy(path, opath); 48 } 49#endif 50 51 ow = promif_preout(); 52 promif_preprom(); 53 ci[0] = p1275_ptr2cell("open"); /* Service name */ 54 ci[1] = (cell_t)1; /* #argument cells */ 55 ci[2] = (cell_t)1; /* #result cells */ 56 ci[3] = p1275_ptr2cell(path); /* Arg1: Pathname */ 57 ci[4] = (cell_t)0; /* Res1: Prime result */ 58 59 (void) p1275_cif_handler(&ci); 60 61 promif_postprom(); 62 promif_postout(ow); 63 64#ifdef PROM_32BIT_ADDRS 65 if (opath != NULL) 66 promplat_free(path, len); 67#endif 68 69 return (p1275_cell2int(ci[4])); /* Res1: ihandle */ 70} 71 72 73int 74prom_seek(int fd, unsigned long long offset) 75{ 76 cell_t ci[7]; 77 78 ci[0] = p1275_ptr2cell("seek"); /* Service name */ 79 ci[1] = (cell_t)3; /* #argument cells */ 80 ci[2] = (cell_t)1; /* #result cells */ 81 ci[3] = p1275_uint2cell((uint_t)fd); /* Arg1: ihandle */ 82 ci[4] = p1275_ull2cell_high(offset); /* Arg2: pos.hi */ 83 ci[5] = p1275_ull2cell_low(offset); /* Arg3: pos.lo */ 84 ci[6] = (cell_t)-1; /* Res1: Prime result */ 85 86 promif_preprom(); 87 (void) p1275_cif_handler(&ci); 88 promif_postprom(); 89 90 return (p1275_cell2int(ci[6])); /* Res1: actual */ 91} 92 93/*ARGSUSED3*/ 94ssize_t 95prom_read(ihandle_t fd, caddr_t buf, size_t len, uint_t startblk, char devtype) 96{ 97 cell_t ci[7]; 98 promif_owrap_t *ow; 99#ifdef PROM_32BIT_ADDRS 100 caddr_t obuf = NULL; 101 102 if ((uintptr_t)buf > (uint32_t)-1) { 103 obuf = buf; 104 buf = promplat_alloc(len); 105 if (buf == NULL) 106 return (-1); 107 } 108#endif 109 110 ow = promif_preout(); 111 promif_preprom(); 112 113 ci[0] = p1275_ptr2cell("read"); /* Service name */ 114 ci[1] = (cell_t)3; /* #argument cells */ 115 ci[2] = (cell_t)1; /* #result cells */ 116 ci[3] = p1275_size2cell((uint_t)fd); /* Arg1: ihandle */ 117 ci[4] = p1275_ptr2cell(buf); /* Arg2: buffer address */ 118 ci[5] = p1275_uint2cell(len); /* Arg3: buffer length */ 119 ci[6] = (cell_t)-1; /* Res1: Prime result */ 120 121 (void) p1275_cif_handler(&ci); 122 123 promif_postprom(); 124 promif_postout(ow); 125 126#ifdef PROM_32BIT_ADDRS 127 if (obuf != NULL) { 128 promplat_bcopy(buf, obuf, len); 129 promplat_free(buf, len); 130 } 131#endif 132 133 return (p1275_cell2size(ci[6])); /* Res1: actual length */ 134} 135 136/* 137 * prom_write is the only prom_*() function we have to intercept 138 * because all the other prom_*() io interfaces eventually call 139 * into prom_write(). 140 */ 141/*ARGSUSED3*/ 142ssize_t 143prom_write(ihandle_t fd, caddr_t buf, size_t len, uint_t startblk, char devtype) 144{ 145 cell_t ci[7]; 146 promif_owrap_t *ow; 147 ssize_t rlen; 148 149#ifdef PROM_32BIT_ADDRS 150 caddr_t obuf = NULL; 151 static char smallbuf[256]; 152 153 ASSERT(buf); 154#endif 155 156 /* 157 * If the callback address is set, attempt to redirect 158 * console output back into kernel terminal emulator. 159 */ 160 if (promif_redirect != NULL && fd == prom_stdout_ihandle()) { 161 ow = promif_preout(); 162 rlen = promif_redirect(promif_redirect_arg, (uchar_t *)buf, 163 len); 164 promif_postout(ow); 165 return (rlen); 166 } 167 168#ifdef PROM_32BIT_ADDRS 169 if ((uintptr_t)buf > (uint32_t)-1) { 170 /* 171 * This is a hack for kernel message output. 172 * By avoiding calls to promplat_alloc (and 173 * using smallbuf instead) when memory is low 174 * we can print shortish kernel messages without 175 * deadlocking. smallbuf should be at least as 176 * large as the automatic buffer in 177 * prom_printf.c:_doprint()'s stack frame. 178 * promplat_alloc() can block on a mutex and so 179 * is called here before calling promif_preprom(). 180 */ 181 if (len > sizeof (smallbuf)) { 182 obuf = buf; 183 buf = promplat_alloc(len); 184 if (buf == NULL) { 185 return (-1); 186 } 187 promplat_bcopy(obuf, buf, len); 188 } 189 } 190#endif 191 192 /* 193 * Normally we'd call promif_preprom() just before 194 * calling into the prom (to enforce single-threaded 195 * access) but here we need to call it before accessing 196 * smallbuf, since smallbuf is statically allocated and 197 * hence can only be accessed by one thread at a time. 198 */ 199 ow = promif_preout(); 200 promif_preprom(); 201 202#ifdef PROM_32BIT_ADDRS 203 if ((uintptr_t)buf > (uint32_t)-1) { 204 /* 205 * If buf is small enough, use smallbuf 206 * instead of promplat_alloc() (see above) 207 * smallbuf is static, so single thread 208 * access to it by using it only after 209 * promif_preprom() 210 */ 211 if (len <= sizeof (smallbuf)) { 212 promplat_bcopy(buf, smallbuf, len); 213 buf = smallbuf; 214 } 215 } 216#endif 217 218 ci[0] = p1275_ptr2cell("write"); /* Service name */ 219 ci[1] = (cell_t)3; /* #argument cells */ 220 ci[2] = (cell_t)1; /* #result cells */ 221 ci[3] = p1275_uint2cell((uint_t)fd); /* Arg1: ihandle */ 222 ci[4] = p1275_ptr2cell(buf); /* Arg2: buffer addr */ 223 ci[5] = p1275_size2cell(len); /* Arg3: buffer len */ 224 ci[6] = (cell_t)-1; /* Res1: Prime result */ 225 226 (void) p1275_cif_handler(&ci); 227 rlen = p1275_cell2size(ci[6]); /* Res1: actual len */ 228 229 promif_postprom(); 230 promif_postout(ow); 231 232#ifdef PROM_32BIT_ADDRS 233 if (obuf != NULL) 234 promplat_free(buf, len); 235#endif 236 237 return (rlen); 238} 239 240int 241prom_close(int fd) 242{ 243 cell_t ci[4]; 244 promif_owrap_t *ow; 245 246 ci[0] = p1275_ptr2cell("close"); /* Service name */ 247 ci[1] = (cell_t)1; /* #argument cells */ 248 ci[2] = (cell_t)0; /* #result cells */ 249 ci[3] = p1275_uint2cell((uint_t)fd); /* Arg1: ihandle */ 250 251 ow = promif_preout(); 252 promif_preprom(); 253 (void) p1275_cif_handler(&ci); 254 promif_postprom(); 255 promif_postout(ow); 256 257 return (0); 258} 259