1 /****************************************************************************** 2 * 3 * Module Name: aslprintf - ASL Printf/Fprintf macro support 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2017, Intel Corp. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions, and the following disclaimer, 16 * without modification. 17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18 * substantially similar to the "NO WARRANTY" disclaimer below 19 * ("Disclaimer") and any redistribution must be conditioned upon 20 * including a substantially similar Disclaimer requirement for further 21 * binary redistribution. 22 * 3. Neither the names of the above-listed copyright holders nor the names 23 * of any contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * Alternatively, this software may be distributed under the terms of the 27 * GNU General Public License ("GPL") version 2 as published by the Free 28 * Software Foundation. 29 * 30 * NO WARRANTY 31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41 * POSSIBILITY OF SUCH DAMAGES. 42 */ 43 44 #include <contrib/dev/acpica/compiler/aslcompiler.h> 45 #include "aslcompiler.y.h" 46 #include <contrib/dev/acpica/include/amlcode.h> 47 48 #define _COMPONENT ACPI_COMPILER 49 ACPI_MODULE_NAME ("aslprintf") 50 51 52 /* Local prototypes */ 53 54 static void 55 OpcCreateConcatenateNode ( 56 ACPI_PARSE_OBJECT *Op, 57 ACPI_PARSE_OBJECT *Node); 58 59 static void 60 OpcParsePrintf ( 61 ACPI_PARSE_OBJECT *Op, 62 ACPI_PARSE_OBJECT *DestOp); 63 64 65 /******************************************************************************* 66 * 67 * FUNCTION: OpcDoPrintf 68 * 69 * PARAMETERS: Op - printf parse node 70 * 71 * RETURN: None 72 * 73 * DESCRIPTION: Convert printf macro to a Store(..., Debug) AML operation. 74 * 75 ******************************************************************************/ 76 77 void 78 OpcDoPrintf ( 79 ACPI_PARSE_OBJECT *Op) 80 { 81 ACPI_PARSE_OBJECT *DestOp; 82 83 84 /* Store destination is the Debug op */ 85 86 DestOp = TrAllocateNode (PARSEOP_DEBUG); 87 DestOp->Asl.AmlOpcode = AML_DEBUG_OP; 88 DestOp->Asl.Parent = Op; 89 DestOp->Asl.LogicalLineNumber = Op->Asl.LogicalLineNumber; 90 91 OpcParsePrintf (Op, DestOp); 92 } 93 94 95 /******************************************************************************* 96 * 97 * FUNCTION: OpcDoFprintf 98 * 99 * PARAMETERS: Op - fprintf parse node 100 * 101 * RETURN: None 102 * 103 * DESCRIPTION: Convert fprintf macro to a Store AML operation. 104 * 105 ******************************************************************************/ 106 107 void 108 OpcDoFprintf ( 109 ACPI_PARSE_OBJECT *Op) 110 { 111 ACPI_PARSE_OBJECT *DestOp; 112 113 114 /* Store destination is the first argument of fprintf */ 115 116 DestOp = Op->Asl.Child; 117 Op->Asl.Child = DestOp->Asl.Next; 118 DestOp->Asl.Next = NULL; 119 120 OpcParsePrintf (Op, DestOp); 121 } 122 123 124 /******************************************************************************* 125 * 126 * FUNCTION: OpcParsePrintf 127 * 128 * PARAMETERS: Op - Printf parse node 129 * DestOp - Destination of Store operation 130 * 131 * RETURN: None 132 * 133 * DESCRIPTION: Convert printf macro to a Store AML operation. The printf 134 * macro parse tree is layed out as follows: 135 * 136 * Op - printf parse op 137 * Op->Child - Format string 138 * Op->Next - Format string arguments 139 * 140 ******************************************************************************/ 141 142 static void 143 OpcParsePrintf ( 144 ACPI_PARSE_OBJECT *Op, 145 ACPI_PARSE_OBJECT *DestOp) 146 { 147 char *Format; 148 char *StartPosition = NULL; 149 ACPI_PARSE_OBJECT *ArgNode; 150 ACPI_PARSE_OBJECT *NextNode; 151 UINT32 StringLength = 0; 152 char *NewString; 153 BOOLEAN StringToProcess = FALSE; 154 ACPI_PARSE_OBJECT *NewOp; 155 156 157 /* Get format string */ 158 159 Format = ACPI_CAST_PTR (char, Op->Asl.Child->Asl.Value.String); 160 ArgNode = Op->Asl.Child->Asl.Next; 161 162 /* 163 * Detach argument list so that we can use a NULL check to distinguish 164 * the first concatenation operation we need to make 165 */ 166 Op->Asl.Child = NULL; 167 168 for (; *Format; ++Format) 169 { 170 if (*Format != '%') 171 { 172 if (!StringToProcess) 173 { 174 /* Mark the beginning of a string */ 175 176 StartPosition = Format; 177 StringToProcess = TRUE; 178 } 179 180 ++StringLength; 181 continue; 182 } 183 184 /* Save string, if any, to new string object and concat it */ 185 186 if (StringToProcess) 187 { 188 NewString = UtStringCacheCalloc (StringLength + 1); 189 strncpy (NewString, StartPosition, StringLength); 190 191 NewOp = TrAllocateNode (PARSEOP_STRING_LITERAL); 192 NewOp->Asl.Value.String = NewString; 193 NewOp->Asl.AmlOpcode = AML_STRING_OP; 194 NewOp->Asl.AcpiBtype = ACPI_BTYPE_STRING; 195 NewOp->Asl.LogicalLineNumber = Op->Asl.LogicalLineNumber; 196 197 OpcCreateConcatenateNode(Op, NewOp); 198 199 StringLength = 0; 200 StringToProcess = FALSE; 201 } 202 203 ++Format; 204 205 /* 206 * We have a format parameter and will need an argument to go 207 * with it 208 */ 209 if (!ArgNode || 210 ArgNode->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) 211 { 212 AslError(ASL_ERROR, ASL_MSG_ARG_COUNT_LO, Op, NULL); 213 return; 214 } 215 216 /* 217 * We do not support sub-specifiers of printf (flags, width, 218 * precision, length). For specifiers we only support %x/%X for 219 * hex or %s for strings. Also, %o for generic "acpi object". 220 */ 221 switch (*Format) 222 { 223 case 's': 224 225 if (ArgNode->Asl.ParseOpcode != PARSEOP_STRING_LITERAL) 226 { 227 AslError(ASL_ERROR, ASL_MSG_INVALID_TYPE, ArgNode, 228 "String required"); 229 return; 230 } 231 232 NextNode = ArgNode->Asl.Next; 233 ArgNode->Asl.Next = NULL; 234 OpcCreateConcatenateNode(Op, ArgNode); 235 ArgNode = NextNode; 236 continue; 237 238 case 'X': 239 case 'x': 240 case 'o': 241 242 NextNode = ArgNode->Asl.Next; 243 ArgNode->Asl.Next = NULL; 244 245 /* 246 * Append an empty string if the first argument is 247 * not a string. This will implicitly conver the 2nd 248 * concat source to a string per the ACPI specification. 249 */ 250 if (!Op->Asl.Child) 251 { 252 NewOp = TrAllocateNode (PARSEOP_STRING_LITERAL); 253 NewOp->Asl.Value.String = ""; 254 NewOp->Asl.AmlOpcode = AML_STRING_OP; 255 NewOp->Asl.AcpiBtype = ACPI_BTYPE_STRING; 256 NewOp->Asl.LogicalLineNumber = Op->Asl.LogicalLineNumber; 257 258 OpcCreateConcatenateNode(Op, NewOp); 259 } 260 261 OpcCreateConcatenateNode(Op, ArgNode); 262 ArgNode = NextNode; 263 break; 264 265 default: 266 267 AslError(ASL_ERROR, ASL_MSG_INVALID_OPERAND, Op, 268 "Unrecognized format specifier"); 269 continue; 270 } 271 } 272 273 /* Process any remaining string */ 274 275 if (StringToProcess) 276 { 277 NewString = UtStringCacheCalloc (StringLength + 1); 278 strncpy (NewString, StartPosition, StringLength); 279 280 NewOp = TrAllocateNode (PARSEOP_STRING_LITERAL); 281 NewOp->Asl.Value.String = NewString; 282 NewOp->Asl.AcpiBtype = ACPI_BTYPE_STRING; 283 NewOp->Asl.AmlOpcode = AML_STRING_OP; 284 NewOp->Asl.LogicalLineNumber = Op->Asl.LogicalLineNumber; 285 286 OpcCreateConcatenateNode(Op, NewOp); 287 } 288 289 /* 290 * If we get here and there's no child node then Format 291 * was an empty string. Just make a no op. 292 */ 293 if (!Op->Asl.Child) 294 { 295 Op->Asl.ParseOpcode = PARSEOP_NOOP; 296 AslError(ASL_WARNING, ASL_MSG_NULL_STRING, Op, 297 "Converted to NOOP"); 298 return; 299 } 300 301 /* Check for erroneous extra arguments */ 302 303 if (ArgNode && 304 ArgNode->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) 305 { 306 AslError(ASL_WARNING, ASL_MSG_ARG_COUNT_HI, ArgNode, 307 "Extra arguments ignored"); 308 } 309 310 /* Change Op to a Store */ 311 312 Op->Asl.ParseOpcode = PARSEOP_STORE; 313 Op->Common.AmlOpcode = AML_STORE_OP; 314 Op->Asl.CompileFlags = 0; 315 316 /* Disable further optimization */ 317 318 Op->Asl.CompileFlags &= ~NODE_COMPILE_TIME_CONST; 319 UtSetParseOpName (Op); 320 321 /* Set Store destination */ 322 323 Op->Asl.Child->Asl.Next = DestOp; 324 } 325 326 327 /******************************************************************************* 328 * 329 * FUNCTION: OpcCreateConcatenateNode 330 * 331 * PARAMETERS: Op - Parse node 332 * Node - Parse node to be concatenated 333 * 334 * RETURN: None 335 * 336 * DESCRIPTION: Make Node the child of Op. If child node already exists, then 337 * concat child with Node and makes concat node the child of Op. 338 * 339 ******************************************************************************/ 340 341 static void 342 OpcCreateConcatenateNode ( 343 ACPI_PARSE_OBJECT *Op, 344 ACPI_PARSE_OBJECT *Node) 345 { 346 ACPI_PARSE_OBJECT *NewConcatOp; 347 348 349 if (!Op->Asl.Child) 350 { 351 Op->Asl.Child = Node; 352 Node->Asl.Parent = Op; 353 return; 354 } 355 356 NewConcatOp = TrAllocateNode (PARSEOP_CONCATENATE); 357 NewConcatOp->Asl.AmlOpcode = AML_CONCAT_OP; 358 NewConcatOp->Asl.AcpiBtype = 0x7; 359 NewConcatOp->Asl.LogicalLineNumber = Op->Asl.LogicalLineNumber; 360 361 /* First arg is child of Op*/ 362 363 NewConcatOp->Asl.Child = Op->Asl.Child; 364 Op->Asl.Child->Asl.Parent = NewConcatOp; 365 366 /* Second arg is Node */ 367 368 NewConcatOp->Asl.Child->Asl.Next = Node; 369 Node->Asl.Parent = NewConcatOp; 370 371 /* Third arg is Zero (not used) */ 372 373 NewConcatOp->Asl.Child->Asl.Next->Asl.Next = 374 TrAllocateNode (PARSEOP_ZERO); 375 NewConcatOp->Asl.Child->Asl.Next->Asl.Next->Asl.Parent = 376 NewConcatOp; 377 378 Op->Asl.Child = NewConcatOp; 379 NewConcatOp->Asl.Parent = Op; 380 } 381