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 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/promif.h> 30 #include <sys/promimpl.h> 31 32 /* 33 * Returns 0 on error. Otherwise returns a handle. 34 */ 35 int 36 prom_open(char *path) 37 { 38 cell_t ci[5]; 39 promif_owrap_t *ow; 40 #ifdef PROM_32BIT_ADDRS 41 char *opath = NULL; 42 size_t len; 43 44 if ((uintptr_t)path > (uint32_t)-1) { 45 opath = path; 46 len = prom_strlen(opath) + 1; /* include terminating NUL */ 47 path = promplat_alloc(len); 48 if (path == NULL) 49 return (0); 50 (void) prom_strcpy(path, opath); 51 } 52 #endif 53 54 ow = promif_preout(); 55 promif_preprom(); 56 ci[0] = p1275_ptr2cell("open"); /* Service name */ 57 ci[1] = (cell_t)1; /* #argument cells */ 58 ci[2] = (cell_t)1; /* #result cells */ 59 ci[3] = p1275_ptr2cell(path); /* Arg1: Pathname */ 60 ci[4] = (cell_t)0; /* Res1: Prime result */ 61 62 (void) p1275_cif_handler(&ci); 63 64 promif_postprom(); 65 promif_postout(ow); 66 67 #ifdef PROM_32BIT_ADDRS 68 if (opath != NULL) 69 promplat_free(path, len); 70 #endif 71 72 return (p1275_cell2int(ci[4])); /* Res1: ihandle */ 73 } 74 75 76 int 77 prom_seek(int fd, unsigned long long offset) 78 { 79 cell_t ci[7]; 80 81 ci[0] = p1275_ptr2cell("seek"); /* Service name */ 82 ci[1] = (cell_t)3; /* #argument cells */ 83 ci[2] = (cell_t)1; /* #result cells */ 84 ci[3] = p1275_uint2cell((uint_t)fd); /* Arg1: ihandle */ 85 ci[4] = p1275_ull2cell_high(offset); /* Arg2: pos.hi */ 86 ci[5] = p1275_ull2cell_low(offset); /* Arg3: pos.lo */ 87 ci[6] = (cell_t)-1; /* Res1: Prime result */ 88 89 promif_preprom(); 90 (void) p1275_cif_handler(&ci); 91 promif_postprom(); 92 93 return (p1275_cell2int(ci[6])); /* Res1: actual */ 94 } 95 96 /*ARGSUSED3*/ 97 ssize_t 98 prom_read(ihandle_t fd, caddr_t buf, size_t len, uint_t startblk, char devtype) 99 { 100 cell_t ci[7]; 101 promif_owrap_t *ow; 102 #ifdef PROM_32BIT_ADDRS 103 caddr_t obuf = NULL; 104 105 if ((uintptr_t)buf > (uint32_t)-1) { 106 obuf = buf; 107 buf = promplat_alloc(len); 108 if (buf == NULL) 109 return (-1); 110 } 111 #endif 112 113 ow = promif_preout(); 114 promif_preprom(); 115 116 ci[0] = p1275_ptr2cell("read"); /* Service name */ 117 ci[1] = (cell_t)3; /* #argument cells */ 118 ci[2] = (cell_t)1; /* #result cells */ 119 ci[3] = p1275_size2cell((uint_t)fd); /* Arg1: ihandle */ 120 ci[4] = p1275_ptr2cell(buf); /* Arg2: buffer address */ 121 ci[5] = p1275_uint2cell(len); /* Arg3: buffer length */ 122 ci[6] = (cell_t)-1; /* Res1: Prime result */ 123 124 (void) p1275_cif_handler(&ci); 125 126 promif_postprom(); 127 promif_postout(ow); 128 129 #ifdef PROM_32BIT_ADDRS 130 if (obuf != NULL) { 131 promplat_bcopy(buf, obuf, len); 132 promplat_free(buf, len); 133 } 134 #endif 135 136 return (p1275_cell2size(ci[6])); /* Res1: actual length */ 137 } 138 139 /* 140 * prom_write is the only prom_*() function we have to intercept 141 * because all the other prom_*() io interfaces eventually call 142 * into prom_write(). 143 */ 144 /*ARGSUSED3*/ 145 ssize_t 146 prom_write(ihandle_t fd, caddr_t buf, size_t len, uint_t startblk, char devtype) 147 { 148 cell_t ci[7]; 149 promif_owrap_t *ow; 150 ssize_t rlen; 151 152 #ifdef PROM_32BIT_ADDRS 153 caddr_t obuf = NULL; 154 static char smallbuf[256]; 155 156 ASSERT(buf); 157 158 if ((uintptr_t)buf > (uint32_t)-1) { 159 /* 160 * This is a hack for kernel message output. 161 * By avoiding calls to promplat_alloc (and 162 * using smallbuf instead) when memory is low 163 * we can print shortish kernel messages without 164 * deadlocking. smallbuf should be at least as 165 * large as the automatic buffer in 166 * prom_printf.c:_doprint()'s stack frame. 167 * promplat_alloc() can block on a mutex and so 168 * is called here before calling promif_preprom(). 169 */ 170 171 if (len > sizeof (smallbuf)) { 172 obuf = buf; 173 buf = promplat_alloc(len); 174 if (buf == NULL) { 175 return (-1); 176 } 177 promplat_bcopy(obuf, buf, len); 178 } 179 } 180 #endif 181 182 ow = promif_preout(); 183 promif_preprom(); 184 185 #ifdef PROM_32BIT_ADDRS 186 187 if ((uintptr_t)buf > (uint32_t)-1) { 188 /* 189 * If buf is small enough, use smallbuf 190 * instead of promplat_alloc() (see above) 191 * smallbuf is static, so single thread 192 * access to it by using it only after 193 * promif_preprom() 194 */ 195 if (len <= sizeof (smallbuf)) { 196 promplat_bcopy(buf, smallbuf, len); 197 buf = smallbuf; 198 } 199 } 200 #endif 201 /* 202 * If the callback address is set, attempt to redirect 203 * console output back into kernel terminal emulator. 204 */ 205 if (promif_redirect != NULL && 206 fd == prom_stdout_ihandle()) { 207 /* 208 * even if we're re-directing output to the kernel 209 * console device, we still have to call promif_preout() 210 * and promif_preprom() because these functions make sure 211 * that the console device is powered up before sending 212 * output to it. 213 */ 214 rlen = promif_redirect(promif_redirect_arg, 215 (uchar_t *)buf, len); 216 } else { 217 ci[0] = p1275_ptr2cell("write"); /* Service name */ 218 ci[1] = (cell_t)3; /* #argument cells */ 219 ci[2] = (cell_t)1; /* #result cells */ 220 ci[3] = p1275_uint2cell((uint_t)fd); /* Arg1: ihandle */ 221 ci[4] = p1275_ptr2cell(buf); /* Arg2: buffer addr */ 222 ci[5] = p1275_size2cell(len); /* Arg3: buffer len */ 223 ci[6] = (cell_t)-1; /* Res1: Prime result */ 224 225 (void) p1275_cif_handler(&ci); 226 rlen = p1275_cell2size(ci[6]); /* Res1: actual len */ 227 } 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