use super::{ opcodes, stream::AmlStream, value::{AmlValue, FieldFlags, RegionSpace}, AmlError, }; use crate::{Acpi, AcpiHandler}; use alloc::string::String; use bit_field::BitField; use core::str; /// This is used internally by the parser to keep track of what we know about a field before we can /// add it to the namespace. struct FieldInfo { pub name: String, pub length: u64, } /// This is used internally by the parser. Often, we're only interested in offset of the end of the /// current explicit-length structure, so we know when to stop parsing it. However, various /// constants (e.g. the size of fields) are also encoded as PkgLengths, and so sometimes we want to /// access the raw data as well. struct PkgLength { pub raw_length: u32, pub end_offset: u32, } pub(crate) struct AmlParser<'s, 'a, 'h, H> where H: AcpiHandler + 'h, { acpi: &'a mut Acpi, handler: &'h mut H, scope: String, stream: AmlStream<'s>, } /// This macro takes a parser and one or more parsing functions and tries to parse the next part of /// the stream with each one. If a parsing function fails, it rolls back the stream and tries the /// next one. If none of the functions can parse the next part of the stream, we error on the /// unexpected byte. macro_rules! try_parse { ($parser: expr, $($function: path),+) => {{ $(if let Some(value) = $parser.try_parse($function)? { Ok(value) } else)+ { Err(AmlError::UnexpectedByte($parser.stream.peek()?)) } }} } impl<'s, 'a, 'h, H> AmlParser<'s, 'a, 'h, H> where H: AcpiHandler, { pub(crate) fn parse( acpi: &'a mut Acpi, handler: &'h mut H, scope: &str, stream: AmlStream<'s>, ) -> Result<(), AmlError> { let mut parser = AmlParser { acpi, handler, scope: String::from(scope), stream }; let end_offset = parser.stream.len() as u32; parser.parse_term_list(end_offset) } /// Consume the next byte in the stream and check if it fulfils the given predicate. If it /// does, returns `Ok(the consumed char)`. If it doesn't, returns /// `Err(AmlError::UnexpectedByte(the consumed char)`. If there's an error consuming the char, /// it will forward the error on from that. fn consume_byte(&mut self, predicate: F) -> Result where F: Fn(u8) -> bool, { let byte = self.stream.next()?; match predicate(byte) { true => Ok(byte), false => Err(AmlError::UnexpectedByte(byte)), } } fn consume_opcode(&mut self, opcode: u8) -> Result<(), AmlError> { self.consume_byte(matches_byte(opcode))?; Ok(()) } fn consume_ext_opcode(&mut self, ext_opcode: u8) -> Result<(), AmlError> { self.consume_byte(matches_byte(opcodes::EXT_OPCODE_PREFIX))?; self.consume_byte(matches_byte(ext_opcode))?; Ok(()) } /// Try to parse the next part of the stream with the given parsing function. This returns any /// `AmlError` as an `Err`, except `AmlError::UnexpectedByte`, to which it will return /// `Ok(None)`. A successful parse gives `Ok(Some(...))`. On failure, this also reverts any /// changes made to the stream, so it's as if the parsing function never run. fn try_parse(&mut self, parsing_function: F) -> Result, AmlError> where F: Fn(&mut Self) -> Result, { let stream = self.stream.clone(); match parsing_function(self) { Ok(result) => Ok(Some(result)), Err(AmlError::UnexpectedByte(_)) => { self.stream = stream; Ok(None) } Err(error) => Err(error), } } fn parse_term_list(&mut self, end_offset: u32) -> Result<(), AmlError> { /* * TermList := Nothing | * * Because TermLists don't have PkgLengths, we pass the offset to stop at from whatever * explicit-length object we were parsing before. */ while self.stream.offset() <= end_offset { self.parse_term_object()?; } Ok(()) } fn parse_term_object(&mut self) -> Result<(), AmlError> { /* * TermObj := NameSpaceModifierObj | NamedObj | Type1Opcode | Type2Opcode * NameSpaceModifierObj := DefAlias | DefName | DefScope * NamedObj := DefBankField | DefCreateBitField | DefCreateByteField | * DefCreateDWordField | DefCreateField | DefCreateQWordField | * DefCreateWordField | DefDataRegion | DefExternal | DefOpRegion | * DefPowerRes | DefProcessor | DefThermalZone */ try_parse!( self, AmlParser::parse_def_scope, AmlParser::parse_def_op_region, AmlParser::parse_def_field //, // AmlParser::parse_type1_opcode TODO: reenable when we can parse them ) } fn parse_def_scope(&mut self) -> Result<(), AmlError> { /* * DefScope := 0x10 PkgLength NameString TermList */ self.consume_opcode(opcodes::SCOPE_OP)?; trace!("Parsing scope op"); let scope_end_offset = self.parse_pkg_length()?.end_offset; let name_string = self.parse_name_string()?; let containing_scope = self.scope.clone(); self.scope = name_string; let _term_list = self.parse_term_list(scope_end_offset)?; self.scope = containing_scope; Ok(()) } fn parse_def_op_region(&mut self) -> Result<(), AmlError> { /* * DefOpRegion := ExtOpPrefix 0x80 NameString RegionSpace RegionOffset RegionLen * RegionSpace := ByteData (where 0x00 = SystemMemory * 0x01 = SystemIO * 0x02 = PciConfig * 0x03 = EmbeddedControl * 0x04 = SMBus * 0x05 = SystemCMOS * 0x06 = PciBarTarget * 0x07 = IPMI * 0x08 = GeneralPurposeIO * 0x09 = GenericSerialBus * 0x80-0xff = OEM Defined) * ByteData := 0x00 - 0xff * RegionOffset := TermArg => Integer * RegionLen := TermArg => Integer */ self.consume_ext_opcode(opcodes::EXT_OP_REGION_OP)?; info!("Parsing op region"); let name = self.parse_name_string()?; info!("name: {}", name); let region_space = match self.stream.next()? { 0x00 => RegionSpace::SystemMemory, 0x01 => RegionSpace::SystemIo, 0x02 => RegionSpace::PciConfig, 0x03 => RegionSpace::EmbeddedControl, 0x04 => RegionSpace::SMBus, 0x05 => RegionSpace::SystemCmos, 0x06 => RegionSpace::PciBarTarget, 0x07 => RegionSpace::IPMI, 0x08 => RegionSpace::GeneralPurposeIo, 0x09 => RegionSpace::GenericSerialBus, space @ 0x80..0xff => RegionSpace::OemDefined(space), byte => return Err(AmlError::UnexpectedByte(byte)), }; info!("region space: {:?}", region_space); let offset = self.parse_term_arg()?.as_integer()?; info!("region offset: {}", offset); let length = self.parse_term_arg()?.as_integer()?; info!("region len: {}", length); // Insert it into the namespace let namespace_path = self.resolve_path(&name)?; self.acpi.namespace.insert( // self.resolve_path(name)?, TODO: I thought this would work with nll? namespace_path, AmlValue::OpRegion { region: region_space, offset, length }, ); Ok(()) } fn parse_def_field(&mut self) -> Result<(), AmlError> { /* * DefField = ExtOpPrefix 0x81 PkgLength NameString FieldFlags FieldList * FieldList := Nothing | * FieldElement := NamedField | ReservedField | AccessField | ExtendedAccessField | * ConnectField * ReservedField := 0x00 PkgLength * AccessField := 0x01 AccessType AccessAttrib * AccessType := ByteData * AccessAttrib := ByteData * ConnectField := <0x02 NameString> | <0x02 BufferData> */ self.consume_ext_opcode(opcodes::EXT_FIELD_OP)?; trace!("Parsing DefField"); let end_offset = self.parse_pkg_length()?.end_offset; trace!("end offset: {}", end_offset); let name = self.parse_name_string()?; trace!("name: {}", name); let flags = FieldFlags::new(self.stream.next()?); trace!("Field flags: {:?}", flags); while self.stream.offset() < end_offset { // TODO: parse other field types let info = try_parse!(self, AmlParser::parse_named_field)?; // TODO: add field name to this (info.name)? let namespace_path = self.resolve_path(&name)?; self.acpi.namespace.insert( namespace_path, AmlValue::Field { flags, offset: 0, // TODO: calculate offset length: info.length, }, ); } Ok(()) } fn parse_named_field(&mut self) -> Result { /* * NamedField := NameSeg PkgLength * * This encodes the size of the field using a PkgLength - it doesn't mark the length of * an explicit-length structure! */ let name = String::from(name_seg_to_string(&self.parse_name_seg()?)?); let length = self.parse_pkg_length()?.raw_length as u64; info!("Adding named field called {:?} with size {}", name, length); Ok(FieldInfo { name, length }) } fn parse_def_buffer(&mut self) -> Result { unimplemented!(); // TODO } fn parse_term_arg(&mut self) -> Result { /* * TermArg := Type2Opcode | DataObject | ArgObj | LocalObj * DataObject := ComputationalData | DefPackage | DefVarPackage */ if let Some(result) = self.try_parse(AmlParser::parse_computational_data)? { Ok(result) } else { Err(AmlError::UnexpectedByte(self.stream.next()?)) } } fn parse_computational_data(&mut self) -> Result { /* * ComputationalData := ByteConst | WordConst | DWordConst | QWordConst | String | * ConstObj | RevisionOp | DefBuffer * ByteConst := 0x0a ByteData * WordConst := 0x0b WordData * DWordConst := 0x0c DWordData * QWordConst := 0x0e QWordData * String := 0x0d AsciiCharList NullChar * ConstObj := ZeroOp(0x00) | OneOp(0x01) | OnesOp(0xff) * RevisionOp := ExtOpPrefix(0x5B) 0x30 */ match self.stream.peek()? { opcodes::BYTE_CONST => { self.consume_opcode(opcodes::BYTE_CONST)?; Ok(AmlValue::Integer(self.stream.next()? as u64)) } opcodes::WORD_CONST => { self.consume_opcode(opcodes::WORD_CONST)?; Ok(AmlValue::Integer(self.stream.next_u16()? as u64)) } opcodes::DWORD_CONST => { self.consume_opcode(opcodes::DWORD_CONST)?; Ok(AmlValue::Integer(self.stream.next_u16()? as u64)) } opcodes::QWORD_CONST => { self.consume_opcode(opcodes::QWORD_CONST)?; Ok(AmlValue::Integer(self.stream.next_u16()? as u64)) } opcodes::STRING_PREFIX => { self.consume_opcode(opcodes::STRING_PREFIX)?; unimplemented!(); // TODO } opcodes::ZERO_OP => { self.consume_opcode(opcodes::ZERO_OP)?; Ok(AmlValue::Integer(0)) } opcodes::ONE_OP => { self.consume_opcode(opcodes::ONE_OP)?; Ok(AmlValue::Integer(1)) } opcodes::ONES_OP => { self.consume_opcode(opcodes::ONES_OP)?; Ok(AmlValue::Integer(u64::max_value())) } opcodes::EXT_OPCODE_PREFIX if self.stream.lookahead(1)? == opcodes::EXT_REVISION_OP => { unimplemented!(); // TODO } _ => self.parse_def_buffer(), } } fn parse_type1_opcode(&mut self) -> Result<(), AmlError> { /* * Type1Opcode := DefBreak | DefBreakPoint | DefContinue | DefFatal | DefIfElse | DefLoad * | DefNoop | DefNotify | DefRelease | DefReset | DefReturn | * DefSignal | DefSleep | DefStall | DefUnload | DefWhile */ unimplemented!(); // TODO } /// Parse a PkgLength. Returns the offset into the stream to stop parsing whatever object the /// PkgLength describes at. // TODO: think hard about whether we actually need to minus the length now because we use // `next()`? Isn't this already handled? fn parse_pkg_length(&mut self) -> Result { /* * PkgLength := PkgLeadByte | * | * | * */ let lead_byte = self.stream.next()?; let byte_data_count = lead_byte.get_bits(6..8); if byte_data_count == 0 { let length = u32::from(lead_byte.get_bits(0..6)); let end_offset = self.stream.offset() + length - 1; // Minus 1 to remove the PkgLength byte trace!( "Parsed 1-byte PkgLength with length {}, so ends at {}(current offset={}", length, end_offset, self.stream.offset() ); return Ok(PkgLength { raw_length: length, end_offset }); } let mut length = u32::from(lead_byte.get_bits(0..4)); for i in 0..byte_data_count { length += u32::from(self.stream.next()?) << (4 + i * 8); } // Minus `byte_data_count + 1` to not include the PkgLength in the remaining bytes let end_offset = self.stream.offset() + length - byte_data_count as u32 - 1; trace!( "Parsed PkgLength with length {}, so ends at {}(current offset={})", length, end_offset, self.stream.offset() ); Ok(PkgLength { raw_length: length, end_offset }) } fn parse_name_string(&mut self) -> Result { /* * NameString := | * PrefixPath := Nothing | <'^' PrefixPath> */ match self.stream.peek()? { b'\\' => { /* * NameString := RootChar NamePath */ self.stream.next()?; Ok(String::from("\\") + &self.parse_name_path()?) } b'^' => { unimplemented!(); } _ => self.parse_name_path(), } } fn parse_name_path(&mut self) -> Result { /* * NamePath := NameSeg | DualNamePath | MultiNamePath | NullPath * DualNamePath := DualNamePrefix NameSeg NameSeg * MultiNamePath := MultiNamePrefix SegCount{ByteData} NameSeg(..SegCount) */ match self.stream.peek()? { opcodes::NULL_NAME => { self.stream.next()?; Ok(String::from("")) } opcodes::DUAL_NAME_PREFIX => { self.stream.next()?; let first = self.parse_name_seg()?; let second = self.parse_name_seg()?; Ok(String::from(str::from_utf8(&first).unwrap()) + str::from_utf8(&second).unwrap()) } opcodes::MULTI_NAME_PREFIX => { // TODO unimplemented!(); } _ => Ok(String::from(str::from_utf8(&self.parse_name_seg()?).unwrap())), } } fn parse_name_seg(&mut self) -> Result<[u8; 4], AmlError> { /* * NameSeg := */ Ok([ self.consume_byte(is_lead_name_char)?, self.consume_byte(is_name_char)?, self.consume_byte(is_name_char)?, self.consume_byte(is_name_char)?, ]) } /// Resolve a given path and the current scope to an absolute path in the namespace. fn resolve_path(&mut self, mut path: &str) -> Result { /* * TODO: how should we handle '.' as they appear in paths? */ let original_path = path.clone(); // If the scope to resolve is from the root of the namespace, or the current scope is // nothing, just return the given scope if self.scope == "" || path.starts_with("\\") { return Ok(String::from(path)); } // "^"s at the start of a path specify to go up one level from the current scope, to its // parent object let mut namespace_object = self.scope.clone(); while path.starts_with("^") { path = &path[1..]; if namespace_object.pop() == None { return Err(AmlError::InvalidPath(String::from(original_path))); } } Ok(namespace_object + &path) } } fn matches_byte(byte: u8) -> impl Fn(u8) -> bool { move |x| x == byte } fn is_lead_name_char(byte: u8) -> bool { (byte >= b'A' && byte <= b'Z') || byte == b'_' } fn is_digit_char(byte: u8) -> bool { byte >= b'0' && byte <= b'9' } fn is_name_char(byte: u8) -> bool { is_lead_name_char(byte) || is_digit_char(byte) } fn name_seg_to_string<'a>(seg: &'a [u8; 4]) -> Result<&'a str, AmlError> { match str::from_utf8(seg) { Ok(seg_str) => Ok(seg_str), Err(_) => Err(AmlError::InvalidNameSeg(*seg)), } }