Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
6595 serge 1
/******************************************************************************
2
 *
3
 * Module Name: exfldio - Aml Field I/O
4
 *
5
 *****************************************************************************/
6
 
7
/*
8
 * Copyright (C) 2000 - 2015, 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 
45
#include "accommon.h"
46
#include "acinterp.h"
47
#include "amlcode.h"
48
#include "acevents.h"
49
#include "acdispat.h"
50
 
51
#define _COMPONENT          ACPI_EXECUTER
52
ACPI_MODULE_NAME("exfldio")
53
 
54
/* Local prototypes */
55
static acpi_status
56
acpi_ex_field_datum_io(union acpi_operand_object *obj_desc,
57
		       u32 field_datum_byte_offset, u64 *value, u32 read_write);
58
 
59
static u8
60
acpi_ex_register_overflow(union acpi_operand_object *obj_desc, u64 value);
61
 
62
static acpi_status
63
acpi_ex_setup_region(union acpi_operand_object *obj_desc,
64
		     u32 field_datum_byte_offset);
65
 
66
/*******************************************************************************
67
 *
68
 * FUNCTION:    acpi_ex_setup_region
69
 *
70
 * PARAMETERS:  obj_desc                - Field to be read or written
71
 *              field_datum_byte_offset - Byte offset of this datum within the
72
 *                                        parent field
73
 *
74
 * RETURN:      Status
75
 *
76
 * DESCRIPTION: Common processing for acpi_ex_extract_from_field and
77
 *              acpi_ex_insert_into_field. Initialize the Region if necessary and
78
 *              validate the request.
79
 *
80
 ******************************************************************************/
81
 
82
static acpi_status
83
acpi_ex_setup_region(union acpi_operand_object *obj_desc,
84
		     u32 field_datum_byte_offset)
85
{
86
	acpi_status status = AE_OK;
87
	union acpi_operand_object *rgn_desc;
88
	u8 space_id;
89
 
90
	ACPI_FUNCTION_TRACE_U32(ex_setup_region, field_datum_byte_offset);
91
 
92
	rgn_desc = obj_desc->common_field.region_obj;
93
 
94
	/* We must have a valid region */
95
 
96
	if (rgn_desc->common.type != ACPI_TYPE_REGION) {
97
		ACPI_ERROR((AE_INFO, "Needed Region, found type 0x%X (%s)",
98
			    rgn_desc->common.type,
99
			    acpi_ut_get_object_type_name(rgn_desc)));
100
 
101
		return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
102
	}
103
 
104
	space_id = rgn_desc->region.space_id;
105
 
106
	/* Validate the Space ID */
107
 
108
	if (!acpi_is_valid_space_id(space_id)) {
109
		ACPI_ERROR((AE_INFO,
110
			    "Invalid/unknown Address Space ID: 0x%2.2X",
111
			    space_id));
112
		return_ACPI_STATUS(AE_AML_INVALID_SPACE_ID);
113
	}
114
 
115
	/*
116
	 * If the Region Address and Length have not been previously evaluated,
117
	 * evaluate them now and save the results.
118
	 */
119
	if (!(rgn_desc->common.flags & AOPOBJ_DATA_VALID)) {
120
		status = acpi_ds_get_region_arguments(rgn_desc);
121
		if (ACPI_FAILURE(status)) {
122
			return_ACPI_STATUS(status);
123
		}
124
	}
125
 
126
	/*
127
	 * Exit now for SMBus, GSBus or IPMI address space, it has a non-linear
128
	 * address space and the request cannot be directly validated
129
	 */
130
	if (space_id == ACPI_ADR_SPACE_SMBUS ||
131
	    space_id == ACPI_ADR_SPACE_GSBUS ||
132
	    space_id == ACPI_ADR_SPACE_IPMI) {
133
 
134
		/* SMBus or IPMI has a non-linear address space */
135
 
136
		return_ACPI_STATUS(AE_OK);
137
	}
138
#ifdef ACPI_UNDER_DEVELOPMENT
139
	/*
140
	 * If the Field access is any_acc, we can now compute the optimal
141
	 * access (because we know know the length of the parent region)
142
	 */
143
	if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
144
		if (ACPI_FAILURE(status)) {
145
			return_ACPI_STATUS(status);
146
		}
147
	}
148
#endif
149
 
150
	/*
151
	 * Validate the request. The entire request from the byte offset for a
152
	 * length of one field datum (access width) must fit within the region.
153
	 * (Region length is specified in bytes)
154
	 */
