Skip to content

Commit 8cd84f8

Browse files
committed
Implement Index and Bank fields
1 parent 4deb78d commit 8cd84f8

File tree

1 file changed

+96
-22
lines changed

1 file changed

+96
-22
lines changed

src/aml/mod.rs

Lines changed: 96 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1374,6 +1374,33 @@ where
13741374
let (_, data) = namespace.search(&data_name, &context.current_scope)?;
13751375
(index, data)
13761376
};
1377+
1378+
if let Object::FieldUnit(ref data_fu) = *data {
1379+
if data_fu.flags.access_type_bytes()? < FieldFlags(field_flags).access_type_bytes()? {
1380+
// On ACPICA this causes reads/writes to be truncated to the width of
1381+
// the data register.
1382+
//
1383+
// The issue comes from this part of the spec:
1384+
// "The value written to the IndexName register is defined to be a byte
1385+
// offset that is aligned on an AccessType boundary."
1386+
//
1387+
// Consider the case where the index field is WordAcc but the data
1388+
// register is ByteAcc. Only even numbers could be written to the index
1389+
// register - multiples of width of word (2 bytes). But to access the
1390+
// high byte of the word for the field, we'd need to write an odd number
1391+
// to the index register. Which is not compatible with the spec.
1392+
//
1393+
// The ASL writer shouldn't have allowed this. And it seems that most
1394+
// uses of IndexField are ByteAcc all around. So whatever strange
1395+
// behaviour we allow is probably OK.
1396+
//
1397+
// But warn the user, just in case.
1398+
warn!("Data field access width is smaller than normal field width at {:?}", start_pc);
1399+
}
1400+
} else {
1401+
warn!("Wrong data field type in IndexField: {:?}", data);
1402+
};
1403+
13771404
let kind = FieldUnitKind::Index { index, data };
13781405
self.parse_field_list(&mut context, kind, start_pc, pkg_length, field_flags)?;
13791406
}
@@ -2374,17 +2401,19 @@ where
23742401
Output::Integer(value) => value,
23752402
};
23762403

