@@ -193,6 +193,13 @@ pub enum AmlValue {
193
193
offset : u64 ,
194
194
length : u64 ,
195
195
} ,
196
+ IndexField {
197
+ index : AmlHandle ,
198
+ data : AmlHandle ,
199
+ flags : FieldFlags ,
200
+ offset : u64 ,
201
+ length : u64 ,
202
+ } ,
196
203
Device ,
197
204
Method {
198
205
flags : MethodFlags ,
@@ -250,7 +257,7 @@ impl AmlValue {
250
257
AmlValue :: Integer ( _) => AmlType :: Integer ,
251
258
AmlValue :: String ( _) => AmlType :: String ,
252
259
AmlValue :: OpRegion { .. } => AmlType :: OpRegion ,
253
- AmlValue :: Field { .. } => AmlType :: FieldUnit ,
260
+ AmlValue :: Field { .. } | AmlValue :: IndexField { .. } => AmlType :: FieldUnit ,
254
261
AmlValue :: Device => AmlType :: Device ,
255
262
AmlValue :: Method { .. } => AmlType :: Method ,
256
263
AmlValue :: Buffer ( _) => AmlType :: Buffer ,
@@ -297,6 +304,8 @@ impl AmlValue {
297
304
* `as_integer` on the result.
298
305
*/
299
306
AmlValue :: Field { .. } => self . read_field ( context) ?. as_integer ( context) ,
307
+ // TODO: IndexField cannot be accessed through an immutable &AmlContext
308
+ AmlValue :: IndexField { .. } => todo ! ( ) ,
300
309
AmlValue :: BufferField { .. } => self . read_buffer_field ( context) ?. as_integer ( context) ,
301
310
302
311
_ => Err ( AmlError :: IncompatibleValueConversion { current : self . type_of ( ) , target : AmlType :: Integer } ) ,
@@ -308,6 +317,8 @@ impl AmlValue {
308
317
AmlValue :: Buffer ( ref bytes) => Ok ( bytes. clone ( ) ) ,
309
318
// TODO: implement conversion of String and Integer to Buffer
310
319
AmlValue :: Field { .. } => self . read_field ( context) ?. as_buffer ( context) ,
320
+ // TODO: IndexField cannot be accessed through an immutable &AmlContext
321
+ AmlValue :: IndexField { .. } => todo ! ( ) ,
311
322
AmlValue :: BufferField { .. } => self . read_buffer_field ( context) ?. as_buffer ( context) ,
312
323
_ => Err ( AmlError :: IncompatibleValueConversion { current : self . type_of ( ) , target : AmlType :: Buffer } ) ,
313
324
}
@@ -318,6 +329,8 @@ impl AmlValue {
318
329
AmlValue :: String ( ref string) => Ok ( string. clone ( ) ) ,
319
330
// TODO: implement conversion of Buffer to String
320
331
AmlValue :: Field { .. } => self . read_field ( context) ?. as_string ( context) ,
332
+ // TODO: IndexField cannot be accessed through an immutable &AmlContext
333
+ AmlValue :: IndexField { .. } => todo ! ( ) ,
321
334
_ => Err ( AmlError :: IncompatibleValueConversion { current : self . type_of ( ) , target : AmlType :: String } ) ,
322
335
}
323
336
}
@@ -404,6 +417,101 @@ impl AmlValue {
404
417
}
405
418
}
406
419
420
+ /// Stores an IndexField's index (as specified by its offset) and returns the bit offset within
421
+ /// the Data part of the field
422
+ fn write_index (
423
+ & mut self ,
424
+ index_flags : & FieldFlags ,
425
+ offset : u64 ,
426
+ length : u64 ,
427
+ context : & mut AmlContext ,
428
+ ) -> Result < usize , AmlError > {
429
+ let index_align = match index_flags. access_type ( ) ? {
430
+ FieldAccessType :: Any => 8 ,
431
+ FieldAccessType :: Byte => 8 ,
432
+ FieldAccessType :: Word => 16 ,
433
+ FieldAccessType :: DWord => 32 ,
434
+ FieldAccessType :: QWord => 64 ,
435
+ FieldAccessType :: Buffer => 8 ,
436
+ } ;
437
+
438
+ // Value to write to the Index part of the field
439
+ let length = length as usize ;
440
+ let index_value = ( offset / 8 ) & !( ( index_align >> 3 ) - 1 ) ;
441
+ let bit_offset = ( offset - index_value * 8 ) as usize ;
442
+
443
+ // TODO handle cases when access_type/offset/length combinations lead to crossing of index
444
+ // boundary
445
+ if ( bit_offset + length - 1 ) / index_align as usize != 0 {
446
+ todo ! (
447
+ "IndexField access crosses the index boundary (range: {:#x?}, access type: {} bits)" ,
448
+ bit_offset..( bit_offset + length) ,
449
+ index_align
450
+ ) ;
451
+ }
452
+
453
+ // Write the desired index
454
+ // NOTE not sure if the spec says the index field can only be an integer one, but I can't
455
+ // think of any reason for it to be anything else
456
+ self . write_field ( AmlValue :: Integer ( index_value) , context) ?;
457
+
458
+ Ok ( bit_offset)
459
+ }
460
+
461
+ /// Reads from an IndexField, returning either an `Integer` or a `Buffer` depending on the
462
+ /// field size
463
+ pub fn read_index_field ( & self , context : & mut AmlContext ) -> Result < AmlValue , AmlError > {
464
+ let AmlValue :: IndexField { index, data, flags, offset, length } = self else {
465
+ return Err ( AmlError :: IncompatibleValueConversion {
466
+ current : self . type_of ( ) ,
467
+ target : AmlType :: FieldUnit ,
468
+ } ) ;
469
+ } ;
470
+
471
+ let mut index_field = context. namespace . get_mut ( * index) ?. clone ( ) ;
472
+ let data_field = context. namespace . get_mut ( * data) ?. clone ( ) ;
473
+
474
+ // Write the Index part of the field
475
+ let bit_offset = index_field. write_index ( flags, * offset, * length, context) ?;
476
+
477
+ // TODO buffer field accesses
478
+
479
+ // Read the value of the Data field
480
+ let field_value = data_field. read_field ( context) ?. as_integer ( context) ?;
481
+ let value = field_value. get_bits ( bit_offset..( bit_offset + * length as usize ) ) ;
482
+
483
+ Ok ( AmlValue :: Integer ( value) )
484
+ }
485
+
486
+ pub fn write_index_field ( & self , value : AmlValue , context : & mut AmlContext ) -> Result < ( ) , AmlError > {
487
+ let AmlValue :: IndexField { index, data, flags, offset, length } = self else {
488
+ return Err ( AmlError :: IncompatibleValueConversion {
489
+ current : self . type_of ( ) ,
490
+ target : AmlType :: FieldUnit ,
491
+ } ) ;
492
+ } ;
493
+
494
+ let mut index_field = context. namespace . get_mut ( * index) ?. clone ( ) ;
495
+ let mut data_field = context. namespace . get_mut ( * data) ?. clone ( ) ;
496
+
497
+ // Write the Index part of the field
498
+ let bit_offset = index_field. write_index ( flags, * offset, * length, context) ?;
499
+
500
+ // TODO handle field update rule properly
501
+ // TODO buffer field accesses
502
+
503
+ // Read the old value of the Data field (to preserve bits we're not interested in)
504
+ let mut field_value = data_field. read_field ( context) ?. as_integer ( context) ?;
505
+
506
+ // Modify the bits
507
+ field_value. set_bits ( bit_offset..( bit_offset + * length as usize ) , value. as_integer ( context) ?) ;
508
+
509
+ // Write the Data field back
510
+ data_field. write_field ( AmlValue :: Integer ( field_value) , context) ?;
511
+
512
+ Ok ( ( ) )
513
+ }
514
+
407
515
/// Reads from a field of an opregion, returning either a `AmlValue::Integer` or an `AmlValue::Buffer`,
408
516
/// depending on the size of the field.
409
517
pub fn read_field ( & self , context : & AmlContext ) -> Result < AmlValue , AmlError > {
0 commit comments