155
	if (rgn_desc->region.length <
156
	    (obj_desc->common_field.base_byte_offset + field_datum_byte_offset +
157
	     obj_desc->common_field.access_byte_width)) {
158
		if (acpi_gbl_enable_interpreter_slack) {
159
			/*
160
			 * Slack mode only:  We will go ahead and allow access to this
161
			 * field if it is within the region length rounded up to the next
162
			 * access width boundary. acpi_size cast for 64-bit compile.
163
			 */
164
			if (ACPI_ROUND_UP(rgn_desc->region.length,
165
					  obj_desc->common_field.
166
					  access_byte_width) >=
167
			    ((acpi_size) obj_desc->common_field.
168
			     base_byte_offset +
169
			     obj_desc->common_field.access_byte_width +
170
			     field_datum_byte_offset)) {
171
				return_ACPI_STATUS(AE_OK);
172
			}
173
		}
174
 
175
		if (rgn_desc->region.length <
176
		    obj_desc->common_field.access_byte_width) {
177
			/*
178
			 * This is the case where the access_type (acc_word, etc.) is wider
179
			 * than the region itself. For example, a region of length one
180
			 * byte, and a field with Dword access specified.
181
			 */
182
			ACPI_ERROR((AE_INFO,
183
				    "Field [%4.4s] access width (%u bytes) too large for region [%4.4s] (length %u)",
184
				    acpi_ut_get_node_name(obj_desc->
185
							  common_field.node),
186
				    obj_desc->common_field.access_byte_width,
187
				    acpi_ut_get_node_name(rgn_desc->region.
188
							  node),
189
				    rgn_desc->region.length));
190
		}
191
 
192
		/*
193
		 * Offset rounded up to next multiple of field width
194
		 * exceeds region length, indicate an error
195
		 */
196
		ACPI_ERROR((AE_INFO,
197
			    "Field [%4.4s] Base+Offset+Width %u+%u+%u is beyond end of region [%4.4s] (length %u)",
198
			    acpi_ut_get_node_name(obj_desc->common_field.node),
199
			    obj_desc->common_field.base_byte_offset,
200
			    field_datum_byte_offset,
201
			    obj_desc->common_field.access_byte_width,
202
			    acpi_ut_get_node_name(rgn_desc->region.node),
203
			    rgn_desc->region.length));
204
 
205
		return_ACPI_STATUS(AE_AML_REGION_LIMIT);
206
	}
207
 
208
	return_ACPI_STATUS(AE_OK);
209
}
210
 
211
/*******************************************************************************
212
 *
213
 * FUNCTION:    acpi_ex_access_region
214
 *
215
 * PARAMETERS:  obj_desc                - Field to be read
216
 *              field_datum_byte_offset - Byte offset of this datum within the
217
 *                                        parent field
218
 *              value                   - Where to store value (must at least
219
 *                                        64 bits)
220
 *              function                - Read or Write flag plus other region-
221
 *                                        dependent flags
222
 *
223
 * RETURN:      Status
224
 *
225
 * DESCRIPTION: Read or Write a single field datum to an Operation Region.
226
 *
227
 ******************************************************************************/
228
 
229
acpi_status
230
acpi_ex_access_region(union acpi_operand_object *obj_desc,
231
		      u32 field_datum_byte_offset, u64 *value, u32 function)
232
{
233
	acpi_status status;
234
	union acpi_operand_object *rgn_desc;
235
	u32 region_offset;
236
 
237
	ACPI_FUNCTION_TRACE(ex_access_region);
238
 
239
	/*
240
	 * Ensure that the region operands are fully evaluated and verify
241
	 * the validity of the request
242
	 */
243
	status = acpi_ex_setup_region(obj_desc, field_datum_byte_offset);
244
	if (ACPI_FAILURE(status)) {
245
		return_ACPI_STATUS(status);
246
	}
247
 
248
	/*
249
	 * The physical address of this field datum is:
250
	 *
251
	 * 1) The base of the region, plus
252
	 * 2) The base offset of the field, plus
253
	 * 3) The current offset into the field
254
	 */
255
	rgn_desc = obj_desc->common_field.region_obj;
256
	region_offset =
257
	    obj_desc->common_field.base_byte_offset + field_datum_byte_offset;
258
 
259
	if ((function & ACPI_IO_MASK) == ACPI_READ) {
260
		ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "[READ]"));
261
	} else {
262
		ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "[WRITE]"));
263
	}
