Skip to content

Commit b178f51

Browse files
committed
Create OpRegion type to abstract away field manipulation
Lots of the field reading/writing behaviour isn't quite correct yet, but this was getting unwieldly and spread about multiple places. Creating this abstraction will hopefully help in future.
1 parent 35ac783 commit b178f51

File tree

5 files changed

+290
-291
lines changed

5 files changed

+290
-291
lines changed

aml/src/lib.rs

+1-183
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ pub(crate) mod misc;
5050
pub(crate) mod name_object;
5151
pub(crate) mod namespace;
5252
pub(crate) mod opcode;
53+
pub mod opregion;
5354
pub(crate) mod parser;
5455
pub mod pci_routing;
5556
pub(crate) mod pkg_length;
@@ -387,189 +388,6 @@ impl AmlContext {
387388
}
388389
}
389390

390-
/// Read from an operation-region, performing only standard-sized reads (supported powers-of-2 only. If a field
391-
/// is not one of these sizes, it may need to be masked, or multiple reads may need to be performed).
392-
pub(crate) fn read_region(
393-
&mut self,
394-
region_handle: AmlHandle,
395-
offset: u64,
396-
length: u64,
397-
) -> Result<u64, AmlError> {
398-
use bit_field::BitField;
399-
use core::convert::TryInto;
400-
use value::RegionSpace;
401-
402-
let (region_space, region_base, _region_length, parent_device) = {
403-
if let AmlValue::OpRegion { region, offset, length, parent_device } =
404-
self.namespace.get(region_handle)?.clone()
405-
{
406-
(region, offset, length, parent_device)
407-
} else {
408-
return Err(AmlError::FieldRegionIsNotOpRegion);
409-
}
410-
};
411-
412-
match region_space {
413-
RegionSpace::SystemMemory => {
414-
let address = (region_base + offset).try_into().map_err(|_| AmlError::FieldInvalidAddress)?;
415-
match length {
416-
8 => Ok(self.handler.read_u8(address) as u64),
417-
16 => Ok(self.handler.read_u16(address) as u64),
418-
32 => Ok(self.handler.read_u32(address) as u64),
419-
64 => Ok(self.handler.read_u64(address)),
420-
_ => Err(AmlError::FieldInvalidAccessSize),
421-
}
422-
}
423-
424-
RegionSpace::SystemIo => {
425-
let port = (region_base + offset).try_into().map_err(|_| AmlError::FieldInvalidAddress)?;
426-
match length {
427-
8 => Ok(self.handler.read_io_u8(port) as u64),
428-
16 => Ok(self.handler.read_io_u16(port) as u64),
429-
32 => Ok(self.handler.read_io_u32(port) as u64),
430-
_ => Err(AmlError::FieldInvalidAccessSize),
431-
}
432-
}
433-
434-
RegionSpace::PciConfig => {
435-
/*
436-
* First, we need to get some extra information out of objects in the parent object. Both
437-
* `_SEG` and `_BBN` seem optional, with defaults that line up with legacy PCI implementations
438-
* (e.g. systems with a single segment group and a single root, respectively).
439-
*/
440-
let parent_device = parent_device.as_ref().unwrap();
441-
let seg = match self.invoke_method(
442-
&AmlName::from_str("_SEG").unwrap().resolve(parent_device).unwrap(),
443-
Args::EMPTY,
444-
) {
445-
Ok(seg) => seg.as_integer(self)?.try_into().map_err(|_| AmlError::FieldInvalidAddress)?,
446-
Err(AmlError::ValueDoesNotExist(_)) => 0,
447-
Err(err) => return Err(err),
448-
};
449-
let bbn = match self.invoke_method(
450-
&AmlName::from_str("_BBN").unwrap().resolve(parent_device).unwrap(),
451-
Args::EMPTY,
452-
) {
453-
Ok(bbn) => bbn.as_integer(self)?.try_into().map_err(|_| AmlError::FieldInvalidAddress)?,
454-
Err(AmlError::ValueDoesNotExist(_)) => 0,
455-
Err(err) => return Err(err),
456-
};
457-
let adr = {
458-
let adr = self.invoke_method(
459-
&AmlName::from_str("_ADR").unwrap().resolve(parent_device).unwrap(),
460-
Args::EMPTY,
461-
)?;
462-
adr.as_integer(self)?
463-
};
464-
465-
let device = adr.get_bits(16..24) as u8;
466-
let function = adr.get_bits(0..8) as u8;
467-
let offset = (region_base + offset).try_into().map_err(|_| AmlError::FieldInvalidAddress)?;
468-
469-
match length {
470-
8 => Ok(self.handler.read_pci_u8(seg, bbn, device, function, offset) as u64),
471-
16 => Ok(self.handler.read_pci_u16(seg, bbn, device, function, offset) as u64),
472-
32 => Ok(self.handler.read_pci_u32(seg, bbn, device, function, offset) as u64),
473-
_ => Err(AmlError::FieldInvalidAccessSize),
474-
}
475-
}
476-
477-
// TODO
478-
_ => unimplemented!(),
479-
}
480-
}
481-
482-
pub(crate) fn write_region(
483-
&mut self,
484-
region_handle: AmlHandle,
485-
offset: u64,
486-
length: u64,
487-
value: u64,
488-
) -> Result<(), AmlError> {
489-
use bit_field::BitField;
490-
use core::convert::TryInto;
491-
use value::RegionSpace;
492-
493-
let (region_space, region_base, _region_length, parent_device) = {
494-
if let AmlValue::OpRegion { region, offset, length, parent_device } =
495-
self.namespace.get(region_handle)?.clone()
496-
{
497-
(region, offset, length, parent_device)
498-
} else {
499-
return Err(AmlError::FieldRegionIsNotOpRegion);
500-
}
501-
};
502-
503-
match region_space {
504-
RegionSpace::SystemMemory => {
505-
let address = (region_base + offset).try_into().map_err(|_| AmlError::FieldInvalidAddress)?;
506-
match length {
507-
8 => Ok(self.handler.write_u8(address, value as u8)),
508-
16 => Ok(self.handler.write_u16(address, value as u16)),
509-
32 => Ok(self.handler.write_u32(address, value as u32)),
510-
64 => Ok(self.handler.write_u64(address, value)),
511-
_ => Err(AmlError::FieldInvalidAccessSize),
512-
}
513-
}
514-
515-
RegionSpace::SystemIo => {
516-
let port = (region_base + offset).try_into().map_err(|_| AmlError::FieldInvalidAddress)?;
517-
match length {
518-
8 => Ok(self.handler.write_io_u8(port, value as u8)),
519-
16 => Ok(self.handler.write_io_u16(port, value as u16)),
520-
32 => Ok(self.handler.write_io_u32(port, value as u32)),
521-
_ => Err(AmlError::FieldInvalidAccessSize),
522-
}
523-
}
524-
525-
RegionSpace::PciConfig => {
526-
/*
527-
* First, we need to get some extra information out of objects in the parent object. Both
528-
* `_SEG` and `_BBN` seem optional, with defaults that line up with legacy PCI implementations
529-
* (e.g. systems with a single segment group and a single root, respectively).
530-
*/
531-
let parent_device = parent_device.as_ref().unwrap();
532-
let seg = match self.invoke_method(
533-
&AmlName::from_str("_SEG").unwrap().resolve(parent_device).unwrap(),
534-
Args::EMPTY,
535-
) {
536-
Ok(seg) => seg.as_integer(self)?.try_into().map_err(|_| AmlError::FieldInvalidAddress)?,
537-
Err(AmlError::ValueDoesNotExist(_)) => 0,
538-
Err(err) => return Err(err),
539-
};
540-
let bbn = match self.invoke_method(
541-
&AmlName::from_str("_BBN").unwrap().resolve(parent_device).unwrap(),
542-
Args::EMPTY,
543-
) {
544-
Ok(bbn) => bbn.as_integer(self)?.try_into().map_err(|_| AmlError::FieldInvalidAddress)?,
545-
Err(AmlError::ValueDoesNotExist(_)) => 0,
546-
Err(err) => return Err(err),
547-
};
548-
let adr = {
549-
let adr = self.invoke_method(
550-
&AmlName::from_str("_ADR").unwrap().resolve(parent_device).unwrap(),
551-
Args::EMPTY,
552-
)?;
553-
adr.as_integer(self)?
554-
};
555-
556-
let device = adr.get_bits(16..24) as u8;
557-
let function = adr.get_bits(0..8) as u8;
558-
let offset = (region_base + offset).try_into().map_err(|_| AmlError::FieldInvalidAddress)?;
559-
560-
match length {
561-
8 => Ok(self.handler.write_pci_u8(seg, bbn, device, function, offset, value as u8)),
562-
16 => Ok(self.handler.write_pci_u16(seg, bbn, device, function, offset, value as u16)),
563-
32 => Ok(self.handler.write_pci_u32(seg, bbn, device, function, offset, value as u32)),
564-
_ => Err(AmlError::FieldInvalidAccessSize),
565-
}
566-
}
567-
568-
// TODO
569-
_ => unimplemented!(),
570-
}
571-
}
572-
573391
fn add_predefined_objects(&mut self) {
574392
/*
575393
* These are the scopes predefined by the spec. Some tables will try to access them without defining them

0 commit comments

Comments
 (0)