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 */ 32 int 33 prom_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 73 int 74 prom_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*/ 94 ssize_t 95 prom_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*/ 142 ssize_t 143 prom_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 240 int 241 prom_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