264
 
265
	ACPI_DEBUG_PRINT_RAW((ACPI_DB_BFIELD,
266
			      " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %8.8X%8.8X\n",
267
			      acpi_ut_get_region_name(rgn_desc->region.
268
						      space_id),
269
			      rgn_desc->region.space_id,
270
			      obj_desc->common_field.access_byte_width,
271
			      obj_desc->common_field.base_byte_offset,
272
			      field_datum_byte_offset,
273
			      ACPI_FORMAT_UINT64(rgn_desc->region.address +
274
						 region_offset)));
275
 
276
	/* Invoke the appropriate address_space/op_region handler */
277
 
278
	status = acpi_ev_address_space_dispatch(rgn_desc, obj_desc,
279
						function, region_offset,
280
						ACPI_MUL_8(obj_desc->
281
							   common_field.
282
							   access_byte_width),
283
						value);
284
 
285
	if (ACPI_FAILURE(status)) {
286
		if (status == AE_NOT_IMPLEMENTED) {
287
			ACPI_ERROR((AE_INFO,
288
				    "Region %s (ID=%u) not implemented",
289
				    acpi_ut_get_region_name(rgn_desc->region.
290
							    space_id),
291
				    rgn_desc->region.space_id));
292
		} else if (status == AE_NOT_EXIST) {
293
			ACPI_ERROR((AE_INFO,
294
				    "Region %s (ID=%u) has no handler",
295
				    acpi_ut_get_region_name(rgn_desc->region.
296
							    space_id),
297
				    rgn_desc->region.space_id));
298
		}
299
	}
300
 
301
	return_ACPI_STATUS(status);
302
}
303
 
304
/*******************************************************************************
305
 *
306
 * FUNCTION:    acpi_ex_register_overflow
307
 *
308
 * PARAMETERS:  obj_desc                - Register(Field) to be written
309
 *              value                   - Value to be stored
310
 *
311
 * RETURN:      TRUE if value overflows the field, FALSE otherwise
312
 *
313
 * DESCRIPTION: Check if a value is out of range of the field being written.
314
 *              Used to check if the values written to Index and Bank registers
315
 *              are out of range. Normally, the value is simply truncated
316
 *              to fit the field, but this case is most likely a serious
317
 *              coding error in the ASL.
318
 *
319
 ******************************************************************************/
320
 
321
static u8
322
acpi_ex_register_overflow(union acpi_operand_object *obj_desc, u64 value)
323
{
324
 
325
	if (obj_desc->common_field.bit_length >= ACPI_INTEGER_BIT_SIZE) {
326
		/*
327
		 * The field is large enough to hold the maximum integer, so we can
328
		 * never overflow it.
329
		 */
330
		return (FALSE);
331
	}
332
 
333
	if (value >= ((u64) 1 << obj_desc->common_field.bit_length)) {
334
		/*
335
		 * The Value is larger than the maximum value that can fit into
336
		 * the register.
337
		 */
338
		ACPI_ERROR((AE_INFO,
339
			    "Index value 0x%8.8X%8.8X overflows field width 0x%X",
340
			    ACPI_FORMAT_UINT64(value),
341
			    obj_desc->common_field.bit_length));
342
 
343
		return (TRUE);
344
	}
345
 
346
	/* The Value will fit into the field with no truncation */
347
 
348
	return (FALSE);
349
}
350
 
351
/*******************************************************************************
352
 *
353
 * FUNCTION:    acpi_ex_field_datum_io
354
 *
355
 * PARAMETERS:  obj_desc                - Field to be read
356
 *              field_datum_byte_offset - Byte offset of this datum within the
357
 *                                        parent field
358
 *              value                   - Where to store value (must be 64 bits)
359
 *              read_write              - Read or Write flag
360
 *
361
 * RETURN:      Status
362
 *
363
 * DESCRIPTION: Read or Write a single datum of a field. The field_type is
364
 *              demultiplexed here to handle the different types of fields
365
 *              (buffer_field, region_field, index_field, bank_field)
366
 *
367
 ******************************************************************************/
368
 
369
static acpi_status
370
acpi_ex_field_datum_io(union acpi_operand_object *obj_desc,
371
		       u32 field_datum_byte_offset, u64 *value, u32 read_write)
