@@ -417,15 +417,12 @@ impl AmlValue {
417
417
}
418
418
}
419
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 ,
420
+ fn index_field_access < F : FnMut ( u64 , usize , usize , usize ) -> Result < ( ) , AmlError > > (
424
421
index_flags : & FieldFlags ,
425
422
offset : u64 ,
426
423
length : u64 ,
427
- context : & mut AmlContext ,
428
- ) -> Result < usize , AmlError > {
424
+ mut access : F ,
425
+ ) -> Result < ( ) , AmlError > {
429
426
let index_align = match index_flags. access_type ( ) ? {
430
427
FieldAccessType :: Any => 8 ,
431
428
FieldAccessType :: Byte => 8 ,
@@ -435,31 +432,37 @@ impl AmlValue {
435
432
FieldAccessType :: Buffer => 8 ,
436
433
} ;
437
434
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
- }
435
+ let mut length = length as usize ;
436
+ let mut index = ( offset / 8 ) & !( ( index_align >> 3 ) - 1 ) ;
437
+
438
+ // Bit offset in the target Data field
439
+ let mut bit_offset = ( offset - index * 8 ) as usize ;
440
+ // Bit offset in the source value
441
+ let mut pos = 0 ;
442
+
443
+ while length != 0 {
444
+ // Bit offset within a single value
445
+ let value_pos = bit_offset % index_align as usize ;
446
+ // Number of bits until the end of the value
447
+ let value_limit = index_align as usize - value_pos;
448
+ // Number of bits to access
449
+ let len = cmp:: min ( length, value_limit) ;
450
+
451
+ access ( index, pos, value_pos, len) ?;
452
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 ) ? ;
453
+ // Advance the bit position
454
+ bit_offset += len ;
455
+ pos += len ;
456
+ length -= len ;
457
457
458
- Ok ( bit_offset)
458
+ // Move to the next index
459
+ index += index_align >> 3 ;
460
+ }
461
+
462
+ Ok ( ( ) )
459
463
}
460
464
461
- /// Reads from an IndexField, returning either an `Integer` or a `Buffer` depending on the
462
- /// field size
465
+ /// Reads from an IndexField, returning either an `Integer`
463
466
pub fn read_index_field ( & self , context : & mut AmlContext ) -> Result < AmlValue , AmlError > {
464
467
let AmlValue :: IndexField { index, data, flags, offset, length } = self else {
465
468
return Err ( AmlError :: IncompatibleValueConversion {
@@ -471,14 +474,22 @@ impl AmlValue {
471
474
let mut index_field = context. namespace . get_mut ( * index) ?. clone ( ) ;
472
475
let data_field = context. namespace . get_mut ( * data) ?. clone ( ) ;
473
476
474
- // Write the Index part of the field
475
- let bit_offset = index_field. write_index ( flags, * offset, * length, context) ?;
476
-
477
477
// TODO buffer field accesses
478
+ let mut value = 0u64 ;
479
+
480
+ Self :: index_field_access ( flags, * offset, * length, |index, value_offset, field_offset, length| {
481
+ // Store the bit range index to the Index field
482
+ index_field. write_field ( AmlValue :: Integer ( index) , context) ?;
483
+
484
+ // Read the bit range from the Data field
485
+ let data = data_field. read_field ( context) ?. as_integer ( context) ?;
486
+ let bits = data. get_bits ( field_offset..field_offset + length) ;
478
487
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 ) ) ;
488
+ // Copy the bit range to the value
489
+ value. set_bits ( value_offset..value_offset + length, bits) ;
490
+
491
+ Ok ( ( ) )
492
+ } ) ?;
482
493
483
494
Ok ( AmlValue :: Integer ( value) )
484
495
}
@@ -494,22 +505,24 @@ impl AmlValue {
494
505
let mut index_field = context. namespace . get_mut ( * index) ?. clone ( ) ;
495
506
let mut data_field = context. namespace . get_mut ( * data) ?. clone ( ) ;
496
507
497
- // Write the Index part of the field
498
- let bit_offset = index_field. write_index ( flags, * offset, * length, context) ?;
508
+ let value = value. as_integer ( context) ?;
499
509
500
- // TODO handle field update rule properly
501
- // TODO buffer field accesses
510
+ Self :: index_field_access ( flags , * offset , * length , |index , value_offset , field_offset , length| {
511
+ // TODO handle the UpdateRule flag
502
512
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) ?;
513
+ // Store the bit range index to the Index field
514
+ index_field . write_field ( AmlValue :: Integer ( index ) , context) ?;
505
515
506
- // Modify the bits
507
- field_value . set_bits ( bit_offset.. ( bit_offset + * length as usize ) , value. as_integer ( context ) ? ) ;
516
+ // Extract the bits going to this specific part of the field
517
+ let bits = value. get_bits ( value_offset..value_offset + length ) ;
508
518
509
- // Write the Data field back
510
- data_field. write_field ( AmlValue :: Integer ( field_value) , context) ?;
519
+ // Read/modify/store the data field
520
+ let mut data = data_field. read_field ( context) ?. as_integer ( context) ?;
521
+ data. set_bits ( field_offset..field_offset + length, bits) ;
522
+ data_field. write_field ( AmlValue :: Integer ( data) , context) ?;
511
523
512
- Ok ( ( ) )
524
+ Ok ( ( ) )
525
+ } )
513
526
}
514
527
515
528
/// Reads from a field of an opregion, returning either a `AmlValue::Integer` or an `AmlValue::Buffer`,
0 commit comments