2377-
let read_region = match field.kind {
2378-
FieldUnitKind::Normal { ref region } => region,
2379-
// FieldUnitKind::Bank { ref region, ref bank, bank_value } => {
2380-
FieldUnitKind::Bank { .. } => {
2381-
// TODO: put the bank_value in the bank
2382-
todo!();
2404+
let (read_region, index_field_idx) = match field.kind {
2405+
FieldUnitKind::Normal { ref region } => (region, 0),
2406+
FieldUnitKind::Bank { ref region, ref bank, bank_value } => {
2407+
let Object::FieldUnit(ref bank) = **bank else { panic!() };
2408+
assert!(matches!(bank.kind, FieldUnitKind::Normal { .. }));
2409+
self.do_field_write(bank, Object::Integer(bank_value).wrap())?;
2410+
(region, 0)
23832411
}
2384-
// FieldUnitKind::Index { ref index, ref data } => {
2385-
FieldUnitKind::Index { .. } => {
2386-
// TODO: configure the correct index
2387-
todo!();
2412+
FieldUnitKind::Index { index: _, ref data } => {
2413+
let Object::FieldUnit(ref data) = **data else { panic!() };
2414+
let FieldUnitKind::Normal { region } = &data.kind else { panic!() };
2415+
let reg_idx = field.bit_index / 8;
2416+
(region, reg_idx)
23882417
}
23892418
};
23902419
let Object::OpRegion(ref read_region) = **read_region else { panic!() };
@@ -2404,7 +2433,27 @@ where
24042433
/ access_width_bits;
24052434
let mut read_so_far = 0;
24062435
for i in 0..native_accesses_needed {
2407-
let aligned_offset = object::align_down(field.bit_index + i * access_width_bits, access_width_bits);
2436+
// Advance the read pointer. For Index fields, this also means updating the Index
2437+
// register.
2438+
let aligned_offset = match field.kind {
2439+
FieldUnitKind::Normal { .. } | FieldUnitKind::Bank { .. } => {
2440+
object::align_down(field.bit_index + i * access_width_bits, access_width_bits)
2441+
}
2442+
FieldUnitKind::Index { ref index, ref data } => {
2443+
// Update index register
2444+
let Object::FieldUnit(ref index) = **index else { panic!() };
2445+
let Object::FieldUnit(ref data) = **data else { panic!() };
2446+
self.do_field_write(
2447+
index,
2448+
Object::Integer((index_field_idx + i * (access_width_bits / 8)) as u64).wrap(),
2449+
)?;
2450+
2451+
// The offset is always that of the data register, as we always read from the
2452+
// base of the data register.
2453+
data.bit_index
2454+
}
2455+
};
2456+
24082457
let raw = self.do_native_region_read(read_region, aligned_offset / 8, access_width_bits / 8)?;
24092458
let src_index = if i == 0 { field.bit_index % access_width_bits } else { 0 };
24102459
let remaining_length = field.bit_length - read_so_far;
@@ -2434,17 +2483,23 @@ where
24342483
};
24352484
let access_width_bits = field.flags.access_type_bytes()? * 8;
24362485

2437-
let write_region = match field.kind {
2438-
FieldUnitKind::Normal { ref region } => region,
2439-
// FieldUnitKind::Bank { ref region, ref bank, bank_value } => {
2440-
FieldUnitKind::Bank { .. } => {
2441-
// TODO: put the bank_value in the bank
2442-
todo!();
2486+
// In this tuple:
2487+
// - write_region is the region that the data will be written to.
2488+
// - index_field_idx is the initial index to write into the Index register of an index
2489+
// field. For all other field types it is unused and set to zero.
2490+
let (write_region, index_field_idx) = match field.kind {
2491+
FieldUnitKind::Normal { ref region } => (region, 0),
2492+
FieldUnitKind::Bank { ref region, ref bank, bank_value } => {
2493+
let Object::FieldUnit(ref bank) = **bank else { panic!() };
2494+
assert!(matches!(bank.kind, FieldUnitKind::Normal { .. }));
2495+
self.do_field_write(bank, Object::Integer(bank_value).wrap())?;
2496+
(region, 0)
24432497
}
2444-
// FieldUnitKind::Index { ref index, ref data } => {
2445-
FieldUnitKind::Index { .. } => {
2446-
// TODO: configure the correct index
2447-
todo!();
2498+
FieldUnitKind::Index { index: _, ref data } => {
2499+
let Object::FieldUnit(ref data) = **data else { panic!() };
2500+
let FieldUnitKind::Normal { region: data_region } = &data.kind else { panic!() };
2501+
let reg_idx = field.bit_index / 8;
2502+
(data_region, reg_idx)
24482503
}
24492504
};
24502505
let Object::OpRegion(ref write_region) = **write_region else { panic!() };
@@ -2459,7 +2514,26 @@ where
24592514
let mut written_so_far = 0;
24602515

24612516
for i in 0..native_accesses_needed {
2462-
let aligned_offset = object::align_down(field.bit_index + i * access_width_bits, access_width_bits);
2517+
// Advance the write pointer... For normal and bank fields this is straightforward. For
2518+
// Index fields, this involves updating the index register.
2519+
let aligned_offset = match field.kind {
2520+
FieldUnitKind::Normal { .. } | FieldUnitKind::Bank { .. } => {
2521+
object::align_down(field.bit_index + i * access_width_bits, access_width_bits)
2522+
}
2523+
FieldUnitKind::Index { ref index, ref data } => {
2524+
// Update index register
2525+
let Object::FieldUnit(ref index) = **index else { panic!() };
2526+
let Object::FieldUnit(ref data) = **data else { panic!() };
2527+
self.do_field_write(
2528+
index,
2529+
Object::Integer((index_field_idx + i * (access_width_bits / 8)) as u64).wrap(),
2530+
)?;
2531+
2532+
// The offset is always that of the data register, as we always read from the
2533+
// base of the data register.
2534+
data.bit_index
2535+
}
2536+
};
24632537
let dst_index = if i == 0 { field.bit_index % access_width_bits } else { 0 };
24642538

24652539
/*

0 commit comments

Comments
 (0)