372
{
373
	acpi_status status;
374
	u64 local_value;
375
 
376
	ACPI_FUNCTION_TRACE_U32(ex_field_datum_io, field_datum_byte_offset);
377
 
378
	if (read_write == ACPI_READ) {
379
		if (!value) {
380
			local_value = 0;
381
 
382
			/* To support reads without saving return value */
383
			value = &local_value;
384
		}
385
 
386
		/* Clear the entire return buffer first, [Very Important!] */
387
 
388
		*value = 0;
389
	}
390
 
391
	/*
392
	 * The four types of fields are:
393
	 *
394
	 * buffer_field - Read/write from/to a Buffer
395
	 * region_field - Read/write from/to a Operation Region.
396
	 * bank_field  - Write to a Bank Register, then read/write from/to an
397
	 *               operation_region
398
	 * index_field - Write to an Index Register, then read/write from/to a
399
	 *               Data Register
400
	 */
401
	switch (obj_desc->common.type) {
402
	case ACPI_TYPE_BUFFER_FIELD:
403
		/*
404
		 * If the buffer_field arguments have not been previously evaluated,
405
		 * evaluate them now and save the results.
406
		 */
407
		if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
408
			status = acpi_ds_get_buffer_field_arguments(obj_desc);
409
			if (ACPI_FAILURE(status)) {
410
				return_ACPI_STATUS(status);
411
			}
412
		}
413
 
414
		if (read_write == ACPI_READ) {
415
			/*
416
			 * Copy the data from the source buffer.
417
			 * Length is the field width in bytes.
418
			 */
419
			memcpy(value,
420
			       (obj_desc->buffer_field.buffer_obj)->buffer.
421
			       pointer +
422
			       obj_desc->buffer_field.base_byte_offset +
423
			       field_datum_byte_offset,
424
			       obj_desc->common_field.access_byte_width);
425
		} else {
426
			/*
427
			 * Copy the data to the target buffer.
428
			 * Length is the field width in bytes.
429
			 */
430
			memcpy((obj_desc->buffer_field.buffer_obj)->buffer.
431
			       pointer +
432
			       obj_desc->buffer_field.base_byte_offset +
433
			       field_datum_byte_offset, value,
434
			       obj_desc->common_field.access_byte_width);
435
		}
436
 
437
		status = AE_OK;
438
		break;
439
 
440
	case ACPI_TYPE_LOCAL_BANK_FIELD:
441
		/*
442
		 * Ensure that the bank_value is not beyond the capacity of
443
		 * the register
444
		 */
445
		if (acpi_ex_register_overflow(obj_desc->bank_field.bank_obj,
446
					      (u64) obj_desc->bank_field.
447
					      value)) {
448
			return_ACPI_STATUS(AE_AML_REGISTER_LIMIT);
449
		}
450
 
451
		/*
452
		 * For bank_fields, we must write the bank_value to the bank_register
453
		 * (itself a region_field) before we can access the data.
454
		 */
455
		status =
456
		    acpi_ex_insert_into_field(obj_desc->bank_field.bank_obj,
457
					      &obj_desc->bank_field.value,
458
					      sizeof(obj_desc->bank_field.
459
						     value));
460
		if (ACPI_FAILURE(status)) {
461
			return_ACPI_STATUS(status);
462
		}
463
 
464
		/*
465
		 * Now that the Bank has been selected, fall through to the
466
		 * region_field case and write the datum to the Operation Region
467
		 */
468
 
469
		/*lint -fallthrough */
470
 
471
	case ACPI_TYPE_LOCAL_REGION_FIELD:
472
		/*
473
		 * For simple region_fields, we just directly access the owning
474
		 * Operation Region.
475
		 */
476
		status =
477
		    acpi_ex_access_region(obj_desc, field_datum_byte_offset,
478
					  value, read_write);
479
		break;
480
 
481
	case ACPI_TYPE_LOCAL_INDEX_FIELD:
482
		/*
483
		 * Ensure that the index_value is not beyond the capacity of
484
		 * the register
485
		 */
486
		if (acpi_ex_register_overflow(obj_desc->index_field.index_obj,
487
					      (u64) obj_desc->index_field.
488
					      value)) {
489
			return_ACPI_STATUS(AE_AML_REGISTER_LIMIT);
490
		}
491
 
492
		/* Write the index value to the index_register (itself a region_field) */
493
 
494
		field_datum_byte_offset += obj_desc->index_field.value;
495
 
496
		ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
497
				  "Write to Index Register: Value %8.8X\n",
498
				  field_datum_byte_offset));
499
 
500
		status =
501
		    acpi_ex_insert_into_field(obj_desc->index_field.index_obj,
502
					      &field_datum_byte_offset,
503
					      sizeof(field_datum_byte_offset));
504
		if (ACPI_FAILURE(status)) {
505
			return_ACPI_STATUS(status);
506
		}
507
 
508
		if (read_write == ACPI_READ) {
509
 
510
			/* Read the datum from the data_register */
511
 
512
			ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
513
					  "Read from Data Register\n"));
514
 
515
			status =
516
			    acpi_ex_extract_from_field(obj_desc->index_field.
517
						       data_obj, value,
518
						       sizeof(u64));
519
		} else {
520
			/* Write the datum to the data_register */
521
 
522
			ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
523
					  "Write to Data Register: Value %8.8X%8.8X\n",
524
					  ACPI_FORMAT_UINT64(*value)));
525
 
526
			status =
527
			    acpi_ex_insert_into_field(obj_desc->index_field.
528
						      data_obj, value,
529
						      sizeof(u64));
530
		}
531
		break;
532
 
533
	default:
534
 
535
		ACPI_ERROR((AE_INFO, "Wrong object type in field I/O %u",
536
			    obj_desc->common.type));
537
		status = AE_AML_INTERNAL;
538
		break;
539
	}
540
 
541
	if (ACPI_SUCCESS(status)) {
542
		if (read_write == ACPI_READ) {
543
			ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
544
					  "Value Read %8.8X%8.8X, Width %u\n",
545
					  ACPI_FORMAT_UINT64(*value),
546
					  obj_desc->common_field.
547
					  access_byte_width));
548
		} else {
549
			ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
550
					  "Value Written %8.8X%8.8X, Width %u\n",
551
					  ACPI_FORMAT_UINT64(*value),
552
					  obj_desc->common_field.
553
					  access_byte_width));
554
		}
555
	}
556
 
557
	return_ACPI_STATUS(status);
558
}
559
 
560
/*******************************************************************************
561
 *
562
 * FUNCTION:    acpi_ex_write_with_update_rule
563
 *
564
 * PARAMETERS:  obj_desc                - Field to be written
565
 *              mask                    - bitmask within field datum
566
 *              field_value             - Value to write
567
 *              field_datum_byte_offset - Offset of datum within field
568
 *
569
 * RETURN:      Status
570
 *
571
 * DESCRIPTION: Apply the field update rule to a field write
572
 *
573
 ******************************************************************************/
574
 
575
acpi_status
576
acpi_ex_write_with_update_rule(union acpi_operand_object *obj_desc,
577
			       u64 mask,
578
			       u64 field_value, u32 field_datum_byte_offset)
579
{
580
	acpi_status status = AE_OK;
581
	u64 merged_value;
582
	u64 current_value;
583
 
584
	ACPI_FUNCTION_TRACE_U32(ex_write_with_update_rule, mask);
585
 
586
	/* Start with the new bits  */
587
 
588
	merged_value = field_value;
589
 
590
	/* If the mask is all ones, we don't need to worry about the update rule */
591
 
592
	if (mask != ACPI_UINT64_MAX) {
593
 
594
		/* Decode the update rule */
595
 
596
		switch (obj_desc->common_field.
597
			field_flags & AML_FIELD_UPDATE_RULE_MASK) {
598
		case AML_FIELD_UPDATE_PRESERVE:
599
			/*
600
			 * Check if update rule needs to be applied (not if mask is all
601
			 * ones)  The left shift drops the bits we want to ignore.
602
			 */
603
			if ((~mask << (ACPI_MUL_8(sizeof(mask)) -
604
				       ACPI_MUL_8(obj_desc->common_field.
605
						  access_byte_width))) != 0) {
606
				/*
607
				 * Read the current contents of the byte/word/dword containing
608
				 * the field, and merge with the new field value.
609
				 */
610
				status =
611
				    acpi_ex_field_datum_io(obj_desc,
612
							   field_datum_byte_offset,
613
							   ¤t_value,
614
							   ACPI_READ);
615
				if (ACPI_FAILURE(status)) {
616
					return_ACPI_STATUS(status);
617
				}
618
 
619
				merged_value |= (current_value & ~mask);
620
			}
621
			break;
622
 
623
		case AML_FIELD_UPDATE_WRITE_AS_ONES:
624
 
625
			/* Set positions outside the field to all ones */
626
 
627
			merged_value |= ~mask;
628
			break;
629
 
630
		case AML_FIELD_UPDATE_WRITE_AS_ZEROS:
631
 
632
			/* Set positions outside the field to all zeros */
633
 
634
			merged_value &= mask;
635
			break;
636
 
637
		default:
638
 
639
			ACPI_ERROR((AE_INFO,
640
				    "Unknown UpdateRule value: 0x%X",
641
				    (obj_desc->common_field.
642
				     field_flags &
643
				     AML_FIELD_UPDATE_RULE_MASK)));
644
			return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
645
		}
646
	}
647
 
648
	ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
649
			  "Mask %8.8X%8.8X, DatumOffset %X, Width %X, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n",
650
			  ACPI_FORMAT_UINT64(mask),
651
			  field_datum_byte_offset,
652
			  obj_desc->common_field.access_byte_width,
653
			  ACPI_FORMAT_UINT64(field_value),
654
			  ACPI_FORMAT_UINT64(merged_value)));
655
 
656
	/* Write the merged value */
657
 
658
	status = acpi_ex_field_datum_io(obj_desc, field_datum_byte_offset,
659
					&merged_value, ACPI_WRITE);
660
 
661
	return_ACPI_STATUS(status);
662
}
663
 
664
/*******************************************************************************
665
 *
666
 * FUNCTION:    acpi_ex_extract_from_field
667
 *
668
 * PARAMETERS:  obj_desc            - Field to be read
669
 *              buffer              - Where to store the field data
670
 *              buffer_length       - Length of Buffer
671
 *
672
 * RETURN:      Status
673
 *
674
 * DESCRIPTION: Retrieve the current value of the given field
675
 *
676
 ******************************************************************************/
677
 
678
acpi_status
679
acpi_ex_extract_from_field(union acpi_operand_object *obj_desc,
680
			   void *buffer, u32 buffer_length)
681
{
682
	acpi_status status;
683
	u64 raw_datum;
684
	u64 merged_datum;
685
	u32 field_offset = 0;
686
	u32 buffer_offset = 0;
687
	u32 buffer_tail_bits;
688
	u32 datum_count;
689
	u32 field_datum_count;
690
	u32 access_bit_width;
691
	u32 i;
692
 
693
	ACPI_FUNCTION_TRACE(ex_extract_from_field);
694
 
695
	/* Validate target buffer and clear it */
696
 
697
	if (buffer_length <
698
	    ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length)) {
699
		ACPI_ERROR((AE_INFO,
700
			    "Field size %u (bits) is too large for buffer (%u)",
701
			    obj_desc->common_field.bit_length, buffer_length));
702
 
703
		return_ACPI_STATUS(AE_BUFFER_OVERFLOW);
704
	}
705
 
706
	memset(buffer, 0, buffer_length);
707
	access_bit_width = ACPI_MUL_8(obj_desc->common_field.access_byte_width);
708
 
709
	/* Handle the simple case here */
710
 
711
	if ((obj_desc->common_field.start_field_bit_offset == 0) &&
712
	    (obj_desc->common_field.bit_length == access_bit_width)) {
713
		if (buffer_length >= sizeof(u64)) {
714
			status =
715
			    acpi_ex_field_datum_io(obj_desc, 0, buffer,
716
						   ACPI_READ);
717
		} else {
718
			/* Use raw_datum (u64) to handle buffers < 64 bits */
719
 
720
			status =
721
			    acpi_ex_field_datum_io(obj_desc, 0, &raw_datum,
722
						   ACPI_READ);
723
			memcpy(buffer, &raw_datum, buffer_length);
724
		}
725
 
726
		return_ACPI_STATUS(status);
727
	}
728
 
729
/* TBD: Move to common setup code */
730
 
731
	/* Field algorithm is limited to sizeof(u64), truncate if needed */
732
 
733
	if (obj_desc->common_field.access_byte_width > sizeof(u64)) {
734
		obj_desc->common_field.access_byte_width = sizeof(u64);
735
		access_bit_width = sizeof(u64) * 8;
736
	}
737
 
738
	/* Compute the number of datums (access width data items) */
739
 
740
	datum_count =
741
	    ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length,
742
			     access_bit_width);
743
 
744
	field_datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length +
745
					     obj_desc->common_field.
746
					     start_field_bit_offset,
747
					     access_bit_width);
748
 
749
	/* Priming read from the field */
750
 
751
	status =
752
	    acpi_ex_field_datum_io(obj_desc, field_offset, &raw_datum,
753
				   ACPI_READ);
754
	if (ACPI_FAILURE(status)) {
755
		return_ACPI_STATUS(status);
756
	}
757
	merged_datum =
758
	    raw_datum >> obj_desc->common_field.start_field_bit_offset;
759
 
760
	/* Read the rest of the field */
761
 
762
	for (i = 1; i < field_datum_count; i++) {
763
 
764
		/* Get next input datum from the field */
765
 
766
		field_offset += obj_desc->common_field.access_byte_width;
767
		status = acpi_ex_field_datum_io(obj_desc, field_offset,
768
						&raw_datum, ACPI_READ);
769
		if (ACPI_FAILURE(status)) {
770
			return_ACPI_STATUS(status);
771
		}
772
 
773
		/*
774
		 * Merge with previous datum if necessary.
775
		 *
776
		 * Note: Before the shift, check if the shift value will be larger than
777
		 * the integer size. If so, there is no need to perform the operation.
778
		 * This avoids the differences in behavior between different compilers
779
		 * concerning shift values larger than the target data width.
780
		 */
781
		if (access_bit_width -
782
		    obj_desc->common_field.start_field_bit_offset <
783
		    ACPI_INTEGER_BIT_SIZE) {
784
			merged_datum |=
785
			    raw_datum << (access_bit_width -
786
					  obj_desc->common_field.
787
					  start_field_bit_offset);
788
		}
789
 
790
		if (i == datum_count) {
791
			break;
792
		}
793
 
794
		/* Write merged datum to target buffer */
795
 
796
		memcpy(((char *)buffer) + buffer_offset, &merged_datum,
797
		       ACPI_MIN(obj_desc->common_field.access_byte_width,
798
				buffer_length - buffer_offset));
799
 
800
		buffer_offset += obj_desc->common_field.access_byte_width;
801
		merged_datum =
802
		    raw_datum >> obj_desc->common_field.start_field_bit_offset;
803
	}
804
 
805
	/* Mask off any extra bits in the last datum */
806
 
807
	buffer_tail_bits = obj_desc->common_field.bit_length % access_bit_width;
808
	if (buffer_tail_bits) {
809
		merged_datum &= ACPI_MASK_BITS_ABOVE(buffer_tail_bits);
810
	}
811
 
812
	/* Write the last datum to the buffer */
813
 
814
	memcpy(((char *)buffer) + buffer_offset, &merged_datum,
815
	       ACPI_MIN(obj_desc->common_field.access_byte_width,
816
			buffer_length - buffer_offset));
817
 
818
	return_ACPI_STATUS(AE_OK);
819
}
820
 
821
/*******************************************************************************
822
 *
823
 * FUNCTION:    acpi_ex_insert_into_field
824
 *
825
 * PARAMETERS:  obj_desc            - Field to be written
826
 *              buffer              - Data to be written
827
 *              buffer_length       - Length of Buffer
828
 *
829
 * RETURN:      Status
830
 *
831
 * DESCRIPTION: Store the Buffer contents into the given field
832
 *
833
 ******************************************************************************/
834
 
835
acpi_status
836
acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
837
			  void *buffer, u32 buffer_length)
838
{
839
	void *new_buffer;
840
	acpi_status status;
841
	u64 mask;
842
	u64 width_mask;
843
	u64 merged_datum;
844
	u64 raw_datum = 0;
845
	u32 field_offset = 0;
846
	u32 buffer_offset = 0;
847
	u32 buffer_tail_bits;
848
	u32 datum_count;
849
	u32 field_datum_count;
850
	u32 access_bit_width;
851
	u32 required_length;
852
	u32 i;
853
 
854
	ACPI_FUNCTION_TRACE(ex_insert_into_field);
855
 
856
	/* Validate input buffer */
857
 
858
	new_buffer = NULL;
859
	required_length =
860
	    ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length);
861
	/*
862
	 * We must have a buffer that is at least as long as the field
863
	 * we are writing to. This is because individual fields are
864
	 * indivisible and partial writes are not supported -- as per
865
	 * the ACPI specification.
866
	 */
867
	if (buffer_length < required_length) {
868
 
869
		/* We need to create a new buffer */
870
 
871
		new_buffer = ACPI_ALLOCATE_ZEROED(required_length);
872
		if (!new_buffer) {
873
			return_ACPI_STATUS(AE_NO_MEMORY);
874
		}
875
 
876
		/*
877
		 * Copy the original data to the new buffer, starting
878
		 * at Byte zero. All unused (upper) bytes of the
879
		 * buffer will be 0.
880
		 */
881
		memcpy((char *)new_buffer, (char *)buffer, buffer_length);
882
		buffer = new_buffer;
883
		buffer_length = required_length;
884
	}
885
 
886
/* TBD: Move to common setup code */
887
 
888
	/* Algo is limited to sizeof(u64), so cut the access_byte_width */
889
	if (obj_desc->common_field.access_byte_width > sizeof(u64)) {
890
		obj_desc->common_field.access_byte_width = sizeof(u64);
891
	}
892
 
893
	access_bit_width = ACPI_MUL_8(obj_desc->common_field.access_byte_width);
894
 
895
	/*
896
	 * Create the bitmasks used for bit insertion.
897
	 * Note: This if/else is used to bypass compiler differences with the
898
	 * shift operator
899
	 */
900
	if (access_bit_width == ACPI_INTEGER_BIT_SIZE) {
901
		width_mask = ACPI_UINT64_MAX;
902
	} else {
903
		width_mask = ACPI_MASK_BITS_ABOVE(access_bit_width);
904
	}
905
 
906
	mask = width_mask &
907
	    ACPI_MASK_BITS_BELOW(obj_desc->common_field.start_field_bit_offset);
908
 
909
	/* Compute the number of datums (access width data items) */
910
 
911
	datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length,
912
				       access_bit_width);
913
 
914
	field_datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length +
915
					     obj_desc->common_field.
916
					     start_field_bit_offset,
917
					     access_bit_width);
918
 
919
	/* Get initial Datum from the input buffer */
920
 
921
	memcpy(&raw_datum, buffer,
922
	       ACPI_MIN(obj_desc->common_field.access_byte_width,
923
			buffer_length - buffer_offset));
924
 
925
	merged_datum =
926
	    raw_datum << obj_desc->common_field.start_field_bit_offset;
927
 
928
	/* Write the entire field */
929
 
930
	for (i = 1; i < field_datum_count; i++) {
931
 
932
		/* Write merged datum to the target field */
933
 
934
		merged_datum &= mask;
935
		status = acpi_ex_write_with_update_rule(obj_desc, mask,
936
							merged_datum,
937
							field_offset);
938
		if (ACPI_FAILURE(status)) {
939
			goto exit;
940
		}
941
 
942
		field_offset += obj_desc->common_field.access_byte_width;
943
 
944
		/*
945
		 * Start new output datum by merging with previous input datum
946
		 * if necessary.
947
		 *
948
		 * Note: Before the shift, check if the shift value will be larger than
949
		 * the integer size. If so, there is no need to perform the operation.
950
		 * This avoids the differences in behavior between different compilers
951
		 * concerning shift values larger than the target data width.
952
		 */
953
		if ((access_bit_width -
954
		     obj_desc->common_field.start_field_bit_offset) <
955
		    ACPI_INTEGER_BIT_SIZE) {
956
			merged_datum =
957
			    raw_datum >> (access_bit_width -
958
					  obj_desc->common_field.
959
					  start_field_bit_offset);
960
		} else {
961
			merged_datum = 0;
962
		}
963
 
964
		mask = width_mask;
965
 
966
		if (i == datum_count) {
967
			break;
968
		}
969
 
970
		/* Get the next input datum from the buffer */
971
 
972
		buffer_offset += obj_desc->common_field.access_byte_width;
973
		memcpy(&raw_datum, ((char *)buffer) + buffer_offset,
974
		       ACPI_MIN(obj_desc->common_field.access_byte_width,
975
				buffer_length - buffer_offset));
976
 
977
		merged_datum |=
978
		    raw_datum << obj_desc->common_field.start_field_bit_offset;
979
	}
980
 
981
	/* Mask off any extra bits in the last datum */
982
 
983
	buffer_tail_bits = (obj_desc->common_field.bit_length +
984
			    obj_desc->common_field.start_field_bit_offset) %
985
	    access_bit_width;
986
	if (buffer_tail_bits) {
987
		mask &= ACPI_MASK_BITS_ABOVE(buffer_tail_bits);
988
	}
989
 
990
	/* Write the last datum to the field */
991
 
992
	merged_datum &= mask;
993
	status = acpi_ex_write_with_update_rule(obj_desc,
994
						mask, merged_datum,
995
						field_offset);
996
 
997
exit:
998
	/* Free temporary buffer if we used one */
999
 
1000
	if (new_buffer) {
1001
		ACPI_FREE(new_buffer);
1002
	}
1003
	return_ACPI_STATUS(status);
1004
}